Skip to content

Commit c7f8e68

Browse files
committed
CTFE: more informative error message on ReadPointerAsBytes trouble
1 parent 1ec9b66 commit c7f8e68

21 files changed

+275
-50
lines changed

compiler/rustc_const_eval/src/const_eval/error.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_span::{Span, Symbol};
99

1010
use super::InterpCx;
1111
use crate::interpret::{
12-
struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType,
12+
struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType, UnsupportedOpInfo,
1313
};
1414

1515
/// The CTFE machine has some custom error kinds.
@@ -153,6 +153,17 @@ impl<'tcx> ConstEvalErr<'tcx> {
153153
if let Some(span_msg) = span_msg {
154154
err.span_label(self.span, span_msg);
155155
}
156+
// Add some more context for select error types.
157+
match self.error {
158+
InterpError::Unsupported(
159+
UnsupportedOpInfo::ReadPointerAsBytes
160+
| UnsupportedOpInfo::PartialPointerOverwrite(_)
161+
) => {
162+
err.help("this code performed an operation that depends on the underlying bytes representing a pointer");
163+
err.help("the absolute address of a pointer is not known at compile-time, so such operations are not supported");
164+
}
165+
_ => {}
166+
}
156167
// Add spans for the stacktrace. Don't print a single-line backtrace though.
157168
if self.stacktrace.len() > 1 {
158169
// Helper closure to print duplicated lines.

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::interpret::eval_nullary_intrinsic;
33
use crate::interpret::{
44
intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId,
55
Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
6-
ScalarMaybeUninit, StackPopCleanup,
6+
ScalarMaybeUninit, StackPopCleanup, InterpError,
77
};
88

99
use rustc_hir::def::DefKind;
@@ -374,7 +374,9 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
374374
ecx.tcx,
375375
"it is undefined behavior to use this value",
376376
|diag| {
377-
diag.note(NOTE_ON_UNDEFINED_BEHAVIOR_ERROR);
377+
if matches!(err.error, InterpError::UndefinedBehavior(_)) {
378+
diag.note(NOTE_ON_UNDEFINED_BEHAVIOR_ERROR);
379+
}
378380
diag.note(&format!(
379381
"the raw bytes of the constant ({}",
380382
display_allocation(

compiler/rustc_const_eval/src/interpret/validity.rs

+10-34
Original file line numberDiff line numberDiff line change
@@ -324,11 +324,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
324324
// FIXME: check if the type/trait match what ty::Dynamic says?
325325
}
326326
ty::Slice(..) | ty::Str => {
327-
let _len = try_validation!(
328-
meta.unwrap_meta().to_machine_usize(self.ecx),
329-
self.path,
330-
err_unsup!(ReadPointerAsBytes) => { "non-integer slice length in wide pointer" },
331-
);
327+
let _len = meta.unwrap_meta().to_machine_usize(self.ecx)?;
332328
// We do not check that `len * elem_size <= isize::MAX`:
333329
// that is only required for references, and there it falls out of the
334330
// "dereferenceable" check performed by Stacked Borrows.
@@ -348,11 +344,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
348344
value: &OpTy<'tcx, M::Provenance>,
349345
kind: &str,
350346
) -> InterpResult<'tcx> {
351-
let value = try_validation!(
352-
self.ecx.read_immediate(value),
353-
self.path,
354-
err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
355-
);
347+
let value = self.ecx.read_immediate(value)?;
356348
// Handle wide pointers.
357349
// Check metadata early, for better diagnostics
358350
let place = try_validation!(
@@ -458,22 +450,14 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
458450
&self,
459451
op: &OpTy<'tcx, M::Provenance>,
460452
) -> InterpResult<'tcx, ScalarMaybeUninit<M::Provenance>> {
461-
Ok(try_validation!(
462-
self.ecx.read_scalar(op),
463-
self.path,
464-
err_unsup!(ReadPointerAsBytes) => { "(potentially part of) a pointer" } expected { "plain (non-pointer) bytes" },
465-
))
453+
self.ecx.read_scalar(op)
466454
}
467455

468456
fn read_immediate_forced(
469457
&self,
470458
op: &OpTy<'tcx, M::Provenance>,
471459
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
472-
Ok(*try_validation!(
473-
self.ecx.read_immediate_raw(op, /*force*/ true),
474-
self.path,
475-
err_unsup!(ReadPointerAsBytes) => { "(potentially part of) a pointer" } expected { "plain (non-pointer) bytes" },
476-
).unwrap())
460+
Ok(*self.ecx.read_immediate_raw(op, /*force*/ true)?.unwrap())
477461
}
478462

479463
/// Check if this is a value of primitive type, and if yes check the validity of the value
@@ -535,7 +519,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
535519
self.ecx.read_immediate(value).and_then(|ref i| self.ecx.ref_to_mplace(i)),
536520
self.path,
537521
err_ub!(InvalidUninitBytes(None)) => { "uninitialized raw pointer" },
538-
err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
539522
);
540523
if place.layout.is_unsized() {
541524
self.check_wide_ptr_meta(place.meta, place.layout)?;
@@ -560,7 +543,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
560543
let value = try_validation!(
561544
self.ecx.read_scalar(value).and_then(|v| v.check_init()),
562545
self.path,
563-
err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
564546
err_ub!(InvalidUninitBytes(None)) => { "uninitialized bytes" } expected { "a proper pointer or integer value" },
565547
);
566548

@@ -715,8 +697,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
715697
{ "{:x}", val } expected { "a valid enum tag" },
716698
err_ub!(InvalidUninitBytes(None)) =>
717699
{ "uninitialized bytes" } expected { "a valid enum tag" },
718-
err_unsup!(ReadPointerAsBytes) =>
719-
{ "a pointer" } expected { "a valid enum tag" },
720700
)
721701
.1)
722702
})
@@ -853,7 +833,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
853833
self.ecx.read_bytes_ptr(mplace.ptr, Size::from_bytes(len)),
854834
self.path,
855835
err_ub!(InvalidUninitBytes(..)) => { "uninitialized data in `str`" },
856-
err_unsup!(ReadPointerAsBytes) => { "a pointer in `str`" },
857836
);
858837
}
859838
ty::Array(tys, ..) | ty::Slice(tys)
@@ -925,9 +904,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
925904

926905
throw_validation_failure!(self.path, { "uninitialized bytes" })
927906
}
928-
err_unsup!(ReadPointerAsBytes) => {
929-
throw_validation_failure!(self.path, { "a pointer" } expected { "plain (non-pointer) bytes" })
930-
}
931907

932908
// Propagate upwards (that will also check for unexpected errors).
933909
_ => return Err(err),
@@ -968,14 +944,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
968944
Ok(()) => Ok(()),
969945
// Pass through validation failures.
970946
Err(err) if matches!(err.kind(), err_ub!(ValidationFailure { .. })) => Err(err),
971-
// Also pass through InvalidProgram, those just indicate that we could not
972-
// validate and each caller will know best what to do with them.
973-
Err(err) if matches!(err.kind(), InterpError::InvalidProgram(_)) => Err(err),
974-
// Avoid other errors as those do not show *where* in the value the issue lies.
975-
Err(err) => {
947+
// Complain about any other kind of UB error -- those are bad because we'd like to
948+
// report them in a way that shows *where* in the value the issue lies.
949+
Err(err) if matches!(err.kind(), InterpError::UndefinedBehavior(_)) => {
976950
err.print_backtrace();
977-
bug!("Unexpected error during validation: {}", err);
951+
bug!("Unexpected Undefined Behavior error during validation: {}", err);
978952
}
953+
// Pass through everything else.
954+
Err(err) => Err(err),
979955
}
980956
}
981957

src/test/ui/const-ptr/forbidden_slices.32bit.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,10 @@ error[E0080]: it is undefined behavior to use this value
5555
--> $DIR/forbidden_slices.rs:27:1
5656
|
5757
LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
58-
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
58+
| ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
5959
|
60-
= 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.
60+
= help: this code performed an operation that depends on the underlying bytes representing a pointer
61+
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
6162
= note: the raw bytes of the constant (size: 8, align: 4) {
6263
╾─ALLOC_ID─╼ 04 00 00 00 │ ╾──╼....
6364
}
@@ -170,9 +171,10 @@ error[E0080]: it is undefined behavior to use this value
170171
--> $DIR/forbidden_slices.rs:57:1
171172
|
172173
LL | pub static R5: &[u8] = unsafe {
173-
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
174+
| ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
174175
|
175-
= 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.
176+
= help: this code performed an operation that depends on the underlying bytes representing a pointer
177+
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
176178
= note: the raw bytes of the constant (size: 8, align: 4) {
177179
╾ALLOC_ID─╼ 04 00 00 00 │ ╾──╼....
178180
}

src/test/ui/const-ptr/forbidden_slices.64bit.stderr

+6-4
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,10 @@ error[E0080]: it is undefined behavior to use this value
5555
--> $DIR/forbidden_slices.rs:27:1
5656
|
5757
LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
58-
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
58+
| ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
5959
|
60-
= 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.
60+
= help: this code performed an operation that depends on the underlying bytes representing a pointer
61+
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
6162
= note: the raw bytes of the constant (size: 16, align: 8) {
6263
╾───────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
6364
}
@@ -170,9 +171,10 @@ error[E0080]: it is undefined behavior to use this value
170171
--> $DIR/forbidden_slices.rs:57:1
171172
|
172173
LL | pub static R5: &[u8] = unsafe {
173-
| ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
174+
| ^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
174175
|
175-
= 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.
176+
= help: this code performed an operation that depends on the underlying bytes representing a pointer
177+
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
176178
= note: the raw bytes of the constant (size: 16, align: 8) {
177179
╾──────ALLOC_ID───────╼ 08 00 00 00 00 00 00 00 │ ╾──────╼........
178180
}

0 commit comments

Comments
 (0)