원문 캡처 · lwn.net
원문 캡처 · lwn.net

Rust 기여자 나드리엘(Nadrieril)이 Kangrejos 2026에서 발표한 Charon은 Rust 컴파일러 내부 정보를 안정적인 형식으로 추출해 도구가 활용하도록 하는 프로젝트다. 커널 빌드 도구나 Rust 코드 분석 도구를 만드는 개발자는 컴파일러 내부 인터페이스를 직접 다루는 부담을 줄일 수 있다.

Rust는 암묵적으로 처리되는 기능이 많아 다른 도구가 코드의 동작을 파악하기 어렵다. 기존 도구는 rustc의 내부 인터페이스를 이용할 수 있지만, 이 인터페이스는 예고 없이 바뀔 수 있다. Charon은 컴파일러가 보는 정보를 일정한 형식으로 제공하고, rustc의 내부 변경에 대응하는 작업을 한곳에 모으는 것을 목표로 한다.

charon cargo로 Rust 프로젝트를 빌드하면 일반적인 빌드 결과에 더해 크레이트 전체 정보를 담은 JSON 형식의 .llbc 파일을 얻는다. 이 파일에는 정의된 타입과 트레이트, 함수가 포함된다. 사람이 읽기 쉽게 출력하면 컴파일러가 암묵적으로 처리한 기능을 주석과 문장으로 드러내며, 값이 해제되는 위치와 변수의 타입 등도 표시한다. 관련 데모는 Charon 데모 저장소에서 확인할 수 있다.

커널에서는 bindgen이 생성한 Rust 코드에 rustc가 어떤 구조체 배치를 적용했는지, 그중 어떤 부분이 컴파일러 버전이 바뀌어도 안정적으로 유지되는지 살펴보는 데 쓸 수 있다. Charon의 JSON은 구조체와 열거형, 클로저·메서드·일반 함수에 일관된 정보를 제공한다. 발표에서 소개한 예시 린터는 프로그램이 std::thread::spawn()을 호출하지 않는지 검사하며, 코드가 약 60줄이라고 나드리엘은 설명했다. 린터 예시 코드

Charon은 Rust 코드를 Python, C, Lean으로 옮기는 데도 쓰였다. Rust-to-C 변환은 안전한 Rust만 대상으로 하며, 나드리엘은 해당 범위에서 읽기 쉬운 C 코드를 생성한다고 말했다. 다만 읽기 쉬운 코드를 만드는 일과 빠른 C 코드를 만드는 일은 다르다. 그는 Rust와 C에서 성능이 좋은 코드 패턴이 일치하지 않을 수 있다고 설명했다. Microsoft는 Rust로 구현한 일부 암호화 기본 요소를 C로 변환하는 데 이 도구를 사용했다. 한편 libcrux를 C로 변환해 BoringSSL의 암호화 코드 대신 사용하려는 패치는 성능이 충분하지 않아 거부됐다고 Xong Fei Ding이 전했다.

Charon은 기본적으로 타입 검사 전의 MIR을 사용하며, --precise-drops 옵션을 요청하면 일부 최적화가 값 해제 위치를 바꿀 수 있는 타입 검사 후의 elaborated MIR을 사용할 수 있다. 최적화 단계가 Rust 코드에 미치는 영향을 보여주는 기능은 아직 없지만, 나드리엘은 추가하기 어렵지는 않을 것으로 봤다.

프로젝트는 4년 넘게 개발됐고 비동기 코드를 제외한 Rust 기능을 지원한다. 버그는 남아 있지만, 나드리엘은 그 외에는 올바른 출력을 생성한다고 설명했으며 1.0 버전이 곧 준비될 것이라고 밝혔다. Charon은 아직 모든 rustc 기반 도구를 대체하지는 않는다. 예를 들어 klint는 생성된 바이너리의 일부 속성도 검사하므로 Charon만으로 완전히 대체할 수 없다는 설명이 나왔다.

부록: 원문 예시

text
// Full name: use_threads::consume
 fn consume(_1: String)
 {
 let _0: (); // return
 let _1: String; // arg #1

 storage_live(_0)
 _0 = ()
 _0 = ()
 conditional_drop[impl_Destruct_for_String::drop_glue<'0>] _1
 ↳⚡ unwind_continue
 return
 }
text
// Full name: bindings::bindings_raw::list_head
 pub struct list_head {
 next: *mut list_head,
 prev: *mut list_head,
 }
 // layout:
 // size: 16usize (guaranteed:
 // at_least(align_to(max(size_of::<*mut list_head>(),
 // size_of::<*mut list_head>()),
 // max(align_of::<*mut list_head>(),
 // align_of::<*mut list_head>())))),
 // align: 8usize (guaranteed:
 // at_least(max(align_of::<*mut list_head>(),
 // align_of::<*mut list_head>()))),
 // discriminator: _,
 // inhabited: true,
 // variants: [
 // _: {
 // offset of next: 0,
 // offset of prev: 8,
 // inhabited: true,
 // tagger: [],
 // },
 // ],
 // repr(C),