{"record":{"id":"06bfc4fea58d1575","repo":"pola-rs/polars","slug":"offset-to-fit-in-usize-06bfc4","errorCode":null,"errorMessage":"Offset to fit in `usize`","messagePattern":"Offset to fit in `usize`","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/polars-arrow/src/ffi/array.rs","lineNumber":358,"sourceCode":"    let storage = SharedStorage::from_slice_with_owner(slice, owner);\n\n    let null_count = if is_validity {\n        Some(array.null_count())\n    } else {\n        None\n    };\n    Ok(Bitmap::from_inner_unchecked(\n        storage, offset, len, null_count,\n    ))\n}\n\nfn buffer_offset(array: &ArrowArray, dtype: &ArrowDataType, i: usize) -> usize {\n    use PhysicalType::*;\n    match (dtype.to_physical_type(), i) {\n        (LargeUtf8, 2) | (LargeBinary, 2) | (Utf8, 2) | (Binary, 2) => 0,\n        (FixedSizeBinary, 1) => {\n            if let ArrowDataType::FixedSizeBinary(size) = dtype.to_storage() {\n                let offset: usize = array.offset.try_into().expect(\"Offset to fit in `usize`\");\n                offset * *size\n            } else {\n                unreachable!()\n            }\n        },\n        _ => array.offset.try_into().expect(\"Offset to fit in `usize`\"),\n    }\n}\n\n/// Returns the length, in slots, of the buffer `i` (indexed according to the C data interface)\nunsafe fn buffer_len(array: &ArrowArray, dtype: &ArrowDataType, i: usize) -> PolarsResult<usize> {\n    Ok(match (dtype.to_physical_type(), i) {\n        (PhysicalType::FixedSizeBinary, 1) => {\n            if let ArrowDataType::FixedSizeBinary(size) = dtype.to_storage() {\n                *size * (array.offset as usize + array.length as usize)\n            } else {\n                unreachable!()\n            }","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/pola-rs/polars/blob/9b5d73fd00236295624374b075d16b1fe6ec6df9/crates/polars-arrow/src/ffi/array.rs#L340-L376","documentation":"`buffer_offset` in crates/polars-arrow/src/ffi/array.rs computes the byte offset into buffer index 1 for FixedSizeBinary arrays: `array.offset.try_into().expect(\"Offset to fit in `usize`\") * size`. Since `array.offset` is i64, a negative value (or one too large for usize on 32-bit) panics here before the multiplication with the fixed element width.","triggerScenarios":"Importing a FixedSizeBinary array over the C Data Interface whose ArrowArray.offset is negative or corrupt. The FixedSizeBinary arm is hit because its values buffer starts at byte `offset * size`, unlike types where the offset only affects bitmap indexing.","commonSituations":"FFI producers exporting sliced fixed-size-binary columns (e.g. 16-byte UUID/hash arrays) with a buggy slice calculation; uninitialized struct fields; struct-layout mismatch between the producer's Arrow version and polars-arrow's generated bindings (ffi/generated.rs).","solutions":["Fix the producer's offset computation for sliced FixedSizeBinary exports (offset must be the element-slot count, non-negative).","Validate/zero-init the whole ArrowArray struct on export and set fields explicitly.","Wrap `from_ffi` in catch_unwind at the boundary to convert the panic into an error you can attribute to the producer.","Reproduce with a known-good producer (pyarrow) to confirm the bug is on the foreign side."],"exampleFix":"// before\nlet array = unsafe { from_ffi(fsb_imported, owner) }?; // panics in buffer_offset(FixedSizeBinary, 1)\n\n// after\nlet array = std::panic::catch_unwind(|| unsafe { from_ffi(fsb_imported, owner) })\n    .map_err(|_| polars_err!(ComputeError: \"FixedSizeBinary export has invalid offset\"))??;","handlingStrategy":"try-catch","validationCode":"// Producer-side: for FixedSizeBinary(size) exports, offset must be a non-negative\n// element-slot count: assert(offset >= 0 && offset * size + length * size <= buffer_len).","typeGuard":null,"tryCatchPattern":"let array = std::panic::catch_unwind(|| unsafe { polars_arrow::ffi::from_ffi(fsb, owner) })\n    .map_err(|_| polars_err!(ComputeError: \"FixedSizeBinary FFI offset invalid\"))?;","preventionTips":["For sliced fixed-size-binary exports, express the slice as element-slot offset (not bytes) >= 0.","Validate byte-buffer capacity against offset*size on the producer before release.","Test sliced (non-zero offset) exports explicitly — unsliced ones never hit this path."],"tags":["rust","polars","arrow","ffi","c-data-interface","fixed-size-binary","offset","panic"],"backgroundTag":"c-data-interface-invalid-metadata","analyzedSha":"9b5d73fd00236295624374b075d16b1fe6ec6df9","analyzedAt":"2026-08-19T12:15:06.350Z","contentChangedAt":"2026-08-19T12:15:06.350Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}