{"record":{"id":"7e3eb47830f6d608","repo":"atuinsh/atuin","slug":"exceeded-maximum-allocation-size","errorCode":null,"errorMessage":"exceeded maximum allocation size","messagePattern":"exceeded maximum allocation size","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/atuin-nucleo/src/boxcar.rs","lineNumber":495,"sourceCode":"                vec: self.vec,\n            },\n            ParIterProducer {\n                start: self.start + index,\n                end: self.end,\n                vec: self.vec,\n            },\n        )\n    }\n}\n\nstruct Bucket<T> {\n    entries: AtomicPtr<Entry<T>>,\n}\n\nimpl<T> Bucket<T> {\n    fn layout(len: u32, layout: Layout) -> Layout {\n        Layout::from_size_align(layout.size() * len as usize, layout.align())\n            .expect(\"exceeded maximum allocation size\")\n    }\n\n    unsafe fn alloc(len: u32, cols: u32) -> *mut Entry<T> {\n        let layout = Entry::<T>::layout(cols);\n        let arr_layout = Self::layout(len, layout);\n        let entries = std::alloc::alloc(arr_layout);\n        if entries.is_null() {\n            std::alloc::handle_alloc_error(arr_layout)\n        }\n\n        for i in 0..len {\n            let active = entries.add(i as usize * layout.size()) as *mut AtomicBool;\n            active.write(AtomicBool::new(false))\n        }\n        entries as *mut Entry<T>\n    }\n\n    unsafe fn dealloc(entries: *mut Entry<T>, len: u32, cols: u32) {","sourceCodeStart":477,"sourceCodeEnd":513,"githubUrl":"https://github.com/atuinsh/atuin/blob/15fe1318f1df51de604262eb50734c9883d48e7b/crates/atuin-nucleo/src/boxcar.rs#L477-L513","documentation":"`Bucket::layout` builds the allocation layout for a bucket's entry array with `Layout::from_size_align(...).expect(\"exceeded maximum allocation size\")`. It fails when `entry_size * bucket_len` exceeds `isize::MAX`, the largest allocation Rust permits. Bucket lengths double per bucket up to 2^31 entries, so this is reachable only near the tail of a multi-billion-entry vector, or with an oversized element type `T`.","triggerScenarios":"Allocating the last buckets of a boxcar vector already holding ~4 billion items; a custom `T` so large that even moderate bucket lengths overflow `isize::MAX`.","commonSituations":"The same practically-unreachable territory as the u32 capacity panics: stress tests, fuzzing, or accidental re-push loops that inflate the vector to billions of rows.","solutions":["Keep the total item count far below the u32 boundary so late buckets are never allocated","Pre-check intended sizes before pushing: `size_of::<T>() * planned_len <= isize::MAX as usize`","Report upstream if hit with a plausible workload - capacity math should degrade gracefully, not abort"],"exampleFix":"// before\nvec.push(item, fill); // let bucket allocation fail late\n\n// after\nlet planned = existing + 1;\nassert!(std::mem::size_of::<T>() as u64 * planned as u64 <= isize::MAX as u64);\nvec.push(item, fill);","handlingStrategy":"validation","validationCode":"// Pre-check allocation math for your element type and scale\nlet per_entry = std::mem::size_of::<T>() as u64;\nif per_entry.saturating_mul(planned_total) > isize::MAX as u64 {\n    return Err(AllocationTooLarge);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep total item counts orders of magnitude below 2^32 so late (huge) buckets are never allocated","Pre-compute worst-case entry sizes for custom T before injecting at scale","Watch process memory growth - allocation failure here follows billions of successful pushes"],"tags":["rust","panic","allocation","isize-overflow","nucleo","memory"],"backgroundTag":"allocation-too-large","analyzedSha":"15fe1318f1df51de604262eb50734c9883d48e7b","analyzedAt":"2026-08-19T08:56:57.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}