디시인사이드 갤러리

갤러리 이슈박스, 최근방문 갤러리

갤러리 본문 영역

Clair 라이브러리: 예외 처리 C 바인딩 아키텍처

나르시갤로그로 이동합니다. 2025.11.27 23:20:15
조회 73 추천 0 댓글 1

C API 래핑 패턴의 비교 분석

Ada의 예외를 C 언어의 에러 코드로 변환하기 위한 '예외 장벽(Exception Barrier)'을 구현하는 방법은 크게 세 가지가 있습니다. 각 방식의 장단점과 실제 구현 코드를 분석하여 Clair 라이브러리에 최적화된 아키텍처를 도출합니다.

1. 예외 매퍼 패턴 (Exception Mapper Pattern)

C API 함수 내부에서 비즈니스 로직을 직접 호출하고, exception 블록에서 예외를 처리하는 방식입니다. 이 패턴은 구현 방식에 따라 두 가지 형태로 나뉩니다.

  1. 인라인 핸들러 방식: 각 함수마다 when Clair.Exceptions.X => return -1;과 같이 개별 예외를 나열하는 방식.
  2. 중앙 매퍼 호출 방식: when others를 통해 모든 예외를 잡은 뒤, 중앙 유틸리티 함수(Map_Exception)로 넘기는 방식.
1.1 구현 코드 예시

[중앙 매퍼 함수 구현 (Clair.API_Utils)]

function Map_Exception (Occ : Exception_Occurrence) return Interfaces.C.int is
   Id : Exception_Id := Exception_Identity (Occ);
begin
   -- 1. Clair 논리 에러 체크 (가장 빈번한 것부터)
   if Id = Clair.Exceptions.Display_Init_Error'Identity then
      return Clair.Errors.Err_Display_Init;
      
   elsif Id = Clair.Exceptions.Library_Load_Error'Identity then
      return Clair.Errors.Err_Library_Load;

   -- 2. 시스템 에러 (Errno) 체크
   --    필요하다면 Clair.Errno 패키지의 예외들과 비교
   elsif Id = Clair.Errno.ENOMEM'Identity then
      return Clair.Errno.ENOMEM_Val; -- (상수로 정의된 값)

   -- 3. Ada 런타임 에러
   elsif Id = Constraint_Error'Identity then
      return Clair.Errors.Err_Invalid_Arg;

   else
      -- 로그를 남기거나 디버깅 정보를 출력할 수 있음
      return Clair.Errors.Err_Unknown;
   end if;
end Map_Exception;

[C API 함수 구현부]

-- C API 함수 내부
function C_Do_Work (...) return int is
begin
   -- 내부 로직 직접 호출 (Zero Overhead)
   Do_Internal(...);      -- [Call Instruction]
   return 0;              -- [Move + Ret]
exception
   -- 예외 발생 시 중앙 매퍼 호출
   when E : others =>
      return Map_Exception(E);      -- [Call Instruction]
end C_Do_Work;

[Ruby 자동 생성 템플릿 예시]

# Ruby Generator Template Concept
template = <<-ADA
   function #{c_name} (#{args}) return Interfaces.C.int 
      with Export, Convention => C, External_Name => "#{c_name}";
   is
   begin
      -- 1. 내부 로직 호출 (Zero Overhead)
      Clair.Core.#{ada_name} (#{converted_args});
      return Clair.Errors.Success;
   exception
      -- 2. 예외 발생 시 중앙 매퍼 호출 (최소 코드량)
      when E : others =>
         return Clair.API_Utils.Map_Exception (E);
   end #{c_name};
ADA
장점
  • 제로 오버헤드: 정상 실행 시 함수 포인터나 객체 생성이 없어 C 함수와 동일한 성능을 냅니다.
  • 최적화된 바이너리: 각 함수에 매퍼 호출 코드만 추가되므로 바이너리 크기가 가장 작습니다.
  • 자동화 최적: 구조가 단순하여 위와 같은 스크립트로 자동 생성하기에 가장 적합합니다.
단점
  • 보일러플레이트: 자동화를 하지 않을 경우, 함수마다 exception 블록을 작성해야 합니다.

2. 로컬 캡처 / Thunk 패턴 (Local Capture / Thunk Pattern)

Ada의 중첩 프로시저(Nested Procedure) 기능을 활용하여 로직을 감싸고(Bridge), 이를 중앙 실행기(Run_Safe)에 전달하는 방식입니다.

2.1 구현 코드 예시
with Interfaces.C;
with Clair.API_Utils;
with Clair.Core; -- 실제 로직이 있는 패키지

function C_Do_Work (X : Interfaces.C.int; Y : Interfaces.C.int) return Interfaces.C.int
   with Export, Convention => C, External_Name => "clair_do_work";
is
   -- [상태 변수] 로직 수행 결과를 저장할 변수
   Result_Val : Integer := 0; 

   ------------------------------------------------------------
   -- [Thunk] 지역 프로시저 (Bridge)
   -- 상위 함수의 인자(X, Y)와 변수(Result_Val)에 접근 가능
   ------------------------------------------------------------
   procedure Bridge is
   begin
      -- C 타입 -> Ada 타입 변환 및 실제 함수 호출
      Result_Val := Clair.Core.Do_Work (Integer(X), Integer(Y));
   end Bridge;

begin
   -- [실행] Bridge의 Access를 넘겨서 실행
   --       Run_Safe는 예외 발생 여부(에러 코드)를 반환함
   declare
      Status : constant Interfaces.C.int := Clair.API_Utils.Run_Safe (Bridge'Access);
   begin
      if Status /= Clair.Errors.Success then
         return Status;
      end if;

      -- 예외가 없다면 실제 로직의 결과 반환
      return Interfaces.C.int(Result_Val);
   end;
end C_Do_Work;
장점
  • 간결한 구현: 파라미터 구조체 없이도 외부 변수를 캡처할 수 있어 코드가 직관적입니다.
  • 정책의 중앙화: 모든 실행 흐름이 Run_Safe를 통과하므로 예외 정책 관리가 용이합니다.
단점
  • 간접 호출 비용: Thunk를 경유하므로 미세한 오버헤드가 발생합니다.
  • 보안 주의 및 컴파일러 의존성: Thunk의 Access를 C 함수 포인터로 직접 넘기면 스택에 코드를 생성하는 트램펄린(Trampoline)이 발생하여 보안(NX Bit) 위험이 있습니다. 또한, Ada 내부 호출이 안전하다는 점(트램펄린 미생성) 역시 컴파일러의 구현 방식(예: GNAT의 Fat Pointer 사용 여부)에 의존적이므로, 엄격한 보안과 이식성이 요구되는 환경에서는 주의가 필요합니다.

3. 파라미터 레코드 + 접근자 패턴 (Parameter Record Pattern)

모든 매개변수를 명시적인 레코드(record) 타입으로 정의하고, 이를 패키지 레벨의 정적 함수에 전달하는 방식입니다.

3.1 구현 코드 예시
type Params is record
   X : Integer;
   Y : Integer;
end record;
type Params_Access is access all Params;
type Param_Thunk is access function (P : Params_Access) return Interfaces.C.int;

function Handle_Exceptions_Param (F : Param_Thunk; P : Params_Access) return Interfaces.C.int is
begin
   return F.all (P);
exception
   when others =>
      Set_Last_Error (-999, Exception_Message (Ada.Exceptions.Others));
      return -999;
end Handle_Exceptions_Param;

function Do_Work_With_Params (P : Params_Access) return Interfaces.C.int is
begin
   return Do_Work_Internal (P.X, P.Y);
end Do_Work_With_Params;

function clair_do_work (x : Interfaces.C.int; y : Interfaces.C.int) return Interfaces.C.int is
   P : aliased Params := (X => Integer(x), Y => Integer(y));
begin
   return Handle_Exceptions_Param (Do_Work_With_Params'Access, P'Access);
end clair_do_work;
장점
  • 완벽한 보안성: 중첩 함수를 사용하지 않으므로 트램펄린 생성 가능성이 0%입니다.
  • 명시적 관리: 데이터와 실행 코드가 분리되어 비동기 작업 처리에 유리합니다.
단점
  • 높은 작성 비용: 함수마다 전용 레코드와 접근자 타입을 정의해야 하므로 코드량이 매우 많아집니다.

결론: Clair 라이브러리의 선택

Clair 라이브러리는 **성능(Zero Overhead)**과 안전성(Safety), 그리고 **개발 생산성(Productivity)**을 모두 만족하기 위해 '중앙 집중식 예외 매퍼(Centralized Exception Mapper)' 전략을 논리적 기반으로 채택합니다.

실제 구현에서는 이 전략을 바탕으로 반복적인 코드 작성을 피하고 타입 안전성을 확보하기 위해 'N-Arity 제네릭 래퍼(N-Arity Generic Wrapper)' 패턴을 사용하여 구현합니다. 이는 1번 패턴의 성능 이점과 2번 패턴의 코드 간결성을 동시에 달성하는 최적의 해법입니다.

Clair 라이브러리 예외(에러) C 바인딩 전략

1.1 개요

Ada로 작성된 라이브러리인 Clair를 C 언어 환경에서 사용하기 위해서는 **언어 경계(Language Boundary)**를 넘나드는 견고한 인터페이스 설계가 필수적입니다. Ada의 예외(Exception)는 C 언어가 이해할 수 없으므로, 이를 C가 처리할 수 있는 정수형 에러 코드(Error Code)로 변환하여 반환해야 합니다.

본 장에서는 성능(Performance), 안전성(Safety), 그리고 유지보수성(Maintainability)을 고려한 **'중앙 집중식 예외 매퍼(Centralized Exception Mapper)'**와 'N-Arity 제네릭 래퍼(N-Arity Generic Wrapper)' 패턴을 소개합니다.

1.2 핵심 설계 원칙

Clair 라이브러리의 C API 바인딩은 다음 세 가지 원칙을 따릅니다.

  1. 예외 장벽(Exception Barrier)의 수립: Ada의 예외가 처리되지 않은 채 C 영역(Foreign Frame)으로 전파될 경우, Ada 런타임은 프로그램을 즉시 **종료(Termination)**시킵니다. 라이브러리 함수 하나가 실패했다고 해서 전체 애플리케이션이 종료되는 것을 막기 위해, 경계에서 모든 예외를 포착해야 합니다.
  2. 제로 오버헤드(Zero Overhead): 정상 실행 경로(Happy Path)에서는 불필요한 객체 생성이나 동적 디스패치(Dynamic Dispatch)를 피하고, C 함수 호출과 동일한 성능을 보장해야 합니다.
  3. 보안 안전성(Security Safety): 스택 실행 권한(NX Bit)을 침해하는 트램펄린(Trampoline) 생성을 원천적으로 방지하기 위해, Ada 내부 규약을 따르는 정적 바인딩(Static Binding) 방식을 사용합니다.

1.3 패키지 구조와 역할

예외와 에러 코드를 명확히 분리하기 위해 다음과 같이 패키지를 구성합니다.

  • Clair.Errno: 운영체제 시스템 에러 코드와 이에 대응하는 Ada 예외를 정의합니다. (자동 생성됨)
  • Clair.Exceptions: Clair 라이브러리 내부 로직 흐름을 제어하기 위한 고수준 Ada 예외 객체입니다.
  • Clair.Errors: C API가 반환할 인터페이스용 정수형 상수(Status Code)입니다.
  • Clair.API_Utils: C API 경계에서 발생하는 예외를 에러 코드로 변환하는 중앙 실행기입니다.

1.4 구현 상세

1.4.1 중앙 실행기 (Clair.API_Utils)

이 패키지는 모든 C API 함수가 공유하는 단 하나의 실행기를 제공합니다. 개별 API 함수마다 예외 처리 로직을 중복 작성하는 대신, 이 실행기가 예외 변환을 전담합니다.

with Ada.Exceptions;
with Interfaces.C;
with Clair.Errors;
with Clair.Exceptions;
with Clair.Errno;

package body Clair.API_Utils is

   -- 모든 C API가 공유하는 예외 처리 실행기
   function Run_Protected (Action : Action_Proc) return Interfaces.C.int is
   begin
      -- 1. 실제 동작 실행 (Zero Overhead: 단순 간접 호출)
      Action.all;
      
      -- 2. 성공 시 0 반환
      return Clair.Errors.Success;

   exception
      ------------------------------------------------------------
      -- 3. 중앙 집중식 예외 매핑 (Native Handler Dispatch)
      ------------------------------------------------------------
      
      -- (A) Clair 라이브러리 논리 에러
      when Clair.Exceptions.Display_Init_Error =>
         return Clair.Errors.Err_Display_Init;

      when Clair.Exceptions.Library_Load_Error =>
         return Clair.Errors.Err_Library_Load;

      -- (B) 시스템 에러 (Errno 패키지와 연동)
      when Clair.Errno.ENOMEM =>
         return Clair.Errno.ENOMEM_Val;

      -- (C) Ada 런타임 에러
      when Constraint_Error =>
         return Clair.Errors.Err_Invalid_Arg;

      when Storage_Error =>
         return Clair.Errors.Err_System_Fatal;

      -- (D) 그 외 예측 불가능한 에러
      when others =>
         return Clair.Errors.Err_Unknown;
   end Run_Protected;

end Clair.API_Utils;

1.4.2 N-Arity 제네릭 래퍼 (Clair.Wrappers)

인자의 개수(Arity) 별로 제네릭 함수를 미리 정의합니다. 이 방식은 타입 안전성을 보장하며, 내부적으로 Thunk를 생성하여 Run_Protected에게 전달합니다. Ada 내부 호출 규약(Convention Ada)을 따르므로 트램펄린이 생성되지 않아 안전합니다.

-- [Clair.Wrappers.ads]
package Clair.Wrappers is
   -- 인자가 2개인 경우의 제네릭 템플릿
   generic
      type Arg1_Type is <>;
      type Arg2_Type is <>;
      with procedure Action (A1 : Arg1_Type; A2 : Arg2_Type);
   function Wrap_2 (A1 : Arg1_Type; A2 : Arg2_Type) return Interfaces.C.int;
end Clair.Wrappers;

-- [Clair.Wrappers.adb]
package body Clair.Wrappers is
   function Wrap_2 (A1 : Arg1_Type; A2 : Arg2_Type) return Interfaces.C.int is
      -- Thunk: 인자를 캡처하여 전달 (Ada 내부에서만 사용되므로 안전)
      procedure Bridge is
      begin
         Action (A1, A2);
      end Bridge;
   begin
      -- 예외 처리 없이 실행기에 위임
      return Clair.API_Utils.Run_Protected (Bridge'Access);
   end Wrap_2;
end Clair.Wrappers;

1.4.3 사용자 API 구현 예시 (clair_do_work)

라이브러리 개발자는 복잡한 예외 처리 로직을 매번 작성할 필요 없이, 제네릭 인스턴스화를 통해 래퍼를 생성하고 사용합니다.

with Clair.Wrappers;
with Clair.Core;

package body Clair.Work is

   -- 1. 내부 비즈니스 로직 (Ada 스타일)
   procedure Do_Internal (X, Y : Integer) is
   begin
      Clair.Core.Do_Work (X, Y);
   end Do_Internal;

   -- 2. 래퍼 생성 (타입과 함수만 지정)
   --    개발자가 명시적으로 이 래퍼를 생성함으로써 안전한 예외 처리가 적용됩니다.
   function Safe_Do_Work is new Clair.Wrappers.Wrap_2
     (Arg1_Type => Integer,
      Arg2_Type => Integer,
      Action    => Do_Internal);

   -- 3. C API Export
   function C_Do_Work (X, Y : Interfaces.C.int) return Interfaces.C.int
      with Export, Convention => C, External_Name => "clair_do_work";
   is
   begin
      -- C 타입을 Ada 타입으로 변환하여 안전한 래퍼 호출
      return Safe_Do_Work (Integer(X), Integer(Y));
   end C_Do_Work;

end Clair.Work;

1.5 결론

이 아키텍처는 다음과 같은 이점을 제공합니다.

  1. 안전성 (Correctness): 이 패턴을 적용하면 Ada 런타임에 의한 프로그램 강제 종료를 방지하고, 모든 예외를 C가 이해할 수 있는 에러 코드로 안전하게 변환할 수 있습니다.
  2. 생산성 (Productivity): Clair.Wrappers의 제네릭을 활용함으로써 반복적인 코드 작성을 최소화합니다.
  3. 성능 (Performance): 정상 실행 시에는 추가적인 비용이 없는 함수 호출 성능을 제공합니다.

추천 비추천

0

고정닉 0

0

댓글 영역

전체 댓글 0
본문 보기

하단 갤러리 리스트 영역

왼쪽 컨텐츠 영역

갤러리 리스트 영역

갤러리 리스트
번호 제목 글쓴이 작성일 조회 추천
설문 뛰어난 운동 신경으로 남자와 싸워도 이길 것 같은 여자 스타는? 운영자 25/11/24 - -
AD 따뜻한 겨울나기! 방한용품 SALE 운영자 25/11/27 - -
공지 프로그래밍 갤러리 이용 안내 [97] 운영자 20.09.28 48792 65
2905502 '19' 젖제로투 추는 BJ.gif 프갤러(59.17) 20:58 0 0
2905501 'ㅎㅂ' 윤 공주 실시간 라방중ㄱㄱ 프갤러(121.175) 20:58 1 0
2905493 모처럼 모진말들을 뱉어내고 나면 [1] 개멍청한유라갤로그로 이동합니다. 20:30 18 0
2905492 기레기 시발놈들 때문에 주가가 올라가고 내려가고 하는데 사람낚는어부갤로그로 이동합니다. 20:14 29 0
2905491 외국계 it support 테크니션이면 어떤 일임?? 프갤러(121.138) 20:06 11 0
2905490 나님 끙야하면서 트림했어양⭐+ [1] ♥멘헤라냥덩♥갤로그로 이동합니다. 19:59 20 0
2905489 나님 달밤의 끙야즁⭐+ ♥멘헤라냥덩♥갤로그로 이동합니다. 19:56 10 0
2905488 이태원 모욕죄 벌금 100이면 인생 하드모드 입갤임? 취업, 이민 종결? ㅇㅇ(118.235) 19:52 10 0
2905486 저 애미뒤진새끼는 아직도 있노 [1] ㅇㅇ(223.38) 19:52 33 0
2905482 뿡야하면 냥덩이 한번 털어줘야함❤+ [3] ♥멘헤라냥덩♥갤로그로 이동합니다. 19:29 19 0
2905478 요즘 해킹 많이 당하네 [3] 사람낚는어부갤로그로 이동합니다. 18:56 61 0
2905476 관세사 따도 초봉 3000~4000 아니냐 ㅇㅅㅇ 류류(118.235) 18:50 15 0
2905475 이태원모욕죄100만원 정식재판청구? 걍내고끝내? 인생에 별 지장 없? [2] ㅇㅇ(118.235) 18:43 17 0
2905472 35살 모욕죄 전과자+좆견인인데, 관세사따면 결혼 가능 스펙임? [1] ㅇㅇ(203.232) 18:29 32 0
2905471 우왓, 연회중에 피분수가..ㅡㅡ;; [2] 박정희대통령갤로그로 이동합니다. 18:18 36 3
2905466 동기 부여 발명도둑잡기(211.235) 16:51 13 0
2905465 모기로 프린터를 만들어 발명도둑잡기(211.235) 16:48 14 0
2905464 청소년이 밤 10시 이후에 발명도둑잡기(211.235) 16:45 13 0
2905463 ❤✨☀⭐⚡☘⛩☃나님 시작합니당☃⛩☘⚡⭐☀✨❤ ♥멘헤라냥덩♥갤로그로 이동합니다. 16:44 22 0
2905461 사람인하고 점핏하고 다른 회사임? ㅇㅇ(182.228) 16:25 18 0
2905460 경력 1년이상, 3년이상 뽑는 회사 [1] ㅇㅇ갤로그로 이동합니다. 16:13 36 0
2905456 유관순은 3.1운동할 때 인공기 흔들었냐? [2] chironpractor갤로그로 이동합니다. 15:53 37 0
2905454 중·일 갈등 ‘패싱’ 미국에···일본은 불안하다 발명도둑잡기(118.216) 15:29 18 0
2905453 ‘한미일 vs 북중러’ 구도 위험성 더 커진다 [2] 발명도둑잡기(118.216) 15:21 21 0
2905452 이젠 뭐가 ai이고 진짜인지 분간이 잘 안 간당.. [5] ♥멘헤라냥덩♥갤로그로 이동합니다. 15:20 70 0
2905451 밤에도 못 자고 일하니까 출생률이 떨어지는 것이다 [1] 발명도둑잡기(118.216) 15:13 20 0
2905450 윤석열 “전한길은 하나님이 한국에 보낸 선물” 옥중 편지 발명도둑잡기(118.216) 15:06 15 0
2905448 '아쉽다. 뽀뽀'…부하 여경 손 깍지·허리 감싼 경찰관 유죄 확정 발명도둑잡기(118.216) 15:01 10 0
2905447 美서 의미 퇴색한 '블프 세일'…"행사 진정성 사라져" 발명도둑잡기(118.216) 14:56 12 0
2905446 '케네디家' 끝없는 비극?…35살 외손녀 시한부 판정 발명도둑잡기(118.216) 14:53 16 0
2905445 5억짜리 ‘인간 세탁기’ 발명도둑잡기(118.216) 14:50 15 0
2905444 노동장관 "해 뜨면 일하고 해 지면 휴식. 야간 노동자 사망' 쿠팡 발명도둑잡기(118.216) 14:47 13 0
2905441 젤렌스키, 러시아 침공전 방어체제 이끈 '분신' 잃었다 발명도둑잡기(118.216) 14:39 17 0
2905440 회사다니면서 우울증 생겼는데.. [16] ㅇㅇ(1.244) 14:16 86 0
2905437 기분 좋은 주말이다 RyuDOG갤로그로 이동합니다. 13:47 21 0
2905436 [대한민국] 국힘 책임당원 일동 입장문 ㅇㅇ(121.172) 13:45 16 0
2905435 와 로리 슬렌더 알몸 ㅇㅅㅇ [2] 류류(121.160) 13:20 64 1
2905432 이마트가즈아 넥도리아(223.38) 12:45 15 0
2905431 나 한동훈 인간적이어서 좋아했습니다. 넥도리아(223.38) 12:41 23 0
2905430 고인모욕이 비도덕적 반인륜적인건 아는데 [1] 류류(118.235) 12:19 37 1
2905429 내년부터 4.5일제 강행이야 ㅇㅅㅇ? 류류(118.235) 12:16 19 0
2905428 내냔 상반기 ㄹㅇ 존나 바쁠거 확정임 ㅅㅂ [2] ♥멘헤라냥덩♥갤로그로 이동합니다. 12:14 58 0
2905427 ㅆㅇㅆ뒤지니까 류독이 또 나와서 나대네 ㅇㅅㅇ 류류(118.235) 12:09 28 1
2905426 이태원 피떡갈비 ㅇㅅㅇ 류류(118.235) 11:57 29 0
2905425 뭔가 있어보이는 Ada 코딩법 ㅋㅋ 나르시갤로그로 이동합니다. 11:39 28 0
2905424 책 사는거 이거 맞는건가? [2] 넥도리아(220.74) 11:38 63 0
2905420 주술회전 최신화 ♥멘헤라냥덩♥갤로그로 이동합니다. 11:04 24 0
2905419 Watsn.ai - 최첨단 AI 구라 탐지기 만들어 봤다 Watsn(47.230) 10:47 25 0
2905418 이태원 모욕죄로 벌금100 너무 분하고 억울하다.. 이딴걸로 전과라니; [3] ㅇㅇ(39.7) 10:31 52 1
갤러리 내부 검색
제목+내용게시물 정렬 옵션

오른쪽 컨텐츠 영역

실시간 베스트

1/8

디시미디어

디시이슈

1/2