프로그래밍시스템 개발자

Rust에서 system FFI(외부 함수 인터페이스)가 어떻게 작동하는지 설명하십시오. C에서 함수 호출을 안전하게 수행하기 위해 어떤 요구 사항과 함정이 있습니까?

Hintsage AI 어시스턴트로 면접 통과

답변

Rust의 FFI는 외부 라이브러리(예: C/C++)에 선언된 함수를 호출하고 Rust 함수를 외부로 내보낼 수 있습니다. 이를 위해 extern 키워드를 사용합니다. 요구 사항:

  • 모든 FFI 호출은 unsafe 선언으로 감싸야 합니다;
  • ABI(응용 프로그램 바이너리 인터페이스)는 일치해야 합니다(일반적으로 "C");
  • 데이터 유형은 호환 가능해야 하며, 고정 크기 기본형(i32, u64 등)을 사용하는 것이 중요합니다;
  • 메모리 관리 — 소유권, 누수 및 이중 해제를 매우 신중하게 처리해야 합니다.

래퍼의 예:

extern "C" { fn abs(input: i32) -> i32; } fn main() { unsafe { println!("{}", abs(-5)); } }

C에서 사용하기 위해 Rust에서 함수를 내보내는 방법은 다음과 같습니다:

#[no_mangle] pub extern "C" fn sum(a: i32, b: i32) -> i32 { a + b }

함정 있는 질문

질문: Rust가 C 함수 호출을 unsafe로 감싼 경우 모든 것이 스레드 안전성과 UB 포착 측면에서 올바르게 작동한다고 보장합니까?

답변: 아니요! unsafe는 컴파일러에 대해 안전성 요구 사항(별칭, 스레드 안전성, 메모리 접근성)을 준수하겠다고 약속하는 것입니다. Rust는 C 내부 코드에 대한 검사를 수행하지 않습니다. 예를 들어, 라이브러리 코드의 경쟁 조건이나 UB는 Rust 프로그램의 런타임을 "파손"할 수 있습니다. Rust 코드가 컴파일되더라도 실제 실행 중에 비정상 종료를 초래할 수 있습니다.


이야기

재무 데이터 제공업체에서 팀은 크기 유형을 검사하지 않고 FFI를 통해 C 라이브러리를 통합했습니다. x86_64에서 longi64가 일치할 것으로 예상했지만, 다른 플랫폼에서 크기가 일치하지 않아 잘못된 메모리 읽기가 계산 오류를 초래했습니다.

이야기

개발자는 C API에 대한 래퍼를 만들면서 버퍼에 대한 포인터 전달을 잊었습니다. Rust가 메모리를 자동으로 해제했기 때문에 C 함수는 때때로 이미 해제된 메모리와 작업하여 충돌 및 크래시를 일으켰습니다.

이야기

클라이언트-서버 제품에서 Rust 모듈이 C 라이브러리와 상호작용하면서 멀티스레드 안전성을 고려하지 않았습니다. 라이브러리는 스레드 안전하지 않았고, Rust 프로그램이 서로 다른 스레드에서 동시에 접근하여 크래시 및 데이터 손상을 초래했습니다.