tursodatabase/turso · critical
munmap failed: {}
Error message
munmap failed: {} What it means
Arena dealloc unmaps the region and panics if munmap fails - in practice EINVAL from a wrong pointer/length pair (double unmap, a len differing from the allocation length, or a corrupted pointer). This is a memory-management invariant break, not an environmental condition.
Source
Thrown at core/storage/buffer_pool.rs:470
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1,
0,
);
if ptr == libc::MAP_FAILED {
panic!("mmap failed: {}", std::io::Error::last_os_error());
}
#[cfg(target_os = "linux")]
{
libc::madvise(ptr, len, libc::MADV_HUGEPAGE);
}
ptr as *mut u8
}
pub unsafe fn dealloc(ptr: *mut u8, len: usize) {
let result = munmap(ptr as *mut c_void, len);
if result != 0 {
panic!("munmap failed: {}", std::io::Error::last_os_error());
}
}
}
#[cfg(any(not(unix), miri))]
mod arena {
pub unsafe fn alloc(len: usize) -> *mut u8 {
let layout = std::alloc::Layout::from_size_align(len, std::mem::size_of::<u8>()).unwrap();
unsafe { std::alloc::alloc_zeroed(layout) }
}
pub unsafe fn dealloc(ptr: *mut u8, len: usize) {
let layout = std::alloc::Layout::from_size_align(len, std::mem::size_of::<u8>()).unwrap();
unsafe { std::alloc::dealloc(ptr, layout) };
}
}
/// Shuttle tests for concurrent buffer pool operations.
///View on GitHub (pinned to 244cde92a7)
Solutions
- Store the allocation length alongside the pointer and free with exactly that pair
- Audit the pool bookkeeping for double-frees of arena ranges
- Run under Miri or ASan to catch the invalid free closer to its cause
Example fix
// before
unsafe { arena::dealloc(ptr, len_guess); } // EINVAL if len_guess != alloc len
// after
struct ArenaBlock { ptr: *mut u8, len: usize } // pair set at alloc
unsafe { arena::dealloc(block.ptr, block.len); } Defensive patterns
Strategy: validation
Validate before calling
// keep (ptr, len) as an inseparable pair; free with exactly the alloc pair
struct ArenaBlock { ptr: *mut u8, len: usize }
fn free(block: ArenaBlock) { unsafe { arena::dealloc(block.ptr, block.len) } } Prevention
- Never recompute lengths at free time; carry them from allocation
- Run the storage crate under Miri/ASan in CI to catch invalid frees early
When it happens
Trigger: Calling arena::dealloc with a len other than the one passed to alloc; freeing the same region twice; pointer arithmetic bugs in buffer-pool bookkeeping.
Common situations: Contributor changes to the buffer pool; refactors that split or merge arena lifetimes and recompute lengths at free time.
Related errors
- mmap failed: {}
- Pool not initialized
- buffer not loaded
- OpenRead on pseudo cursor
- Rewind on non-btree/materialized-view cursor
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/e95cfbbb0a2e9dbd.
Report an issue: GitHub.