Debugging FFI in libraptor

I am trying to debug an FFI wrapper that I have made. It seems to be
mostly working, in the sense that it is capable of doing work and
produces results.

However, the test set crashes rather stocastically, about one times in
ten. I’ve tried valgrind which reports a leak in this code:

let base_uri = CString::new(base_uri).unwrap();

unsafe {
    let world = raptor_new_world();

    let base_uri = raptor_new_uri(world, base_uri.as_ptr() as *const u8);

    let double_boxed_handler: Box<Box<&ParserHandler>> = Box::new(Box::new(handler));
    let handler_ptr = Box::into_raw(double_boxed_handler);

}

at the raptor_new_uri line. As far as I can see, I do not need to do
do anything to explicitly free base_uri here, since it should be
dropped when the method ends.

I’m struggling a little here to work out how to debug the problem
further, especially given the results are predictable. Thoughts
welcome.

The whole project is here:

memory leak generally not cause crash. So this is problem of course,
may be becaues of you never free handler_ptr, but should not cause crash.

What about core dump, can you generate it and open with rust-gdb ?

I did the following hacky way of repeatingly calling gdb until the test crashes:

while true; do
    gdb -ex='set confirm on' -ex=run -ex=quit --args target/debug/deps/raptor_rs-faf2f4df0c64c179
done

and got the following backtrace:

#0  0x00007ffff7d4ad7f in raise () from /usr/lib/libc.so.6
#1  0x00007ffff7d35672 in abort () from /usr/lib/libc.so.6
#2  0x00007ffff7d8d878 in __libc_message () from /usr/lib/libc.so.6
#3  0x00007ffff7d9418a in malloc_printerr () from /usr/lib/libc.so.6
#4  0x00007ffff7d95b27 in _int_free () from /usr/lib/libc.so.6
#5  0x00007ffff56aba9a in xmlCleanupCharEncodingHandlers () from /usr/lib/libxml2.so.2
#6  0x00007ffff56ca989 in xmlCleanupParser () from /usr/lib/libxml2.so.2
#7  0x00007ffff7f3b5f4 in raptor_free_world () from /usr/lib/libraptor2.so.0
#8  0x0000555555563ef0 in <raptor_rs::push::Parser as core::ops::drop::Drop>::drop (self=0x7fffefffe6f0) at src/push.rs:105
#9  0x000055555556e81e in core::ptr::real_drop_in_place () at /rustc/6afcb5628523b0baae5704ad34ac1aba8ba10de6/src/libcore/ptr.rs:195
#10 0x000055555556527c in raptor_rs::push::tests::test_parse_with_lang () at src/push.rs:176
#11 0x000055555556ba0a in raptor_rs::push::tests::test_parse_with_lang::{{closure}} () at src/push.rs:170
#12 0x000055555556e0ee in core::ops::function::FnOnce::call_once () at /rustc/6afcb5628523b0baae5704ad34ac1aba8ba10de6/src/libcore/ops/function.rs:231
#13 0x000055555557b73f in call_once<(),FnBox<()>> () at /rustc/6afcb5628523b0baae5704ad34ac1aba8ba10de6/src/liballoc/boxed.rs:704

searching the suspicious xmlCleanupCharEncodingHandlers brings me to this:

Looks to me like freeing a parser in raptor calls xmlCleanupParser which is deadly in multithreaded environments.

2 Likes

Ah, yes, @ExpHP, that is fiendish and clever.

It does indeed look like you are correct; I’ve tried running the tests single threaded in a loop for an hour or so, and not one crash. Also explains the stochasticity of the process.

Thank you, I really had no idea how to proceed on that one.