Rust ffi problem


#1

lib.rs

#[repr(C)]
pub struct MysqlOption {
    pub host:     *const c_char,
    pub port:     *const c_short,
    pub username: *const c_char,
    pub password: *const c_char,
    pub dbname:   *const c_char,
}

#[no_mangle]
pub unsafe extern fn init_mysql_config(config: *mut MysqlOption) {
    let raw_host = CString::from_raw((*config).host as *mut c_char);

    println!("host: {}", raw_host.to_str().unwrap());
    println!("next drop");
}

test.h

struct _mysql_opt {
    char *host;
    short port;
    char *username;
    char *password;
    char *dbname;
};

typedef struct _mysql_opt mysql_opt;

void init_mysql_config(mysql_opt *opt);

test.c

#include <stdio.h>
#include <stdlib.h>

#include "rust_mysql.h"

int
main(int argc, char **argv) {
    mysql_opt opt;
    opt.host = "127.0.0.1";
    opt.port = 3306;
    opt.username = "root";
    opt.password = NULL;
    opt.dbname = "asd";

    init_mysql_config(&opt);
}

when init_mysql_config lifetime end, i got a exception!

host: 127.0.0.1
next drop
test(30436,0x7fff77a24000) malloc: *** error for object 0x10b7a2f68: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

how to fix that. thanks;


#2

You’re using CString::from_raw. From the documentation ( https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#method.from_raw ):

Retakes ownership of a CString that was transferred to C.

The only appropriate argument is a pointer obtained by calling into_raw. The length of the string will be recalculated using the pointer.

The “takes ownership” part tells you that the CString object will, when dropped, free() the passed string; but in your example code, host is a string literal ("127.0.0.1"). Since the string is not in the heap, it doesn’t make sense to use CString; instead, use CStr, which is intended for strings that are owned by the caller.

Something like this should work (untested):

let raw_host = CStr::from_ptr((*config).host);
println!(“host: {}”, raw_host.to_str().unwrap());


#3

wow! thanks.