}
/// It is the caller's responsibility to handle undefined and pointer bytes.
- /// However, this still checks that there are no relocations on the egdes.
+ /// However, this still checks that there are no relocations on the *egdes*.
#[inline]
fn get_bytes_with_undef_and_ptr(
&self,
}
}
+ pub fn check_bytes(
+ &self,
+ ptr: Scalar<M::PointerTag>,
+ size: Size,
+ allow_ptr: bool,
+ ) -> EvalResult<'tcx> {
+ // Empty accesses don't need to be valid pointers, but they should still be non-NULL
+ let align = Align::from_bytes(1, 1).unwrap();
+ if size.bytes() == 0 {
+ self.check_align(ptr, align)?;
+ return Ok(());
+ }
+ let ptr = ptr.to_ptr()?;
+ self.get_bytes_with_undef_and_ptr(ptr, size, align)?;
+ // Check undef, and maybe ptr
+ self.check_defined(ptr, size)?;
+ if !allow_ptr {
+ self.check_relocations(ptr, size)?;
+ }
+ Ok(())
+ }
+
pub fn read_bytes(&self, ptr: Scalar<M::PointerTag>, size: Size) -> EvalResult<'tcx, &[u8]> {
// Empty accesses don't need to be valid pointers, but they should still be non-NULL
let align = Align::from_bytes(1, 1).unwrap();
}
// Special handling for arrays/slices of builtin integer types
ty::Array(tys, ..) | ty::Slice(tys) if {
- // This optimization applies only for integer types
+ // This optimization applies only for integer and floating point types
+ // (i.e., types that can hold arbitrary bytes).
match tys.sty {
- ty::Int(..) | ty::Uint(..) => true,
+ ty::Int(..) | ty::Uint(..) | ty::Float(..) => true,
_ => false,
}
} => {
// This is the size in bytes of the whole array.
let size = Size::from_bytes(ty_size * len);
- match self.memory.read_bytes(dest.ptr, size) {
+ // In run-time mode, we accept points in here. This is actually more
+ // permissive than a per-element check would be, e.g. we accept
+ // an &[u8] that contains a pointer even though bytewise checking would
+ // reject it. However, that's good: We don't inherently want
+ // to reject those pointers, we just do not have the machinery to
+ // talk about parts of a pointer.
+ match self.memory.check_bytes(dest.ptr, size, /*allow_ptr*/!const_mode) {
// In the happy case, we needn't check anything else.
- Ok(_) => {},
+ Ok(()) => {},
// Some error happened, try to provide a more detailed description.
Err(err) => {
// For some errors we might be able to provide extra information
const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
//~^ ERROR this constant likely exhibits undefined behavior
+const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
+//~^ ERROR this constant likely exhibits undefined behavior
+
const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
//~^ ERROR this constant likely exhibits undefined behavior
error[E0080]: this constant likely exhibits undefined behavior
--> $DIR/ub-ref.rs:24:1
|
+LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a raw memory access tried to access part of a pointer value as raw bytes
+ |
+ = 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
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-ref.rs:27:1
+ |
LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered integer pointer in non-ZST reference
|
= 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
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0080`.