{"record":{"id":"2e2415e2b0ee7397","repo":"pydantic/monty","slug":"masked-below-2-32","errorCode":null,"errorMessage":"masked below 2**32","messagePattern":"masked below 2\\*\\*32","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"info","filePath":"crates/monty/src/modules/binascii.rs","lineNumber":412,"sourceCode":"    data: Value,\n    #[from_args(default = Value::Bool(false))]\n    header: Value,\n}\n\n/// Reduces an `int` to the `unsigned int` CPython's `I` format takes, which\n/// wraps modulo 2**32 rather than rejecting a value out of range — so a\n/// negative or huge `crc` seed is accepted, as CPython accepts it.\nfn wrapping_u32(value: &Value, vm: &VM<'_>) -> RunResult<u32> {\n    const MODULUS: i64 = 1 << 32;\n\n    match value {\n        Value::Int(int) => Ok(u32::try_from(int.rem_euclid(MODULUS)).expect(\"reduced below 2**32\")),\n        Value::Bool(flag) => Ok(u32::from(*flag)),\n        Value::Ref(heap_id) => match vm.heap.get(*heap_id) {\n            HeapData::LongInt(long) => {\n                // `&` on a `BigInt` is two's-complement, so this is Python's\n                // own `value & 0xffffffff` for negatives as well.\n                Ok((&long.0 & BigInt::from(u32::MAX)).to_u32().expect(\"masked below 2**32\"))\n            }\n            _ => Err(ExcType::type_error_not_integer(&value.py_type_name(vm))),\n        },\n        _ => Err(ExcType::type_error_not_integer(&value.py_type_name(vm))),\n    }\n}\n\n/// Encodes bytes as lowercase hex, inserting `sep` every `bytes_per_sep` bytes.\n///\n/// A positive `bytes_per_sep` groups from the right, so any short group leads;\n/// a negative one groups from the left. Zero, or no separator, means none.\nfn hex_encode(data: &[u8], sep: Option<u8>, bytes_per_sep: i32) -> Vec<u8> {\n    let group = match sep {\n        Some(_) if bytes_per_sep != 0 && !data.is_empty() => usize::try_from(bytes_per_sep.unsigned_abs())\n            .expect(\"u32 fits usize on supported targets\")\n            .min(data.len()),\n        // Without a separator, or with an empty input, emit one flat run.\n        _ => data.len().max(1),","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty/src/modules/binascii.rs#L394-L430","documentation":"Internal `expect` in `wrapping_u32` for arbitrary-precision (`LongInt`) seeds: the BigInt is bitwise-ANDed with `0xffffffff`, so the result fits a `u32` and `to_u32()` cannot return `None`. The two's-complement `&` reproduces Python's `value & 0xffffffff` for negatives. Not user-triggerable from `crc32`/`crc_hqx`.","triggerScenarios":"Unreachable; requires the mask (`& BigInt::from(u32::MAX)`) to be removed or changed in a code edit.","commonSituations":"Only during refactors of the bigint seed path in `wrapping_u32`.","solutions":["No runtime action; preserve the `& 0xffffffff` masking before `to_u32()`."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Mask BigInt seeds with `& u32::MAX` before `to_u32()`; add a test seeding crc32 with a negative and a >2**32 integer."],"tags":["rust","internal-invariant","bigint"],"backgroundTag":"internal-invariant-violation","analyzedSha":"adc986b362e3961f407868cb118a99fe831b9e61","analyzedAt":"2026-09-13T19:19:18.698Z","contentChangedAt":"2026-09-13T19:19:18.698Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}