{"id":"edfbff0d618a4ab8","repo":"rust-lang/rust","slug":"there-must-be-provenance-somewhere-here","errorCode":null,"errorMessage":"there must be provenance somewhere here","messagePattern":"there must be provenance somewhere here","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/rustc_middle/src/mir/interpret/allocation.rs","lineNumber":614,"sourceCode":"    #[inline]\n    pub fn get_bytes_strip_provenance(\n        &self,\n        cx: &impl HasDataLayout,\n        range: AllocRange,\n    ) -> AllocResult<&[u8]> {\n        self.init_mask.is_range_initialized(range).map_err(|uninit_range| {\n            AllocError::InvalidUninitBytes(Some(BadBytesAccess {\n                access: range,\n                bad: uninit_range,\n            }))\n        })?;\n        if !Prov::OFFSET_IS_ADDR && !self.provenance.range_empty(range, cx) {\n            // Find the provenance.\n            let (prov_range, _prov) = self\n                .provenance\n                .get_range(range, cx)\n                .next()\n                .expect(\"there must be provenance somewhere here\");\n            let start = prov_range.start.max(range.start); // the pointer might begin before `range`!\n            let end = prov_range.end().min(range.end()); // the pointer might end after `range`!\n            return Err(AllocError::ReadPointerAsInt(Some(BadBytesAccess {\n                access: range,\n                bad: AllocRange::from(start..end),\n            })));\n        }\n        Ok(self.get_bytes_unchecked(range))\n    }\n\n    /// This is the entirely abstraction-violating way to just get mutable access to the raw bytes.\n    /// Just calling this already marks everything as defined and removes provenance, so be sure to\n    /// actually overwrite all the data there!\n    ///\n    /// It is the caller's responsibility to check bounds and alignment beforehand.\n    /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods\n    /// on `InterpCx` instead.\n    pub fn get_bytes_unchecked_for_overwrite(","sourceCodeStart":596,"sourceCodeEnd":632,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_middle/src/mir/interpret/allocation.rs#L596-L632","documentation":"This `.expect` in `Allocation::get_bytes_strip_provenance` fires only when `Prov::OFFSET_IS_ADDR == false` AND `provenance.range_empty(range, cx)` returned `false` (provenance overlaps the range) yet `provenance.get_range(range, cx).next()` yields `None`. The two provenance queries are supposed to agree: if the range overlaps any provenance, `get_range` must produce at least one entry. The panic therefore signals corruption or desync inside the provenance bookkeeping data structure (the tags/blocks table), not a user error.","triggerScenarios":"An allocation whose `Provenance` map became inconsistent — e.g. a `clear`/`init`/`write_provenance` sequence left `range_empty` and `get_range` disagreeing; a partial write that updated only one of two internal indices; or a fuzzed allocation whose bytes/provenance/init_mask triples were mutated out of sync. Reachable via Miri, const-eval, or any direct caller of `get_bytes_strip_provenance` on a corrupted `Allocation`.","commonSituations":"Miri/MIR-interpret test failures after touching the `Provenance` enum or switching between `Tag` and `AllocId` provenance; rmeta/const-eval regressions when a new optimization reorders provenance-clearing vs byte writes; differential-fuzzing crashes between two rustc builds.","solutions":["Reproduce with `RUST_BACKTRACE=1` and capture the allocation id + range from the panic context, then audit the last `write_provenance`/`mark_init`/`clear` calls on that allocation.","Bisect recent changes to `compiler/rustc_middle/src/mir/interpret/allocation.rs` and the `Provenance` impl — the bug is almost always an index update that skipped one of the two queries.","Run the case under Miri with extra checks (`-Zmiri-track-raw-pointers -Zmiri-validate-resolution`) to surface the first inconsistent write.","Report as a rustc ICE with a minimal repro; do not try to silence the expect."],"exampleFix":"// This is an internal invariant; no user-side code change silences it safely.\n// before: provenance.range_empty(r) == false and provenance.get_range(r).next() == None\n// fix: make the Provenance impl keep `range_empty` and `get_range` in lockstep.\n// e.g. in `clear`, also drop the block from the range index:\n\nimpl Provenance {\n    fn clear(&mut self, range: AllocRange, ...) {\n        self.blocks.retain(|b| !range.contains(b.range)); // keep both views consistent\n    }\n}","handlingStrategy":"validation","validationCode":"// The expect fires when provenance.range_empty(range, cx) was false but\n// get_range(range, cx).next() returned None -- an internal inconsistency.\n// You cannot fully prevent an ICE here from the outside, but you can avoid\n// feeding it ranges whose provenance bookkeeping you have not confirmed.\nfn range_has_provenance<Prov, Cx>(\n    alloc: &Allocation<Prov>,\n    range: AllocRange,\n    cx: &Cx,\n) -> bool\nwhere\n    Prov: ProvenanceMap<Cx>,\n{\n    !alloc.provenance.range_empty(range, cx)\n        && alloc.provenance.get_range(range, cx).next().is_some()\n}\n\nif !range_has_provenance(alloc, range, cx) {\n    return Err(\"provenance bookkeeping inconsistent for range\");\n}","typeGuard":null,"tryCatchPattern":"let bytes = std::panic::catch_unwind(|| alloc.get_bytes_with_provenance(cx, range));\nmatch bytes {\n    Ok(b) => /* use b */,\n    Err(_) => /* this is an ICE: report upstream with the allocation dump */,\n}","preventionTips":["Treat this panic as an internal-compiler-error signal: it indicates corrupted allocation provenance, not user input, so file a rustc issue with the reproducer rather than working around it.","When manipulating allocations directly (e.g. in Miri or a custom codegen), keep the provenance map and byte writes in lockstep so no range is ever marked as having provenance without an entry.","Before reading bytes that may overlap a pointer, prefer the higher-level read_scalar / read_pointer APIs that return Err(AllocError) instead of the unchecked byte path.","If you build allocations incrementally, run a self-check pass (provenance ranges are non-overlapping and within bounds) before handing the allocation to interpretation."],"tags":["rustc","mir","const-eval","interpreter","provenance","internal","compiler-ice"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}