I am writing a Rust program using libevdev through FFI (using bindgen). I was trying to write a struct to store some libevdev pointer and free the pointer automatically when the struct is drop. And I find that this cause memory leak, but calling the free function directly does not. This is weird since these two ways should be equivalent.
Here is the code:
pub struct DevicePtr {
pub value: *mut libevdev,
}
impl Drop for DevicePtr {
fn drop(&mut self) {
if !self.value.is_null() {
println!("dropping device ptr");
unsafe {
libevdev_free(self.value);
}
}
}
}
fn main() {
unsafe {
let dev = libevdev_new();
// libevdev_free(dev);
let device_ptr = DevicePtr { value: dev };
}
}
valgrind --leak-check=full reports that there are 51284 bytes leak, but all of them are still reachable. Also, the program does print dropping device ptr so libevdev_free() is indeed called.
If I replace the line let device_ptr = ... with libevdev_free(dev), then the valgrind reports no leak.
So here is a snippet of heap summary output by valgrind --leak-check=full --show-leak-kinds=all:
==889647== HEAP SUMMARY:
==889647== in use at exit: 51,284 bytes in 262 blocks
==889647== total heap usage: 331 allocs, 69 frees, 64,885 bytes allocated
==889647==
==889647== 4 bytes in 1 blocks are still reachable in loss record 1 of 241
==889647== at 0x483F7B5: malloc (vg_replace_malloc.c:381)
==889647== by 0x4988583: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.7
000.2)
==889647== by 0x4988BC9: g_private_get (in /usr/lib/x86_64-linux-gnu/libglib-
2.0.so.0.7000.2)
==889647== by 0x49540EF: g_slice_alloc (in /usr/lib/x86_64-linux-gnu/libglib-
2.0.so.0.7000.2)
==889647== by 0x492251D: g_hash_table_new_full (in /usr/lib/x86_64-linux-gnu/
libglib-2.0.so.0.7000.2)
==889647== by 0x4945DFA: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.7
000.2)
==889647== by 0x48FFE24: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.7
000.2)
==889647== by 0x401000D: call_init.part.0 (dl-init.c:74)
==889647== by 0x40100EF: call_init (dl-init.c:37)
==889647== by 0x40100EF: _dl_init (dl-init.c:121)
==889647== by 0x4001089: ??? (in /usr/lib/x86_64-linux-gnu/ld-2.33.so)
==889647==
==889647== 8 bytes in 1 blocks are still reachable in loss record 2 of 241
==889647== at 0x483F6C5: malloc (vg_replace_malloc.c:380)
==889647== by 0x493BEB7: g_realloc (in /usr/lib/x86_64-linux-gnu/libglib-2.0.
so.0.7000.2)
==889647== by 0x48B6522: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.
0.7000.2)
==889647== by 0x48BAF1C: g_type_register_static (in /usr/lib/x86_64-linux-gnu
/libgobject-2.0.so.0.7000.2)
==889647== by 0x48BFBFE: g_type_plugin_get_type (in /usr/lib/x86_64-linux-gnu
/libgobject-2.0.so.0.7000.2)
==889647== by 0x48969F1: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.
0.7000.2)
==889647== by 0x401000D: call_init.part.0 (dl-init.c:74)
==889647== by 0x40100EF: call_init (dl-init.c:37)
==889647== by 0x40100EF: _dl_init (dl-init.c:121)
==889647== by 0x4001089: ??? (in /usr/lib/x86_64-linux-gnu/ld-2.33.so)
==889647==