Rust FFI with C++: Works Perfectly on Ubuntu, But Fails with Segmentation Fault in Alpine Container When Transmitting Parameters

⚓ Rust    📅 2025-09-04    👤 surdeus    👁️ 2      

surdeus

Hi, my problem is that FFI works on ubuntu but doesn't work on alpine. I develop my algorithm on Ubuntu, and once I implement a new feature, I package it into an Alpine container(based on rust:alpine3.22). I implement the solver in C++, and the server is built using Rust. The server receives network requests and then calls the C++ solver to process them.

I used to use CLI, and my solver on Alpine worked fine. But today, I replaced the CLI with FFI. The Rust server transmits C-style strings as parameters to the C++ solve function. It works fine on Ubuntu, successfully solving the problem and printing the solution. However, when I package the program into the Alpine container, it runs successfully until it transmits the parameters to the C++ function. My program is able to print "calc begin", but then it doesn't proceed. Then it throw Segmentation fault instead of print "read problem". So I suspect the issue occurs when transmitting the parameters.

Rust

use crate::request_data::ToProblem;
use crate::response::response_v3::ResponseV3;
use crate::CliError;
use crate::request_data::request_data_v3::RequestDataV3;
use crate::response::Response;
use libc::{c_char, c_void};
use std::ffi::{CStr, CString};

unsafe extern "C" {
    fn solve(problem_string: *const c_char, config_string: *const c_char)->*mut c_void;
    fn get_c_str(result:*mut c_void)->*const c_char;
    fn free_result(result:*mut c_void);
}

pub async fn handle_request(data: RequestDataV3) -> Result<warp::reply::Json, warp::Rejection> {
    println!("start handle");
    let problem_string=serde_json::to_string(&data.to_problem()).unwrap();
    let config_string=serde_json::to_string(&data.config).unwrap();
    let problem_cstr = CString::new(problem_string).unwrap();
    let config_cstr = CString::new(config_string).unwrap();
    println!("{:?}",problem_cstr);
    println!("{:?}",config_cstr);
    let solution;
    println!("calc begin");
    unsafe {
        let result=solve(problem_cstr.as_ptr(), config_cstr.as_ptr());
        println!("calc end");
        solution = CStr::from_ptr(get_c_str(result)).to_string_lossy().into_owned();
        println!("get string");
        free_result(result);
        println!("free");
    }
    let solution_json = serde_json::from_str(&solution);
    if let Err(e) = solution_json{
        return Err(warp::reject::custom(CliError(e.to_string())));
    }
    let solution_json=solution_json.unwrap();
    let response = Response {
        solution:solution_json,
    };
    let response_v3=ResponseV3::from_response(&data, response);
    Ok(warp::reply::json(&response_v3))
}

C++

#include <solver.hpp>

extern "C"{
    struct Result{
        std::string result;
    };

    Result* solve(const char * problem_string,const char * config_string){

        std::cout<<"read problem"<<std::endl;
        SolverConfig config(json::parse(config_string));
        json problem_json=json::parse(problem_string);
        Problem problem(problem_json);

        std::cout<<"solve"<<std::endl;
        Solver solver(&problem,config);
        Solution solution=solver.solve();

        std::cout<<"return"<<std::endl;
        Result* result=new Result();
        result->result=solution.to_json().dump();
        return result;
    }

    const char* get_c_str(Result* result) {
        return result->result.c_str();
    }

    void free_result(Result* result) {
        delete result;
    }
}

2 posts - 2 participants

Read full topic

🏷️ Rust_feed