{"record":{"id":"33de33e156a04622","repo":"clockworklabs/SpacetimeDB","slug":"allocation-size-overflow","errorCode":null,"errorMessage":"allocation size overflow","messagePattern":"allocation size overflow","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/dst/src/sim/commitlog.rs","lineNumber":459,"sourceCode":"}\n\nimpl io::Seek for ReadOnlySegment {\n    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {\n        self.inner.seek(pos)\n    }\n}\n\nimpl SegmentLen for ReadOnlySegment {}\n\nfn next_page_multiple(size: u64) -> io::Result<u64> {\n    let page = PAGE_SIZE as u64;\n    let remainder = size % page;\n    if remainder == 0 {\n        return Ok(size);\n    }\n\n    size.checked_add(page - remainder)\n        .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, \"allocation size overflow\"))\n}\n\nfn enospc() -> io::Error {\n    io::Error::new(io::ErrorKind::StorageFull, \"no space left on device\")\n}\n\n#[cfg(test)]\nmod tests {\n    use std::io::{Read, Seek, Write};\n\n    use super::*;\n\n    fn segment() -> Segment {\n        Segment::from_shared(Arc::new(Mutex::new(u64::MAX)), Arc::new(RwLock::new(Storage::new())))\n    }\n\n    #[test]\n    fn write_overwrites_at_seek_position() {","sourceCodeStart":441,"sourceCodeEnd":477,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/dst/src/sim/commitlog.rs#L441-L477","documentation":"next_page_multiple rounds a byte size up to the next multiple of PAGE_SIZE. When the input is already page-aligned it is returned unchanged; otherwise it computes size + (PAGE_SIZE - remainder) with checked_add. Only a size within PAGE_SIZE of u64::MAX that is not page-aligned makes the addition overflow, producing ErrorKind::InvalidInput, 'allocation size overflow'. Callers pass either a write end position or pos + 1 from Segment::write.","triggerScenarios":"A requested write whose end position (pos + buf.len()) is non-page-aligned and within PAGE_SIZE of u64::MAX; a position of exactly u64::MAX - k for small k feeding the minimum-allocation path; again only realistic in adversarial tests since the shared space budget triggers StorageFull long before.","commonSituations":"Edge-case unit tests probing allocation at the top of the u64 range; production occurrence indicates a corrupted position value, not a real allocation request.","solutions":["Keep test write positions far from u64::MAX so rounding never overflows","If seen outside tests, audit how the Segment position became huge (seek corruption, fixture bug)","Bound accepted write sizes/positions at your API boundary before they reach the commitlog"],"exampleFix":"// before\nlet end = u64::MAX - 3; // non-page-aligned, near max\nnext_page_multiple(end)?; // InvalidInput: allocation size overflow\n\n// after\nconst MAX_SEG_END: u64 = u64::MAX - (u64::MAX % 4096) - 4096; // keep headroom\nassert!(end <= MAX_SEG_END, \"write end too large\");","handlingStrategy":"validation","validationCode":"const PAGE: u64 = 4096;\nfn page_multiple_fits(size: u64) -> bool {\n    let rem = size % PAGE;\n    rem == 0 || size <= u64::MAX - (PAGE - rem)\n}","typeGuard":null,"tryCatchPattern":"// surfaced via Segment::write; see write's own InvalidInput handling:\nmatch seg.write(buf) {\n    Err(ref e) if e.kind() == std::io::ErrorKind::InvalidInput\n        && e.to_string().contains(\"overflow\") => { /* position/size corrupted: investigate */ }\n    r => r?,\n}","preventionTips":["Cap accepted write sizes and positions well below u64::MAX at the API boundary","Keep test positions realistic; avoid constructing sizes near 2^64","Treat occurrence outside tests as corrupted state, not a tuning issue"],"tags":["commitlog","storage","rust","integer-overflow","allocation","simulation"],"backgroundTag":"integer-overflow","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}