Skip to content

Commit dc4b277

Browse files
committed
validation: accept pointers in integer arrays
1 parent c96eb70 commit dc4b277

File tree

4 files changed

+46
-6
lines changed

4 files changed

+46
-6
lines changed

src/librustc_mir/interpret/memory.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
650650
}
651651

652652
/// It is the caller's responsibility to handle undefined and pointer bytes.
653-
/// However, this still checks that there are no relocations on the egdes.
653+
/// However, this still checks that there are no relocations on the *egdes*.
654654
#[inline]
655655
fn get_bytes_with_undef_and_ptr(
656656
&self,
@@ -842,6 +842,28 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
842842
}
843843
}
844844

845+
pub fn check_bytes(
846+
&self,
847+
ptr: Scalar<M::PointerTag>,
848+
size: Size,
849+
allow_ptr: bool,
850+
) -> EvalResult<'tcx> {
851+
// Empty accesses don't need to be valid pointers, but they should still be non-NULL
852+
let align = Align::from_bytes(1, 1).unwrap();
853+
if size.bytes() == 0 {
854+
self.check_align(ptr, align)?;
855+
return Ok(());
856+
}
857+
let ptr = ptr.to_ptr()?;
858+
self.get_bytes_with_undef_and_ptr(ptr, size, align)?;
859+
// Check undef, and maybe ptr
860+
self.check_defined(ptr, size)?;
861+
if !allow_ptr {
862+
self.check_relocations(ptr, size)?;
863+
}
864+
Ok(())
865+
}
866+
845867
pub fn read_bytes(&self, ptr: Scalar<M::PointerTag>, size: Size) -> EvalResult<'tcx, &[u8]> {
846868
// Empty accesses don't need to be valid pointers, but they should still be non-NULL
847869
let align = Align::from_bytes(1, 1).unwrap();

src/librustc_mir/interpret/validity.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -496,9 +496,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
496496
}
497497
// Special handling for arrays/slices of builtin integer types
498498
ty::Array(tys, ..) | ty::Slice(tys) if {
499-
// This optimization applies only for integer types
499+
// This optimization applies only for integer and floating point types
500+
// (i.e., types that can hold arbitrary bytes).
500501
match tys.sty {
501-
ty::Int(..) | ty::Uint(..) => true,
502+
ty::Int(..) | ty::Uint(..) | ty::Float(..) => true,
502503
_ => false,
503504
}
504505
} => {
@@ -510,9 +511,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
510511
// This is the size in bytes of the whole array.
511512
let size = Size::from_bytes(ty_size * len);
512513

513-
match self.memory.read_bytes(dest.ptr, size) {
514+
// In run-time mode, we accept points in here. This is actually more
515+
// permissive than a per-element check would be, e.g. we accept
516+
// an &[u8] that contains a pointer even though bytewise checking would
517+
// reject it. However, that's good: We don't inherently want
518+
// to reject those pointers, we just do not have the machinery to
519+
// talk about parts of a pointer.
520+
match self.memory.check_bytes(dest.ptr, size, /*allow_ptr*/!const_mode) {
514521
// In the happy case, we needn't check anything else.
515-
Ok(_) => {},
522+
Ok(()) => {},
516523
// Some error happened, try to provide a more detailed description.
517524
Err(err) => {
518525
// For some errors we might be able to provide extra information

src/test/ui/consts/const-eval/ub-ref.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ const NULL: &u16 = unsafe { mem::transmute(0usize) };
2121
const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
2222
//~^ ERROR this constant likely exhibits undefined behavior
2323

24+
const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
25+
//~^ ERROR this constant likely exhibits undefined behavior
26+
2427
const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
2528
//~^ ERROR this constant likely exhibits undefined behavior
2629

src/test/ui/consts/const-eval/ub-ref.stderr

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,19 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
2525
error[E0080]: this constant likely exhibits undefined behavior
2626
--> $DIR/ub-ref.rs:24:1
2727
|
28+
LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a raw memory access tried to access part of a pointer value as raw bytes
30+
|
31+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
32+
33+
error[E0080]: this constant likely exhibits undefined behavior
34+
--> $DIR/ub-ref.rs:27:1
35+
|
2836
LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
2937
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered integer pointer in non-ZST reference
3038
|
3139
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
3240

33-
error: aborting due to 4 previous errors
41+
error: aborting due to 5 previous errors
3442

3543
For more information about this error, try `rustc --explain E0080`.

0 commit comments

Comments
 (0)