Safely Wrapping Crash-Prone C Code in Rust Without Full Migration

โš“ rust    ๐Ÿ“… 2025-05-30    ๐Ÿ‘ค surdeus    ๐Ÿ‘๏ธ 4      

surdeus

:magnifying_glass_tilted_left: 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.

:white_check_mark: 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 Result types in Rust.
  • Performance: Prefer zero-cost abstractions where possible.

:prohibited: 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.

:test_tube: 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.

:puzzle_piece: 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

Read full topic

๐Ÿท๏ธ rust_feed