C++ and Rust Interop: FFI, Memory Safety at the Boundary [#44-2]

C++ and Rust Interop: FFI, Memory Safety at the Boundary [#44-2]

이 글의 핵심

Why FFI is still unsafe: explicit contracts for pointers, lifetimes, and threading. Use extern C wrappers, document who frees, and automate bindings.

Introduction: “Do we rewrite everything in Rust?”

Rust is strong for memory safety and concurrency, but real systems often keep C++ and add Rust modules (or vice versa) via C ABI (FFI). Templates, exceptions, and C++ classes are not stable across compilers—expose C-style functions and plain structs only.

Topics: why interop exists, C ABI design, bindgen / cxx, common link and ABI errors, ownership at boundaries, incremental adoption.


Scenarios

  • Reuse a validated C++ crypto or physics lib from Rust.
  • Ship a Rust parser/core in a C++ GUI host.
  • Ownership bugs: buffer freed on one side while the other still references it.
  • No stable ABI for std::vector or exceptions across Rust↔C++—wrap with opaque pointers + length.

C ABI as the contract

  • extern "C" on C++ exports; #[no_mangle] extern "C" on Rust.
  • Plain POD layouts; fixed repr(C) in Rust.
  • Document: who allocates, who frees, thread constraints.
sequenceDiagram
    participant CPP as C++ app
    participant ABI as C wrapper
    participant RS as Rust lib
    CPP->>ABI: rust_add(3,5)
    ABI->>RS: exported C fn
    RS-->>ABI: result
    ABI-->>CPP: result

Tools

  • bindgen: Rust from C headers.
  • cxx: typed bridge between Rust and C++ with less manual unsafe (still review).

Build integration

  • CMake + Cargo coordination: consistent PIC, stdlib, sanitizers.
  • Link order and rpath issues are common—encode in CMake targets.

Memory safety discussion

Rust safety stops at unsafe and FFI. C++ side must uphold invariants Rust assumes. Treat FFI as its own mini specification with tests and fuzzing.


  • Rust vs C++ memory
  • PIMPL / ABI

Summary

FFI is powerful but unsafe by default at the seam. Minimize surface area, automate bindings, and document ownership—then migrate incrementally with tests.