fix nits and handling of extern static
This commit is contained in:
parent
322017b2bc
commit
e09e3c898c
5 changed files with 42 additions and 36 deletions
|
@ -19,7 +19,7 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use rustc::ty::{self, Instance, query::TyCtxtAt};
|
use rustc::ty::{self, Instance, ParamEnv, query::TyCtxtAt};
|
||||||
use rustc::ty::layout::{self, Align, TargetDataLayout, Size, HasDataLayout};
|
use rustc::ty::layout::{self, Align, TargetDataLayout, Size, HasDataLayout};
|
||||||
use rustc::mir::interpret::{Pointer, AllocId, Allocation, ConstValue, GlobalId,
|
use rustc::mir::interpret::{Pointer, AllocId, Allocation, ConstValue, GlobalId,
|
||||||
EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
|
EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
|
||||||
|
@ -235,7 +235,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
||||||
// Check non-NULL/Undef, extract offset
|
// Check non-NULL/Undef, extract offset
|
||||||
let (offset, alloc_align) = match ptr {
|
let (offset, alloc_align) = match ptr {
|
||||||
Scalar::Ptr(ptr) => {
|
Scalar::Ptr(ptr) => {
|
||||||
let (size, align) = self.get_size_and_align(ptr.alloc_id)?;
|
let (size, align) = self.get_size_and_align(ptr.alloc_id);
|
||||||
// check this is not NULL -- which we can ensure only if this is in-bounds
|
// check this is not NULL -- which we can ensure only if this is in-bounds
|
||||||
// of some (potentially dead) allocation.
|
// of some (potentially dead) allocation.
|
||||||
if ptr.offset > size {
|
if ptr.offset > size {
|
||||||
|
@ -359,19 +359,28 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_size_and_align(&self, id: AllocId) -> EvalResult<'tcx, (Size, Align)> {
|
pub fn get_size_and_align(&self, id: AllocId) -> (Size, Align) {
|
||||||
Ok(match self.get(id) {
|
if let Ok(alloc) = self.get(id) {
|
||||||
Ok(alloc) => (Size::from_bytes(alloc.bytes.len() as u64), alloc.align),
|
return (Size::from_bytes(alloc.bytes.len() as u64), alloc.align);
|
||||||
Err(err) => match err.kind {
|
}
|
||||||
EvalErrorKind::DanglingPointerDeref =>
|
// Could also be a fn ptr or extern static
|
||||||
// This should be in the dead allocation map
|
match self.tcx.alloc_map.lock().get(id) {
|
||||||
*self.dead_alloc_map.get(&id).expect(
|
Some(AllocType::Function(..)) => (Size::ZERO, Align::from_bytes(1, 1).unwrap()),
|
||||||
"allocation missing in dead_alloc_map"
|
Some(AllocType::Static(did)) => {
|
||||||
),
|
// The only way `get` couldnÄt have worked here is if this is an extern static
|
||||||
// E.g. a function ptr allocation
|
assert!(self.tcx.is_foreign_item(did));
|
||||||
_ => return Err(err)
|
// Use size and align of the type
|
||||||
|
let ty = self.tcx.type_of(did);
|
||||||
|
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
|
||||||
|
(layout.size, layout.align)
|
||||||
}
|
}
|
||||||
})
|
_ => {
|
||||||
|
// Must be a deallocated pointer
|
||||||
|
*self.dead_alloc_map.get(&id).expect(
|
||||||
|
"allocation missing in dead_alloc_map"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut(
|
pub fn get_mut(
|
||||||
|
|
|
@ -384,7 +384,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
||||||
} else {
|
} else {
|
||||||
// FIXME: The caller thinks this function cannot return. How do
|
// FIXME: The caller thinks this function cannot return. How do
|
||||||
// we verify that the callee agrees?
|
// we verify that the callee agrees?
|
||||||
// On the plus side, the the callee every writes to its return place,
|
// On the plus side, the the callee ever writes to its return place,
|
||||||
// that will be detected as UB (because we set that to NULL above).
|
// that will be detected as UB (because we set that to NULL above).
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -209,22 +209,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
||||||
}
|
}
|
||||||
// for safe ptrs, recursively check
|
// for safe ptrs, recursively check
|
||||||
if let ty::Ref(..) = value.layout.ty.sty {
|
if let ty::Ref(..) = value.layout.ty.sty {
|
||||||
if const_mode {
|
|
||||||
// Skip validation entirely for some external statics
|
|
||||||
if let Scalar::Ptr(ptr) = place.ptr {
|
|
||||||
let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
|
|
||||||
if let Some(AllocType::Static(did)) = alloc_kind {
|
|
||||||
// `extern static` cannot be validated as they have no body.
|
|
||||||
// They are not even properly aligned.
|
|
||||||
// Statics from other crates are already checked.
|
|
||||||
// They might be checked at a different type, but for now we want
|
|
||||||
// to avoid recursing too deeply. This is not sound!
|
|
||||||
if !did.is_local() || self.tcx.is_foreign_item(did) {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Make sure this is non-NULL and aligned
|
// Make sure this is non-NULL and aligned
|
||||||
let (size, align) = self.size_and_align_of(place.extra, place.layout)?;
|
let (size, align) = self.size_and_align_of(place.extra, place.layout)?;
|
||||||
match self.memory.check_align(place.ptr, align) {
|
match self.memory.check_align(place.ptr, align) {
|
||||||
|
@ -244,6 +228,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
||||||
if !place.layout.is_zst() {
|
if !place.layout.is_zst() {
|
||||||
let ptr = try_validation!(place.ptr.to_ptr(),
|
let ptr = try_validation!(place.ptr.to_ptr(),
|
||||||
"integer pointer in non-ZST reference", path);
|
"integer pointer in non-ZST reference", path);
|
||||||
|
if const_mode {
|
||||||
|
// Skip validation entirely for some external statics
|
||||||
|
let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
|
||||||
|
if let Some(AllocType::Static(did)) = alloc_kind {
|
||||||
|
// `extern static` cannot be validated as they have no body.
|
||||||
|
// FIXME: Statics from other crates are also skipped.
|
||||||
|
// They might be checked at a different type, but for now we
|
||||||
|
// want to avoid recursing too deeply. This is not sound!
|
||||||
|
if !did.is_local() || self.tcx.is_foreign_item(did) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
try_validation!(self.memory.check_bounds(ptr, size, false),
|
try_validation!(self.memory.check_bounds(ptr, size, false),
|
||||||
"dangling (not entirely in bounds) reference", path);
|
"dangling (not entirely in bounds) reference", path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
#![allow(safe_extern_statics, warnings)]
|
#![allow(safe_extern_statics, warnings)]
|
||||||
|
|
||||||
extern {
|
extern {
|
||||||
pub static symbol: ();
|
pub static symbol: u32;
|
||||||
}
|
}
|
||||||
static CRASH: () = symbol;
|
static CRASH: u32 = symbol;
|
||||||
//~^ ERROR could not evaluate static initializer
|
//~^ ERROR could not evaluate static initializer
|
||||||
//~| tried to read from foreign (extern) static
|
//~| tried to read from foreign (extern) static
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error[E0080]: could not evaluate static initializer
|
error[E0080]: could not evaluate static initializer
|
||||||
--> $DIR/issue-14227.rs:16:20
|
--> $DIR/issue-14227.rs:16:21
|
||||||
|
|
|
|
||||||
LL | static CRASH: () = symbol;
|
LL | static CRASH: u32 = symbol;
|
||||||
| ^^^^^^ tried to read from foreign (extern) static
|
| ^^^^^^ tried to read from foreign (extern) static
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue