I have a feeling that ONE rust Box<Context> (as struct Context * in C) is automatically freed when leaving main.
I have a rust library /home/codes/libspeakdet.so from following code in lib.rs compiled with cargo build
pub struct Context { pub sim: f32 }
#[no_mangle]
pub extern "C" fn make_context() -> Box<Context> {
Box::new(Context { sim: 0.2733f32 })
}
#[no_mangle]
pub extern "C" fn drop_context(_ctx: Option<Box<Context>>) {}
And test.c compiled with cc -fsanitize=address -fno-omit-frame-pointer -o test -g test.c /home/codes/libspeakdet.so
struct Context *make_context();
void drop_context(struct Context *ctx);
int main(int argc, char *argv[])
{
struct Context *ctx;
ctx = make_context();
//drop_context(ctx);
ctx = make_context();
return 0;
}
with the drop_context line commented, running test got output
==44143==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 4 byte(s) in 1 object(s) allocated from:
...
and no leak report with the drop_context line uncommented. Having N make_context calls will have asan report N-1 objects direct leak.
I'm confused, because I think the ownership is a rust feature that frees memory.
How could a C program automatically free that ONE ctx when leaving main?
EDIT
I think use Box to receive C pointer is a example from rust document. module level document of Box. Please help me understand it if I'm wrong.
... Here, the struct Foo* type from C is translated to Box, which captures the ownership constraints. ...
the document have EXACT code as mine.
EDIT
I added these codes just before return 0 to verify the still reachable explain provided by the answers.
//ctx = NULL;
ctx = (struct Context *)malloc(7);
//free(ctx);
- setting
ctx = NULLhas no change to the asan report. - setting
ctxto malloced 7 bytes made asan report 7 bytes leak. - after
freethe malloced 7 bytes, asan report became same as without these lines.
EDIT MORE
- parallel experiment
compile the following c code to independent libleaktest.so, and link test.c to libleaktest.so instead, asan reports N leaks.
struct Context *make_context() {
struct Context *ctx = (struct Context *)malloc(9);
return ctx;
}
void drop_context(struct Context *ctx) {
free(ctx);
}
EDIT MORE
some extra experiment result
valgrind is reporting N blocks of definitely lost as expected.
When Context size is <= 460 bytes, the last leak is not reported in asan.
When Context size is >= 461 bytes, the last leak is reported in asan.
Declare ctx as ctx[1], and use ctx[0] instead of ctx in following code, the last leak is reported in asan (with 4B size Context).
CONCLUSION
Thank you for help. I'm pretty sure now, that the N-1 report behavior is asan bug on rust code. If that block is reachable with 460B size, then it cannot become unreachable with 461B size.
P.S. Fortunately, after commenting each log4rs and println line, valgrind is quiet and correct again. That was initial reason why I came to use asan instead.