cod*_*ppy 0 c memory memory-leaks ffi rust
我试图证明 C 可以调用 Rust 库。它有效,但是当我监视程序的内存使用情况时,它不断变得越来越大。
货物.toml:
[lib]
name="test_ccallr"
crate-type=["cdylib"]
path = "src/lib.rs"
[dependencies]
libc = "0.2"
Run Code Online (Sandbox Code Playgroud)
C代码:
[lib]
name="test_ccallr"
crate-type=["cdylib"]
path = "src/lib.rs"
[dependencies]
libc = "0.2"
Run Code Online (Sandbox Code Playgroud)
我使用以下命令构建 C 代码:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
struct Payload_t{
char* data;
int len;
};
int show_str(char* raw, struct Payload_t *data);
int main()
{
while(1){
char * p_raw = "hlease print it !ello this is string from c, please print it !";
char * p_raw_ = "hhello this is another ";
char * pp = (char* )malloc(strlen(p_raw));
memcpy(pp, p_raw, strlen(p_raw));
struct Payload_t *tmp = (struct Payload_t*)malloc(sizeof (struct Payload_t));
struct Payload_t *_tmp = tmp;
tmp->data = (char*)malloc(strlen(p_raw_));
memcpy(tmp->data, p_raw_, strlen(p_raw_));
tmp->len = strlen(p_raw_);
printf("\n%d %d %d", pp, tmp, tmp->data);
show_str(pp, tmp);
printf("\n%d %d %d", pp, tmp, tmp->data);
free(pp);
free(tmp->data);
//free(_tmp);
usleep(5);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
铁锈代码:
gcc main.c -L ./ -Bstatic -l:libtest_ccallr.so -o test[lib]
Run Code Online (Sandbox Code Playgroud)
如果我取消注释//free(_tmp);,程序就会崩溃。如果我保留此行注释并运行该程序,它可以运行,但会泄漏内存。
有什么不合适的地方吗?
这是不恰当的用法Box::from_raw:
let payload_ptr: Payload_t = unsafe { *Box::from_raw(data as *mut Payload_t) };
Run Code Online (Sandbox Code Playgroud)
从文档中,强调我的(请阅读不安全函数的文档):
调用此函数后,原始指针归结果
Box. 具体来说,析构函数Box将调用 的析构函数T并释放分配的内存。为了安全起见,必须根据 所使用的内存布局来分配内存Box。
Box::new您应该仅对您要重新获得所有权的数据分配的数据使用此函数。你的情况两者都不是。Box正在释放 C 分配的内存。这很可能是导致您调用的原因free崩溃的原因,因为 Rust 用它自己的析构函数在内存上乱写乱画。
编写 Rust 函数的更好方法不会尝试获取 的所有权data:
#[no_mangle]
pub unsafe extern "C" fn show_str(raw: *const c_char, data: *const Payload_t) -> i32 {
let c_str = CStr::from_ptr(raw);
let str_from_ptr = match c_str.to_str() {
Ok(s) => s,
Err(err) => {
eprintln!("{}", err);
return 0;
}
};
let payload_ptr = &*data;
let payload = std::slice::from_raw_parts(payload_ptr.data, payload_ptr.len as usize);
let s = match std::str::from_utf8(payload) {
Ok(s) => s,
Err(err) => {
eprintln!("{}", err);
return 0;
}
};
println!("the raw string is {}", str_from_ptr);
println!("the length string is {}", s);
0
}
Run Code Online (Sandbox Code Playgroud)