Skip to content

Commit 5e8435a

Browse files
Rollup merge of #82061 - RalfJung:ctfe-read-pointer-as-bytes, r=oli-obk
CTFE validation: catch ReadPointerAsBytes and better error r? ``@oli-obk`` Fixes #79690 Cc rust-lang/miri#1706
2 parents c7ebc59 + d6dcb3d commit 5e8435a

File tree

2 files changed

+30
-14
lines changed

2 files changed

+30
-14
lines changed

compiler/rustc_mir/src/interpret/validity.rs

+29-13
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use std::hash::Hash;
2121

2222
use super::{
2323
CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
24-
ValueVisitor,
24+
ScalarMaybeUninit, ValueVisitor,
2525
};
2626

2727
macro_rules! throw_validation_failure {
@@ -378,7 +378,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
378378
value: OpTy<'tcx, M::PointerTag>,
379379
kind: &str,
380380
) -> InterpResult<'tcx> {
381-
let value = self.ecx.read_immediate(value)?;
381+
let value = try_validation!(
382+
self.ecx.read_immediate(value),
383+
self.path,
384+
err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
385+
);
382386
// Handle wide pointers.
383387
// Check metadata early, for better diagnostics
384388
let place = try_validation!(
@@ -485,6 +489,17 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
485489
Ok(())
486490
}
487491

492+
fn read_scalar(
493+
&self,
494+
op: OpTy<'tcx, M::PointerTag>,
495+
) -> InterpResult<'tcx, ScalarMaybeUninit<M::PointerTag>> {
496+
Ok(try_validation!(
497+
self.ecx.read_scalar(op),
498+
self.path,
499+
err_unsup!(ReadPointerAsBytes) => { "(potentially part of) a pointer" } expected { "plain (non-pointer) bytes" },
500+
))
501+
}
502+
488503
/// Check if this is a value of primitive type, and if yes check the validity of the value
489504
/// at that type. Return `true` if the type is indeed primitive.
490505
fn try_visit_primitive(
@@ -495,7 +510,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
495510
let ty = value.layout.ty;
496511
match ty.kind() {
497512
ty::Bool => {
498-
let value = self.ecx.read_scalar(value)?;
513+
let value = self.read_scalar(value)?;
499514
try_validation!(
500515
value.to_bool(),
501516
self.path,
@@ -505,7 +520,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
505520
Ok(true)
506521
}
507522
ty::Char => {
508-
let value = self.ecx.read_scalar(value)?;
523+
let value = self.read_scalar(value)?;
509524
try_validation!(
510525
value.to_char(),
511526
self.path,
@@ -515,11 +530,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
515530
Ok(true)
516531
}
517532
ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
518-
let value = try_validation!(
519-
self.ecx.read_scalar(value),
520-
self.path,
521-
err_unsup!(ReadPointerAsBytes) => { "read of part of a pointer" },
522-
);
533+
let value = self.read_scalar(value)?;
523534
// NOTE: Keep this in sync with the array optimization for int/float
524535
// types below!
525536
if self.ctfe_mode.is_some() {
@@ -541,9 +552,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
541552
// actually enforce the strict rules for raw pointers (mostly because
542553
// that lets us re-use `ref_to_mplace`).
543554
let place = try_validation!(
544-
self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?),
555+
self.ecx.read_immediate(value).and_then(|i| self.ecx.ref_to_mplace(i)),
545556
self.path,
546557
err_ub!(InvalidUninitBytes(None)) => { "uninitialized raw pointer" },
558+
err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
547559
);
548560
if place.layout.is_unsized() {
549561
self.check_wide_ptr_meta(place.meta, place.layout)?;
@@ -569,9 +581,13 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
569581
Ok(true)
570582
}
571583
ty::FnPtr(_sig) => {
572-
let value = self.ecx.read_scalar(value)?;
584+
let value = try_validation!(
585+
self.ecx.read_immediate(value),
586+
self.path,
587+
err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
588+
);
573589
let _fn = try_validation!(
574-
value.check_init().and_then(|ptr| self.ecx.memory.get_fn(ptr)),
590+
value.to_scalar().and_then(|ptr| self.ecx.memory.get_fn(ptr)),
575591
self.path,
576592
err_ub!(DanglingIntPointer(..)) |
577593
err_ub!(InvalidFunctionPointer(..)) |
@@ -615,7 +631,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
615631
op: OpTy<'tcx, M::PointerTag>,
616632
scalar_layout: &Scalar,
617633
) -> InterpResult<'tcx> {
618-
let value = self.ecx.read_scalar(op)?;
634+
let value = self.read_scalar(op)?;
619635
let valid_range = &scalar_layout.valid_range;
620636
let (lo, hi) = valid_range.clone().into_inner();
621637
// Determine the allowed range

src/test/ui/consts/issue-79690.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/issue-79690.rs:29:1
33
|
44
LL | const G: Fat = unsafe { Transmute { t: FOO }.u };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered read of part of a pointer at .1.<deref>.size.foo
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered (potentially part of) a pointer at .1.<deref>.size.foo, but expected plain (non-pointer) bytes
66
|
77
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
88

0 commit comments

Comments
 (0)