Skip to content

Safe c.h

C에 초능력을 부여하기 - 사용자 정의 헤더 파일 (safe_c.h)

About

  • safe_c.h는 C 언어에 C++과 Rust의 안전성과 편의 기능을 추가하는 600줄짜리 사용자 정의 헤더 파일로, 메모리 누수 없는 스레드 안전 grep(cgrep) 구현에 사용됨
  • RAII, 스마트 포인터, 자동 정리(cleanup) 속성을 통해 수동 free() 호출 없이 자원 관리 자동화
  • 벡터, 뷰, Result 타입, 계약 매크로 등으로 버퍼 오버플로, 오류 처리, 전제 조건 검증을 안전하게 수행
  • 뮤텍스 자동 해제, 스레드 스폰 매크로, 분기 예측 최적화 등으로 동시성과 성능을 유지하면서 안전성 확보
  • 결과적으로 동일한 성능(-O2 수준)으로 누수·세그폴트 없는 C 코드 작성 가능성을 입증

safe_c.h 개요

  • safe_c.h는 C++과 Rust의 기능을 C 코드에 이식하는 헤더 파일
    • C23의 cleanup 속성을 지원하지 않는 컴파일러(GCC 11, Clang 18 등)에서도 동일한 RAII(자동 정리) 동작 제공
    • CLEANUP(func) 매크로로 함수 종료 시 자원 자동 해제
    • LIKELY()와 UNLIKELY() 매크로로 핫패스 분기 예측 최적화

메모리 관리: UniquePtr과 SharedPtr

  • UniquePtr은 단일 소유 스마트 포인터로, 스코프 종료 시 자동으로 free() 호출
    • AUTO_UNIQUE_PTR() 매크로로 선언 시, 오류 발생이나 조기 반환에도 메모리 자동 해제
  • SharedPtr은 자동 참조 카운팅 구조로, 마지막 참조가 해제될 때 자원 자동 파괴
    • shared_ptr_init()과 shared_ptr_copy()로 참조 증가·감소 자동 처리
    • 스레드 간 안전한 공유 구조체 관리에 사용

버퍼 오버플로 방지: Vector와 View

  • DEFINE_VECTOR_TYPE() 매크로로 타입 안전한 자동 확장 벡터 생성
    • 재할당, 용량 관리, 정리(cleanup)를 자동 처리
    • AUTO_TYPED_VECTOR()로 선언 시 스코프 종료 시 자동 해제
  • StringView와 Span은 비소유 참조 구조체로, 별도 malloc 없이 문자열·배열 슬라이스 처리
    • DEFINE_SPAN_TYPE()으로 타입별 Span 정의
    • 경계 검사 포함으로 안전한 배열 접근 보장

오류 처리: Result 타입과 RAII

  • Result 구조체는 Rust의 Result와 유사한 성공/실패 구분형 반환 타입
    • DEFINE_RESULT_TYPE()으로 타입별 결과 구조 생성
    • RESULT_IS_OK()와 RESULT_UNWRAP_ERROR()로 명확한 오류 처리
  • CLEANUP 속성과 결합해 함수 종료 시 자원 자동 해제
    • AUTO_MEMORY() 매크로로 malloc된 메모리 자동 정리

계약과 안전 문자열

  • requires() / ensures() 매크로로 함수의 전·후 조건 명시
    • 실패 시 명확한 오류 메시지 출력
  • safe_strcpy() 는 버퍼 크기 검사 포함 복사 함수로, 오버플로 방지
    • 실패 시 false 반환으로 안전한 오류 처리

동시성: 자동 잠금 해제와 스레드 매크로

  • CLEANUP 기반 mutex 자동 해제 함수로 데드락 방지
    • 스코프 종료 시 pthread_mutex_unlock() 자동 호출
  • SPAWN_THREAD()와 JOIN_THREAD() 매크로로 스레드 생성·조인 단순화
    • cgrep의 파일 처리 스레드 풀 구현에 사용

성능 최적화

  • LIKELY() / UNLIKELY() 매크로로 핫패스 분기 예측 제공
    • PGO 수준의 최적화 효과를 -O2 빌드에서도 확보
  • 안전 기능이 추가되어도 성능 저하 없음

결론

  • safe_c.h를 사용한 cgrep은 2,300줄의 C 코드로, 50회 이상의 수동 free() 호출을 제거
  • 동일한 어셈블리와 실행 속도를 유지하면서 메모리 누수와 세그폴트 없는 안전한 C 코드 구현
  • C의 단순함과 자유로움을 유지하면서 현대적 안전성을 결합한 사례
  • 작성자는 이후 글에서 cgrep이 ripgrep보다 2배 이상 빠르고 메모리 사용량은 20배 적은 이유를 다룰 예정
  • safe_c.h는 새 프로젝트에 적합, 매크로 기반이라 디버깅 난이도 상승 가능성 언급
  • 다양한 정적 분석기(GCC analyzer, ASAN, UBSAN, Clang-tidy 등)로 정확성과 안전성 검증 수행

See also

Favorite site