Cpp2Rust: C++를 안전한 Rust로 자동 번역
(github.com/Cpp2Rust)- Cpp2Rust는 clang AST 기반의 구문 주도 번역기로, C++ 입력을 자동으로 완전히 안전한 Rust 코드로 변환함
- 번역 과정은 clang으로 C++ 파일을 파싱해 AST를 만들고, AST를 순회하며 Rust 코드를 문자열로 생성한 뒤
rustfmt로 단일.rs파일을 출력함 - 기본값은 참조 카운팅 모델이며, 디버깅과 성능 비교를 위해
--model=unsafe로 unsafe Rust 생성도 가능함 - 생성된 코드는
libcc2rs런타임 라이브러리에 의존하며, C 포인터는 null, 산술, 별칭을 모델링하는Ptr<T>로 변환됨 - 전체 프로그램 번역에는
compile_commands.json이 필요하며, CMake 프로젝트는CMAKE_EXPORT_COMPILE_COMMANDS=ON플래그로 생성할 수 있음
C++에서 안전한 Rust로 자동 변환
- Cpp2Rust는 C++를 완전히 안전한 Rust로 자동 번역하는 도구임
- clang의 AST를 기반으로 하는 구문 주도 번역기임
- 번역 알고리듬은 PLDI 2026에 게재된 논문 Cpp2Rust: Automatic Translation of C++ to Safe Rust에 설명돼 있음
번역 파이프라인
- 입력 C++ 파일을 먼저 clang으로 파싱해 AST를 생성함
- 이후 AST를 순회하며 Rust 코드를 문자열로 출력함
- 필요한 경우
libcc2rs런타임 라이브러리 호출을 삽입함- 예시는 raw pointer semantics 처리임
- 마지막으로
rustfmt를 사용해 Rust 코드를 단일.rs파일로 정리함
안전한 Rust와 unsafe Rust 모델
- 기본 동작은 참조 카운팅 모델을 사용하며, 완전히 안전한 Rust 출력을 생성함
- unsafe Rust 생성기도 제공됨
- 명령행 인자는
--model=unsafe - 용도는 디버깅과 성능 비교임
- 명령행 인자는
libcc2rs 런타임 라이브러리
- 생성된 코드는 번역 과정을 단순화하기 위해 설계된 런타임 라이브러리에 의존함
- C 포인터는
libcc2rs가 제공하는Ptr<T>타입으로 변환됨 Ptr<T>는 C 포인터 의미를 모델링함- null
- 포인터 산술
- 별칭
- Rust의 borrow checker는 검사된 런타임 연산을 통해 만족함
빌드와 실행 흐름
- Ubuntu 의존성 설치 예시는
libclang-22-dev,clang++-22,ninja-build,cmake,ruff를 포함함 - 빌드는
cmake -GNinja ..,ninja,ninja check순서로 진행함 - 단일 파일 번역 명령은 다음 형태임
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs
- unsafe Rust를 생성하려면 다음처럼 실행함
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs --model=unsafe
최소 예제와 전체 프로그램 번역
hello.cpp의printf("hello world\n")예제는 Rust의println!("hello world")를 포함한 코드로 변환됨- 변환된
hello.rs는 다음처럼 컴파일하고 실행함
rustc hello.rs -L ../libcc2rs/target/debug
./hello
- 전체 프로그램 번역에는
compile_commands.json이 필요함 - CMake에서는 다음 플래그로
compile_commands.json을 생성함
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
- 전체 프로그램 번역 명령은 다음 형태임
./build/cpp2rust/cpp2rust --dir=<dir> -o <output>.rs
<dir>는compile_commands.json이 들어 있는 디렉터리여야 함
테스트 명령
- 전체 테스트는
ninja check로 실행함 - 단위 테스트는
ninja check-unit로 실행함 libcc2rs단위 테스트는ninja check-libcc2rs로 실행함libcc2rs-macros단위 테스트는ninja check-libcc2rs-macros로 실행함- 의도적으로 변경한 뒤 예상 출력을 재생성하려면
REPLACE_EXPECTED=1 ninja check-unit을 사용함
댓글과 토론
Lobste.rs 의견들
-
올해 2월 Dan Wallach의 발표를 들었는데, DARPA의 TRACTOR(Translating All C to Rust) 프로젝트를 소개했음 [1] [2] [3]
연구 프로그램의 시험·평가는 MIT Lincoln Laboratory 팀이 수행 중이라고 함
아직 연구 단계로 알고 있지만 이 주제에 관심이 많고, 이런 도구와 아이디어가 어떻게 나올지 꽤 궁금함
메모리 관리에서 오는 많은 “사소한” 버그를 실제로 없애줄 수 있을 것 같음
[1] https://www.darpa.mil/research/programs/translating-all-c-to-rust
[2] https://github.com/DARPA-TRACTOR-Program
[3] https://ll.mit.edu/r-d/projects/… -
흥미로움. 저자들이 이걸로 변환했고 스스로도 흥미롭다고 보는 라이브러리나 앱 데모를 한두 개 볼 수 있으면 정말 좋겠음
- https://github.com/Cpp2Rust/cpp2rust-testsuite 에 관련 논문의 예제가 있고, WOFF2, brotli 등 여러 버전이 들어 있음
예를 들어 https://github.com/Cpp2Rust/cpp2rust-testsuite/… 를 보면 안전한 Rust일 수는 있지만, 관용적인 Rust라고 하기는 확실히 어려움
- https://github.com/Cpp2Rust/cpp2rust-testsuite 에 관련 논문의 예제가 있고, WOFF2, brotli 등 여러 버전이 들어 있음
-
왜 변환 단계가 필요한지 잘 모르겠음. 메모리 안전한 Rust로 변환할 만큼 충분한 정보가 있다면, C++도 정적 분석으로 안전하다고 보장할 수 있을 만큼 정보가 있는 것 아닌가?
- 변환 과정에서 새 검사를 넣는 방식이라, “원래 코드가 안전했다”기보다는 “새 코드는 메모리를 망가뜨리는 대신 크게 실패하며 종료된다”는 절충에 가까움
- README에 링크된 논문 첫머리에 이 내용이 있음
널리 배포된 소프트웨어 보안 취약점의 약 70%는 C와 C++ 같은 언어의 메모리 안전성 버그에서 나오고, 정적 분석·새니타이저·하드웨어 격리 같은 완화책에 수십 년 투자했지만 공격자는 여전히 안전하지 않은 메모리 연산을 악용한다고 함
장기적으로 유망한 해법은 기존 C++ 코드베이스를 Rust 같은 메모리 안전 언어로 옮기는 것이지만, 수작업으로 하기는 비용이 지나치게 크고 오류가 나기 쉽다고 설명함
Cpp2Rust는 C++ 프로그램을 기능적으로 동등하고 메모리 안전한 Rust 코드로 자동 변환할 수 있는 첫 시스템이라고 주장함
성능 일부를 보안과 맞바꾸면서, C++의 제한 없는 별칭 참조와 Rust의 소유권 모델 사이의 근본적 불일치를 런타임 소유권·가변성 검사 삽입으로 해결해 의미를 보존하면서 안전성을 보장한다고 함
동적 검사 오버헤드를 줄이기 위해 Rust 코드용 소스 간 최적화도 만들었고, 중복 소유권 연산을 제거해 잃은 성능 상당 부분을 회복한다고 함
그래서 동기는 단순히 안전성을 증명하는 게 아니라, Rust로 이식하고 앞으로의 개발을 Rust로 옮기기 쉽게 하려는 쪽임 - 충분한 정보가 없고, 라이스 정리에 따르면 앞으로도 없을 것임
이런 프로젝트의 아이디어는 관용적인 Rust로 더 리팩터링하기 위한 출발점을 만드는 것이고, 그렇게 되면 코드를 분석 가능하게 만들 수 있음
바라건대 변환된 코드에서 런타임 검사나 안전하지 않은 부분도 제거할 수 있게 됨
C++를 “Rust 모양”으로 리팩터링해서 똑같이 분석 가능하게 만들면 되지 않느냐고 할 수 있지만, C++는 더 많은 유연성을 허용하는 다른 의미론을 갖고 있어서 분석해야 할 경로가 지수적으로 늘거나 정적 분석이 애매한 막다른 길에 빠질 수 있음
정적 분석기에 까다로운 일을 하지 않고 경계 사례를 악용하지 않겠다고 약속해야 하며, 그러려면 더 제한된 의미론과 추가 애너테이션을 가진 C++ 방언을 만들 수 있음
Circle/Safe C++가 가능성을 보였지만 C++ WG가 그 방향을 강하게 거부했으니, 지원받지 못하는 Rust 비슷한 C++ 방언을 직접 쓰거나 그냥 Rust를 쓰는 선택만 남음
-
입력 코드 자체가 안전하지 않은 경우에는 정확히 어떻게 동작하는 걸까?
- 런타임 검사로 처리함. 그래서 위반이 발생하는 순간 메모리를 망가뜨리는 대신 안전하고 결정적으로 크래시할 수 있음