{"record":{"id":"0bacca5b9172b1be","repo":"gfx-rs/wgpu","slug":"slice-offset-slice-offset-size-slice-size-is-o","errorCode":null,"errorMessage":"slice offset {slice_offset} size {slice_size} is out of range for buffer of size {whole_size}","messagePattern":"slice offset (.+?) size (.+?) is out of range for buffer of size (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"wgpu/src/api/buffer.rs","lineNumber":1065,"sourceCode":"}\n\n#[track_caller]\nfn check_buffer_bounds(\n    whole_size: BufferAddress,\n    slice_offset: BufferAddress,\n    slice_size: BufferAddress,\n) {\n    if slice_offset > whole_size {\n        panic!(\n            \"slice offset {} is out of range for buffer of size {}\",\n            slice_offset, whole_size\n        );\n    }\n\n    // Detect integer overflow.\n    let end = slice_offset.checked_add(slice_size);\n    if end.is_none_or(|end| end > whole_size) {\n        panic!(\n            \"slice offset {} size {} is out of range for buffer of size {}\",\n            slice_offset, slice_size, whole_size\n        );\n    }\n}\n\n#[track_caller]\npub(crate) fn range_to_offset_size<S: RangeBounds<BufferAddress>>(\n    bounds: S,\n    whole_size: BufferAddress,\n) -> (BufferAddress, BufferAddress) {\n    let offset = match bounds.start_bound() {\n        Bound::Included(&bound) => bound,\n        Bound::Excluded(&bound) => bound + 1,\n        Bound::Unbounded => 0,\n    };\n    let size = match bounds.end_bound() {\n        Bound::Included(&bound) => bound + 1 - offset,","sourceCodeStart":1047,"sourceCodeEnd":1083,"githubUrl":"https://github.com/gfx-rs/wgpu/blob/3e11ff59bf3f9795d285ecc045014089640d7248/wgpu/src/api/buffer.rs#L1047-L1083","documentation":"Buffer::slice also validates offset + size, panicking when the addition overflows or the end of the requested range exceeds the buffer's total size. This guarantees every buffer slice refers to memory fully inside the buffer.","triggerScenarios":"Calling buffer.slice(start..end) where end > buffer.size(), or where start + end overflows u64 (the checked_add path), e.g. a wraparound from a bad computation.","commonSituations":"Computing dynamic bind-group offsets with wrapping arithmetic, stacking multiple regions into one buffer and running past the end, or unit mistakes (bytes vs. element counts) inflating the end offset.","solutions":["Ensure offset + size <= buffer.size() before slicing; recompute the end from buffer.size().","Fix integer overflow in offset arithmetic (use saturating/checked math and correct types).","Resize the buffer at creation time to cover all regions you plan to slice."],"exampleFix":"// before\nlet view = buffer.slice(off..off + size); // off + size > buffer.size()\n// after\nlet end = off + size;\nassert!(end <= buffer.size());\nlet view = buffer.slice(off..end);","handlingStrategy":"validation","validationCode":"let end = slice_offset.checked_add(slice_size);\nmatch end {\n    Some(e) if e <= buffer.size() => buffer.slice(slice_offset..e),\n    _ => return Err(\"slice range out of bounds or overflowing\".into()),\n}","typeGuard":null,"tryCatchPattern":"let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| buffer.slice(off..off + size)));","preventionTips":["Use checked_add when combining offsets and sizes.","Size buffers up front to cover all planned regions, including alignment padding.","Assert end <= buffer.size() in debug builds around dynamic bind-group offset code."],"tags":["panic","rust","buffer","bounds","overflow"],"backgroundTag":"buffer-out-of-bounds","analyzedSha":"3e11ff59bf3f9795d285ecc045014089640d7248","analyzedAt":"2026-09-03T01:43:21.459Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T07:17:11.731Z"}