rust-lang/rust · error
got a pointer where a ScalarInt was expected
Error message
got a pointer where a ScalarInt was expected
What it means
`Scalar::assert_scalar_int` (value.rs:325) panics when called on a `Scalar::Ptr(..)` — it is the unchecked variant that assumes the caller has already ensured the scalar holds an integer. The checked sibling `try_to_scalar_int` returns `Ok(ScalarInt)` only for `Scalar::Int` (or, when `Prov::OFFSET_IS_ADDR`, for pointers that can be folded into an address); `assert_scalar_int` simply `.expect`s that result.
Source
Thrown at compiler/rustc_middle/src/mir/interpret/value.rs:325
}
}
pub fn clear_provenance(&mut self) -> InterpResult<'tcx> {
if matches!(self, Scalar::Ptr(..)) {
*self = self.to_scalar_int()?.into();
}
interp_ok(())
}
#[inline(always)]
pub fn to_scalar_int(self) -> InterpResult<'tcx, ScalarInt> {
self.try_to_scalar_int().map_err(|_| err_unsup!(ReadPointerAsInt(None))).into()
}
#[inline(always)]
#[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
pub fn assert_scalar_int(self) -> ScalarInt {
self.try_to_scalar_int().expect("got a pointer where a ScalarInt was expected")
}
/// This throws UB (instead of ICEing) on a size mismatch since size mismatches can arise in
/// Miri when someone declares a function that we shim (such as `malloc`) with a wrong type.
#[inline]
pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
self.to_scalar_int()?
.try_to_bits(target_size)
.map_err(|size| {
err_ub!(ScalarSizeMismatch(ScalarSizeMismatch {
target_size: target_size.bytes(),
data_size: size.bytes(),
}))
})
.into()
}
View on GitHub (pinned to 22057b88b0)
Solutions
- Switch to the checked form `scalar.to_scalar_int()?` which yields a proper `InterpError` (`ReadPointerAsInt`) instead of panicking.
- If you truly need an integer and can prove the operand is one, strip provenance first via `Scalar::clear_provenance` before asserting.
- Use `try_to_scalar_int()` and branch on the `Err(Scalar::Ptr)` to emit a precise diagnostic.
- Inspect the `#[track_caller]` location from the panic backtrace to find the asserting caller.
Example fix
// before let int = scalar.assert_scalar_int(); // after let int = scalar.to_scalar_int()?;
Defensive patterns
Strategy: type-guard
Validate before calling
// assert_scalar_int panics when the value is a pointer. Use the fallible API
// instead and branch on whether the value holds an integer.
fn read_as_int<'tcx>(v: Scalar) -> InterpResult<'tcx, ScalarInt> {
v.to_scalar_int() // returns Err(ReadPointerAsInt) instead of panicking
} Type guard
// Narrow a Scalar before assuming it is an integer.
fn is_scalar_int(v: &Scalar) -> bool {
matches!(v.try_to_scalar_int(), Ok(_))
}
if is_scalar_int(&scalar) {
let bits = scalar.assert_scalar_int();
} else {
// it is a pointer (or uninitialized); handle accordingly
} Try / catch
// Only if you must keep assert_scalar_int in hot path: catch the panic.
let bits = std::panic::catch_unwind(|| scalar.assert_scalar_int());
match bits {
Ok(i) => /* use i */,
Err(_) => /* scalar held a pointer; treat as UB or read it as a pointer */,
} Prevention
- Prefer to_scalar_int() / try_to_scalar_int() over assert_scalar_int(); the assert exists for invariant-holding internals, not untrusted values.
- Before reading bits via to_bits, confirm the scalar is not a pointer with the type guard above.
- Track which Scalars come from pointer-typed allocations and route them through pointer-reading APIs, never integer ones.
- In debug builds assert_scalar_int carries #[track_caller]; when you see this panic, the caller location pinpoints the mistaken integer read.
When it happens
Trigger: Calling `scalar.assert_scalar_int()` on a value that is actually `Scalar::Ptr(ptr, sz)`. Common when a const-eval path assumes a value is an integer (e.g. discriminant, bit read, integer arithmetic) but the operand holds a pointer — most often because provenance stripping was skipped or a pointer flowed into an integer-only MIR op.
Common situations: Miri exercises that expose pointer-as-int paths; const-eval of code that reads the bits of a `usize` cast from a reference; bugs in intrinsic shims (`memcmp`, atomic ops) that call `assert_scalar_int` on operands that may carry provenance; debug builds (`#[cfg_attr(debug_assertions, track_caller)]`) surface this earlier than release.
Related errors
- range should be nonempty
- there must be provenance somewhere here
- an interpreter error got improperly discarded; use `discard_
- Invalid scalar type {val:?}
- statics should not have generic parameters
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/d44d133aceb0d958.json.
Report an issue: GitHub.