Memory leak when calling FFI function in drop

Viewed 194

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==
0 Answers
Related