1 điểm bởi GN⁺ 3 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • Cpp2Rust là một trình dịch theo cú pháp dựa trên clang AST, tự động chuyển đổi đầu vào C++ thành mã Rust hoàn toàn an toàn
  • Quá trình dịch phân tích tệp C++ bằng clang để tạo AST, duyệt AST và sinh mã Rust dưới dạng chuỗi, rồi xuất một tệp .rs duy nhất bằng rustfmt
  • Mặc định là mô hình đếm tham chiếu, và cũng có thể sinh unsafe Rust bằng --model=unsafe để gỡ lỗi và so sánh hiệu năng
  • Mã được sinh ra phụ thuộc vào thư viện runtime libcc2rs; con trỏ C được chuyển đổi thành Ptr<T>, mô hình hóa null, phép toán số học trên con trỏ và aliasing
  • Dịch toàn bộ chương trình cần compile_commands.json; với dự án CMake có thể tạo bằng cờ CMAKE_EXPORT_COMPILE_COMMANDS=ON

Tự động chuyển đổi từ C++ sang Rust an toàn

  • Cpp2Rust là công cụ tự động dịch C++ sang Rust hoàn toàn an toàn
  • Đây là trình dịch theo cú pháp dựa trên AST của clang
  • Thuật toán dịch được mô tả trong bài báo Cpp2Rust: Automatic Translation of C++ to Safe Rust, đăng tại PLDI 2026

Pipeline dịch

  • Tệp C++ đầu vào trước tiên được phân tích bằng clang để tạo AST
  • Sau đó duyệt AST và xuất mã Rust dưới dạng chuỗi
  • Khi cần, chèn các lệnh gọi tới thư viện runtime libcc2rs
    • Ví dụ là xử lý raw pointer semantics
  • Cuối cùng dùng rustfmt để định dạng mã Rust thành một tệp .rs duy nhất

Mô hình Rust an toàn và unsafe Rust

  • Hành vi mặc định sử dụng mô hình đếm tham chiếu và tạo đầu ra Rust hoàn toàn an toàn
  • Cũng cung cấp bộ sinh unsafe Rust
    • Đối số dòng lệnh là --model=unsafe
    • Mục đích là gỡ lỗi và so sánh hiệu năng

Thư viện runtime libcc2rs

  • Mã được sinh ra phụ thuộc vào thư viện runtime được thiết kế để đơn giản hóa quá trình dịch
  • Con trỏ C được chuyển đổi thành kiểu Ptr<T> do libcc2rs cung cấp
  • Ptr<T> mô hình hóa ngữ nghĩa con trỏ C
    • null
    • phép toán số học trên con trỏ
    • aliasing
  • Borrow checker của Rust được thỏa mãn thông qua các thao tác runtime đã được kiểm tra

Luồng build và chạy

  • Ví dụ cài đặt dependency trên Ubuntu bao gồm libclang-22-dev, clang++-22, ninja-build, cmake, ruff
  • Quá trình build diễn ra theo thứ tự cmake -GNinja .., ninja, ninja check
  • Lệnh dịch một tệp có dạng sau
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs
  • Để sinh unsafe Rust, chạy như sau
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs --model=unsafe

Ví dụ tối thiểu và dịch toàn bộ chương trình

  • Ví dụ printf("hello world\n") trong hello.cpp được chuyển đổi thành mã bao gồm println!("hello world") của Rust
  • hello.rs sau khi chuyển đổi được biên dịch và chạy như sau
rustc hello.rs -L ../libcc2rs/target/debug
./hello
  • Dịch toàn bộ chương trình cần compile_commands.json
  • Trong CMake, tạo compile_commands.json bằng cờ sau
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
  • Lệnh dịch toàn bộ chương trình có dạng sau
./build/cpp2rust/cpp2rust --dir=<dir> -o <output>.rs
  • <dir> phải là thư mục chứa compile_commands.json

Lệnh kiểm thử

  • Chạy toàn bộ kiểm thử bằng ninja check
  • Chạy kiểm thử đơn vị bằng ninja check-unit
  • Chạy kiểm thử đơn vị của libcc2rs bằng ninja check-libcc2rs
  • Chạy kiểm thử đơn vị của libcc2rs-macros bằng ninja check-libcc2rs-macros
  • Nếu muốn tái tạo đầu ra kỳ vọng sau khi cố ý thay đổi, dùng REPLACE_EXPECTED=1 ninja check-unit

1 bình luận

 
Ý kiến trên Lobste.rs
  • Tôi đã nghe bài trình bày của Dan Wallach vào tháng 2 năm nay, trong đó ông giới thiệu dự án TRACTOR (Translating All C to Rust) của DARPA [1] [2] [3]
    Việc thử nghiệm và đánh giá chương trình nghiên cứu này hiện đang do nhóm tại MIT Lincoln Laboratory thực hiện
    Tôi biết nó vẫn đang ở giai đoạn nghiên cứu, nhưng tôi rất quan tâm đến chủ đề này và khá tò mò xem những công cụ cũng như ý tưởng như thế này sẽ phát triển ra sao
    Có vẻ như nó thực sự có thể loại bỏ nhiều lỗi “vặt” phát sinh từ quản lý bộ nhớ
    [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/…

  • Thú vị đấy. Sẽ rất tuyệt nếu có thể xem một hoặc hai bản demo thư viện hoặc ứng dụng mà chính tác giả đã chuyển đổi bằng công cụ này và cũng thấy đáng chú ý

  • Tôi không thực sự hiểu vì sao cần bước chuyển đổi. Nếu đã có đủ thông tin để chuyển sang Rust an toàn bộ nhớ, thì chẳng phải cũng có đủ thông tin để đảm bảo C++ là an toàn bằng phân tích tĩnh hay sao?

    • Trong quá trình chuyển đổi, họ thêm các phép kiểm tra mới, nên đây gần với một sự đánh đổi kiểu “mã mới sẽ dừng lại với lỗi nghiêm trọng thay vì làm hỏng bộ nhớ”, hơn là “mã gốc vốn đã an toàn”
    • Nội dung này có ngay ở phần đầu bài báo được liên kết trong README
      Khoảng 70% lỗ hổng bảo mật trong phần mềm được phân phối rộng rãi xuất phát từ lỗi an toàn bộ nhớ trong các ngôn ngữ như C và C++, và dù đã đầu tư hàng chục năm vào các biện pháp giảm thiểu như phân tích tĩnh, sanitizer và cô lập phần cứng, kẻ tấn công vẫn tiếp tục khai thác các thao tác bộ nhớ không an toàn
      Họ giải thích rằng về lâu dài, một giải pháp đầy hứa hẹn là chuyển các codebase C++ hiện có sang ngôn ngữ an toàn bộ nhớ như Rust, nhưng làm thủ công thì quá tốn kém và dễ phát sinh lỗi
      Cpp2Rust được giới thiệu là hệ thống đầu tiên có thể tự động chuyển chương trình C++ thành mã Rust tương đương về chức năng và an toàn bộ nhớ
      Bằng cách đánh đổi một phần hiệu năng lấy bảo mật, họ giải quyết sự không tương thích nền tảng giữa tham chiếu bí danh không bị hạn chế của C++ và mô hình sở hữu của Rust bằng cách chèn các kiểm tra quyền sở hữu và tính khả biến lúc chạy, từ đó bảo toàn ngữ nghĩa đồng thời đảm bảo an toàn
      Để giảm chi phí của các kiểm tra động, họ cũng tạo ra tối ưu hóa liên thủ tục cho mã Rust, giúp loại bỏ các thao tác sở hữu dư thừa và khôi phục được phần lớn hiệu năng đã mất
      Vì vậy, động cơ không chỉ đơn thuần là chứng minh tính an toàn, mà còn là chuyển sang Rust và giúp việc phát triển về sau bằng Rust trở nên dễ dàng hơn
    • Không có đủ thông tin, và theo định lý Rice thì sau này cũng sẽ không có
      Ý tưởng của các dự án kiểu này là tạo ra một điểm khởi đầu để tiếp tục refactor sang Rust đúng phong cách hơn, và khi đó mã sẽ trở nên có thể phân tích được
      Hy vọng là từ mã đã chuyển đổi, người ta còn có thể loại bỏ các kiểm tra lúc chạy hoặc những phần không an toàn
      Có thể bạn sẽ hỏi tại sao không refactor C++ thành “dạng giống Rust” để đạt khả năng phân tích tương tự, nhưng C++ có ngữ nghĩa khác và cho phép mức linh hoạt lớn hơn, khiến số đường đi cần phân tích tăng theo cấp số mũ hoặc dẫn phân tích tĩnh vào những ngõ cụt mơ hồ
      Bạn sẽ phải hứa không làm những thứ gây khó cho bộ phân tích tĩnh và không khai thác các trường hợp biên; mà nếu vậy thì có thể tạo ra một phương ngữ C++ với ngữ nghĩa bị hạn chế hơn và các annotation bổ sung
      Circle/Safe C++ đã cho thấy hướng này có tiềm năng, nhưng vì C++ WG đã phản đối mạnh mẽ hướng đó, nên rốt cuộc chỉ còn lựa chọn либо tự dùng một phương ngữ C++ giống Rust nhưng không được hỗ trợ, hoặc đơn giản là dùng Rust
  • Nếu chính mã đầu vào không an toàn, thì cụ thể nó sẽ hoạt động như thế nào?

    • Họ xử lý bằng kiểm tra lúc chạy. Vì vậy khi có vi phạm xảy ra, chương trình có thể crash một cách an toàn và xác định được, thay vì làm hỏng bộ nhớ