Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

12. Unsafe Rust: 통제된 위험 🔴

학습 목표:

  • 컴파일러가 검증할 수 없는 다섯 가지 Unsafe 초능력과 그 사용 시점을 이해합니다.
  • 건전한 추상화(Sound Abstraction): 안전한 API로 비안전한 내부 로직을 감싸는 법을 배웁니다.
  • C 언어와 통신하기 위한 FFI 패턴을 익힙니다.
  • 흔히 발생하는 **미정의 동작(UB)**의 함정과 아레나/슬래브 할당자 패턴을 학습합니다.

Unsafe의 다섯 가지 초능력

unsafe 키워드는 컴파일러가 안전성을 보장할 수 없는 다섯 가지 특수 작업을 허용합니다.

#![allow(unused)]
fn main() {
unsafe {
    // 1. RAW 포인터 역참조
    let value = *raw_ptr;

    // 2. Unsafe 함수 또는 메서드 호출
    let mem = std::alloc::alloc(layout);

    // 3. 가변 정적 변수(static mut) 접근 및 수정
    COUNTER += 1;

    // 4. Unsafe 트레이트 구현
    unsafe impl Send for MyType {}

    // 5. 유니온(Union) 필드 접근
    let f = u.f;
}
}

핵심 원칙: unsafe가 빌림 검사기(Borrow checker)를 끄는 것은 아닙니다. 오직 위 다섯 가지 능력만 해제하며, 나머지 모든 Rust 규칙은 여전히 적용됩니다.


건전한 추상화 (Sound Abstraction) 작성

unsafe의 진정한 목적은 위험한 로직을 내부에 숨기고, 외부 사용자에게는 절대 오용할 수 없는 안전한 인터페이스를 제공하는 것입니다.

건전한 Unsafe 코드의 3계명:

  1. 불변성(Invariant) 문서화: 모든 unsafe 블록 위에 // SAFETY: 주석을 달아 왜 이 작업이 안전한지 논리적으로 설명하세요.
  2. 캡슐화: 사용자가 안전한 API만 사용해도 내부에서 미정의 동작(UB)이 발생하지 않도록 설계하세요.
  3. 최소화: unsafe 블록은 필요한 최소한의 범위로 유지하세요.

커스텀 할당자: 아레나(Arena)와 슬래브(Slab)

대규모 시스템에서는 표준 할당자(malloc)의 오버헤드를 줄이기 위해 특화된 할당 패턴을 사용합니다.

  • 아레나(Arena): 포인터를 앞으로 밀기만 하는 매우 빠른 할당 방식입니다. 개별 해제는 불가능하며, 아레나 전체를 한꺼번에 해제하여 메모리 파편화를 방지합니다. 프레임 단위 처리나 요청 단위 작업에 최적입니다.
  • 슬래브(Slab): 고정된 크기의 슬롯들을 미리 확보해 두고 재사용합니다. 메모리 파편화가 전혀 없으며, 고정 크기 객체(예: 커넥션 풀)를 빈번하게 생성하고 삭제할 때 최고의 성능을 냅니다.

미정의 동작(UB)의 일반적인 함정

함정원인방지법
Null 역참조Null 포인터 접근ptr.is_null() 체크 시 수행
댄글링 포인터해제된 메모리 접근수명(Lifetime) 규칙 준수
데이터 경합동기화 없는 static mut 접근Atomic이나 Mutex 사용
Aliasing 위반동일 데이터에 두 개 이상의 &mut 생성Rust의 대여 규칙 엄수

📝 연습 문제: Unsafe를 활용한 안전한 래퍼 제작 ★★★ (~45분)

고정 크기 스택 할당 벡터인 FixedVec<T, N>을 구현해 보세요.

  • push, pop, as_slice 기능을 구현하되, 내부적으로는 MaybeUninit을 사용하세요.
  • 모든 공개 API는 안전해야 하며, 내부의 모든 unsafe에는 상세한 // SAFETY: 주석을 달아야 합니다.
  • Drop 구현을 통해 초기화된 요소들이 정상적으로 소멸되도록 하세요.

📌 요약

  • FFI 경계성능 병목 구간 외에는 unsafe 사용을 지양하세요.
  • 모든 비안전한 연산 뒤에는 이를 안전하게 만드는 논리적 증거가 있어야 합니다.
  • 아레나슬래브 할당자는 일반적인 힙 할당보다 수십 배 빠를 수 있습니다.
  • 복잡한 메모리 레이아웃이 필요하다면 **repr(C)**를 사용하여 C 언어와의 호환성을 확보하세요.