Safely Wrapping Crash-Prone C Code in Rust Without Full Migration
โ Rust ๐ 2025-05-30 ๐ค surdeus ๐๏ธ 12
Context
We're integrating legacy C code into a Rust application via FFI. The C codebase is extensive and cannot be modified or fully migrated to Rust at this time. Some C functions exhibit undefined behavior (e.g., division by zero, null pointer dereferences), leading to crashes that propagate into the Rust application.
Requirements
- No process forking: Avoiding the overhead of spawning separate processes for isolation.
- Memory safety: Prevent issues like dangling pointers and buffer overflows from affecting Rust code.
- Undefined behavior handling: Gracefully handle errors such as division by zero and null dereferences originating from C code.
- Thread safety: Ensure safe concurrent calls to C functions.
- Rust-style error handling: Convert C failures into
Resulttypes in Rust. - Performance: Prefer zero-cost abstractions where possible.
Constraints
- Immutable C code: Cannot modify the existing C source code.
- Partial Rust migration: The team is not ready for a full migration to Rust.
- Maintain existing FFI interface: Need to preserve the current interface between Rust and C.
Attempted Solutions
catch_unwind: Ineffective for catching undefined behavior like segmentation faults.- Process isolation: Too resource-intensive for our use case.
- Manual checks: Insufficient for covering all cases of undefined behavior.
Objective
Seeking a Rust-only solution to safely wrap and handle errors from crash-prone C code without modifying the C source or incurring significant performance penalties. The solution should uniquely leverage Rust's capabilities to provide safety guarantees that are difficult to achieve in C or C++.
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
#[link(name = "example_static", kind = "static")]
extern "C" {
fn errore(a: i32, b: i32) -> i32;
}
fn main() {
unsafe {
let result = errore(100, 0); // Potential division by zero error but I want to handle without c midfication
println!("Result: {}", result);
}
}
Challenge:
This is an open challenge to find a solution not in C or C++, and without the overhead of boilerplate code! If you're truly experienced with Rust, show it here.
I'm trying to convince my team to migrate to Rustโnot just for safety, but also because I can handle undefined behaviors from old C and C++ modules within Rust. If the same is easily achievable in C or C++, they won't be convinced to switch.
So, the answer must be unique to Rust. I'm new to Rust and currently working on a proof of concept (PoC).
6 posts - 4 participants
๐ท๏ธ rust_feed