vielite's blog

QA-11: Potential Per-Entry Memory Leak in traverse_callback

March 23, 2026
0 min read
Table of Contents
monad-qa-11-traverse-callback-memory-leak

Summary

The trie traversal callback copies key and value buffers into Rust Vecs but does not finalize the original FFI buffers through bindings::triedb_finalize.

Vulnerability details

2025-09-monad/bft/monad-triedb/src/lib.rs
pub unsafe extern "C" fn traverse_callback(
op_kind: bindings::triedb_async_traverse_callback,
context: *mut std::ffi::c_void,
key_ptr: *const u8,
key_len: usize,
value_ptr: *const u8,
value_len: usize,
) {
let traverse_context = unsafe { Box::from_raw(context as *mut TraverseContext) };
// ...
let key = unsafe { std::slice::from_raw_parts(key_ptr, key_len).to_vec() };
let value = unsafe { std::slice::from_raw_parts(value_ptr, value_len).to_vec() };
{
let mut lock = traverse_context.data.lock().expect("mutex poisoned");
lock.push(TraverseEntry { key, value });
}
let _ = Box::into_raw(traverse_context);
}

Impact

Traversals over large tries can leak one allocation per returned key and value entry, eventually causing avoidable memory growth.

Recommendation

Finalize per-entry FFI buffers after copying them into Rust-owned memory.