mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-09 16:37:36 +00:00
make sure ByVal pointers act just like ByRef to a pointer
This commit is contained in:
parent
4a39c228df
commit
14ff6411f0
@ -21,10 +21,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||||||
|
|
||||||
Bool | Char | U8 | U16 | U32 | U64 => self.cast_int(val.bits, ty, false),
|
Bool | Char | U8 | U16 | U32 | U64 => self.cast_int(val.bits, ty, false),
|
||||||
|
|
||||||
FnPtr | Ptr => {
|
FnPtr | Ptr => self.cast_ptr(val.to_ptr(), ty),
|
||||||
let ptr = val.expect_ptr("FnPtr- or Ptr-tagged PrimVal had no relocation");
|
|
||||||
self.cast_ptr(ptr, ty)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -963,33 +963,27 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Deref => {
|
Deref => {
|
||||||
use interpreter::value::Value::*;
|
let val = self.eval_and_read_lvalue(&proj.base)?;
|
||||||
|
|
||||||
let val = match self.eval_and_read_lvalue(&proj.base)? {
|
let pointee_type = match base_ty.sty {
|
||||||
ByRef(ptr) => self.read_value(ptr, base_ty)?,
|
ty::TyRawPtr(ty::TypeAndMut{ty, ..}) |
|
||||||
v => v,
|
ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
|
||||||
|
ty::TyBox(ty) => ty,
|
||||||
|
_ => bug!("can only deref pointer types"),
|
||||||
};
|
};
|
||||||
|
|
||||||
match val {
|
trace!("deref to {} on {:?}", pointee_type, val);
|
||||||
ByValPair(ptr, vtable)
|
|
||||||
if ptr.try_as_ptr().is_some() && vtable.try_as_ptr().is_some()
|
match self.tcx.struct_tail(pointee_type).sty {
|
||||||
=> {
|
ty::TyTrait(_) => {
|
||||||
let ptr = ptr.try_as_ptr().unwrap();
|
let (ptr, vtable) = val.expect_ptr_vtable_pair(&self.memory)?;
|
||||||
let vtable = vtable.try_as_ptr().unwrap();
|
|
||||||
(ptr, LvalueExtra::Vtable(vtable))
|
(ptr, LvalueExtra::Vtable(vtable))
|
||||||
}
|
},
|
||||||
|
ty::TyStr | ty::TySlice(_) => {
|
||||||
ByValPair(ptr, n) if ptr.try_as_ptr().is_some() => {
|
let (ptr, len) = val.expect_slice(&self.memory)?;
|
||||||
let ptr = ptr.try_as_ptr().unwrap();
|
(ptr, LvalueExtra::Length(len))
|
||||||
(ptr, LvalueExtra::Length(n.expect_uint("slice length")))
|
},
|
||||||
}
|
_ => (val.read_ptr(&self.memory)?, LvalueExtra::None),
|
||||||
|
|
||||||
ByVal(ptr) if ptr.try_as_ptr().is_some() => {
|
|
||||||
let ptr = ptr.try_as_ptr().unwrap();
|
|
||||||
(ptr, LvalueExtra::None)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => bug!("can't deref non pointer types"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,15 +124,17 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||||||
|
|
||||||
"drop_in_place" => {
|
"drop_in_place" => {
|
||||||
let ty = substs.type_at(0);
|
let ty = substs.type_at(0);
|
||||||
|
trace!("drop in place on {}", ty);
|
||||||
let ptr_ty = self.tcx.mk_mut_ptr(ty);
|
let ptr_ty = self.tcx.mk_mut_ptr(ty);
|
||||||
let lvalue = match self.follow_by_ref_value(arg_vals[0], ptr_ty)? {
|
let lvalue = match self.follow_by_ref_value(arg_vals[0], ptr_ty)? {
|
||||||
Value::ByRef(_) => bug!("follow_by_ref_value returned ByRef"),
|
Value::ByRef(_) => bug!("follow_by_ref_value returned ByRef"),
|
||||||
Value::ByVal(ptr) => Lvalue::from_ptr(ptr.expect_ptr("drop_in_place first arg not a pointer")),
|
Value::ByVal(value) => Lvalue::from_ptr(value.to_ptr()),
|
||||||
Value::ByValPair(ptr, extra) => Lvalue::Ptr {
|
Value::ByValPair(ptr, extra) => Lvalue::Ptr {
|
||||||
ptr: ptr.expect_ptr("drop_in_place first arg not a pointer"),
|
ptr: ptr.to_ptr(),
|
||||||
extra: match extra.try_as_ptr() {
|
extra: match self.tcx.struct_tail(ty).sty {
|
||||||
Some(vtable) => LvalueExtra::Vtable(vtable),
|
ty::TyTrait(_) => LvalueExtra::Vtable(extra.to_ptr()),
|
||||||
None => LvalueExtra::Length(extra.expect_uint("either pointer or not, but not neither")),
|
ty::TyStr | ty::TySlice(_) => LvalueExtra::Length(extra.try_as_uint()?),
|
||||||
|
_ => bug!("invalid fat pointer type: {}", ptr_ty),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -440,7 +442,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||||||
ty::TySlice(_) | ty::TyStr => {
|
ty::TySlice(_) | ty::TyStr => {
|
||||||
let elem_ty = ty.sequence_element_type(self.tcx);
|
let elem_ty = ty.sequence_element_type(self.tcx);
|
||||||
let elem_size = self.type_size(elem_ty).expect("slice element must be sized") as u64;
|
let elem_size = self.type_size(elem_ty).expect("slice element must be sized") as u64;
|
||||||
let len = value.expect_slice_len(&self.memory)?;
|
let (_, len) = value.expect_slice(&self.memory)?;
|
||||||
let align = self.type_align(elem_ty);
|
let align = self.type_align(elem_ty);
|
||||||
Ok((len * elem_size, align as u64))
|
Ok((len * elem_size, align as u64))
|
||||||
}
|
}
|
||||||
|
@ -85,8 +85,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||||||
let func_ty = self.operand_ty(func);
|
let func_ty = self.operand_ty(func);
|
||||||
match func_ty.sty {
|
match func_ty.sty {
|
||||||
ty::TyFnPtr(bare_fn_ty) => {
|
ty::TyFnPtr(bare_fn_ty) => {
|
||||||
let fn_ptr = self.eval_operand_to_primval(func)?
|
let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr();
|
||||||
.expect_fn_ptr("TyFnPtr callee did not evaluate to FnPtr");
|
|
||||||
let (def_id, substs, fn_ty) = self.memory.get_fn(fn_ptr.alloc_id)?;
|
let (def_id, substs, fn_ty) = self.memory.get_fn(fn_ptr.alloc_id)?;
|
||||||
if fn_ty != bare_fn_ty {
|
if fn_ty != bare_fn_ty {
|
||||||
return Err(EvalError::FunctionPointerTyMismatch(fn_ty, bare_fn_ty));
|
return Err(EvalError::FunctionPointerTyMismatch(fn_ty, bare_fn_ty));
|
||||||
@ -542,14 +541,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||||||
Value::ByRef(_) => bug!("follow_by_ref_value can't result in ByRef"),
|
Value::ByRef(_) => bug!("follow_by_ref_value can't result in ByRef"),
|
||||||
Value::ByVal(ptr) => {
|
Value::ByVal(ptr) => {
|
||||||
assert!(self.type_is_sized(contents_ty));
|
assert!(self.type_is_sized(contents_ty));
|
||||||
let contents_ptr = ptr.expect_ptr("value of Box type must be a pointer");
|
let contents_ptr = ptr.to_ptr();
|
||||||
self.drop(Lvalue::from_ptr(contents_ptr), contents_ty, drop)?;
|
self.drop(Lvalue::from_ptr(contents_ptr), contents_ty, drop)?;
|
||||||
},
|
},
|
||||||
Value::ByValPair(prim_ptr, extra) => {
|
Value::ByValPair(prim_ptr, extra) => {
|
||||||
let ptr = prim_ptr.expect_ptr("value of Box type must be a pointer");
|
let ptr = prim_ptr.to_ptr();
|
||||||
let extra = match extra.try_as_ptr() {
|
let extra = match self.tcx.struct_tail(contents_ty).sty {
|
||||||
Some(vtable) => LvalueExtra::Vtable(vtable),
|
ty::TyTrait(_) => LvalueExtra::Vtable(extra.to_ptr()),
|
||||||
None => LvalueExtra::Length(extra.expect_uint("slice length")),
|
ty::TyStr | ty::TySlice(_) => LvalueExtra::Length(extra.try_as_uint()?),
|
||||||
|
_ => bug!("invalid fat pointer type: {}", ty),
|
||||||
};
|
};
|
||||||
self.drop(
|
self.drop(
|
||||||
Lvalue::Ptr {
|
Lvalue::Ptr {
|
||||||
|
@ -22,10 +22,7 @@ impl<'a, 'tcx: 'a> Value {
|
|||||||
use self::Value::*;
|
use self::Value::*;
|
||||||
match *self {
|
match *self {
|
||||||
ByRef(ptr) => mem.read_ptr(ptr),
|
ByRef(ptr) => mem.read_ptr(ptr),
|
||||||
|
ByVal(ptr) | ByValPair(ptr, _) => Ok(ptr.to_ptr()),
|
||||||
ByVal(ptr) | ByValPair(ptr, _) => {
|
|
||||||
Ok(ptr.try_as_ptr().expect("unimplemented: `read_ptr` on non-ptr primval"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,29 +32,29 @@ impl<'a, 'tcx: 'a> Value {
|
|||||||
) -> EvalResult<'tcx, (Pointer, Pointer)> {
|
) -> EvalResult<'tcx, (Pointer, Pointer)> {
|
||||||
use self::Value::*;
|
use self::Value::*;
|
||||||
match *self {
|
match *self {
|
||||||
ByRef(ptr) => {
|
ByRef(ref_ptr) => {
|
||||||
let ptr = mem.read_ptr(ptr)?;
|
let ptr = mem.read_ptr(ref_ptr)?;
|
||||||
let vtable = mem.read_ptr(ptr.offset(mem.pointer_size() as isize))?;
|
let vtable = mem.read_ptr(ref_ptr.offset(mem.pointer_size() as isize))?;
|
||||||
Ok((ptr, vtable))
|
Ok((ptr, vtable))
|
||||||
}
|
}
|
||||||
|
|
||||||
ByValPair(ptr, vtable)
|
ByValPair(ptr, vtable) => Ok((ptr.to_ptr(), vtable.to_ptr())),
|
||||||
if ptr.try_as_ptr().is_some() && vtable.try_as_ptr().is_some()
|
|
||||||
=> {
|
|
||||||
let ptr = ptr.try_as_ptr().unwrap();
|
|
||||||
let vtable = vtable.try_as_ptr().unwrap();
|
|
||||||
Ok((ptr, vtable))
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => bug!("expected ptr and vtable, got {:?}", self),
|
_ => bug!("expected ptr and vtable, got {:?}", self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn expect_slice_len(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, u64> {
|
pub(super) fn expect_slice(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, (Pointer, u64)> {
|
||||||
use self::Value::*;
|
use self::Value::*;
|
||||||
match *self {
|
match *self {
|
||||||
ByRef(ptr) => mem.read_usize(ptr.offset(mem.pointer_size() as isize)),
|
ByRef(ref_ptr) => {
|
||||||
ByValPair(_, val) if val.kind.is_int() => Ok(val.bits),
|
let ptr = mem.read_ptr(ref_ptr)?;
|
||||||
|
let len = mem.read_usize(ref_ptr.offset(mem.pointer_size() as isize))?;
|
||||||
|
Ok((ptr, len))
|
||||||
|
},
|
||||||
|
ByValPair(ptr, val) => {
|
||||||
|
Ok((ptr.to_ptr(), val.try_as_uint()?))
|
||||||
|
},
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -533,8 +533,8 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_primval(&mut self, dest: Pointer, val: PrimVal) -> EvalResult<'tcx, ()> {
|
pub fn write_primval(&mut self, dest: Pointer, val: PrimVal) -> EvalResult<'tcx, ()> {
|
||||||
if let Some(ptr) = val.try_as_ptr() {
|
if let Some(alloc_id) = val.relocation {
|
||||||
return self.write_ptr(dest, ptr);
|
return self.write_ptr(dest, Pointer::new(alloc_id, val.bits as usize));
|
||||||
}
|
}
|
||||||
|
|
||||||
use primval::PrimValKind::*;
|
use primval::PrimValKind::*;
|
||||||
|
@ -137,15 +137,19 @@ impl PrimVal {
|
|||||||
bits_to_f64(self.bits)
|
bits_to_f64(self.bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_as_ptr(self) -> Option<Pointer> {
|
pub fn to_ptr(self) -> Pointer {
|
||||||
self.relocation.map(|alloc_id| {
|
self.relocation.map(|alloc_id| {
|
||||||
Pointer::new(alloc_id, self.bits as usize)
|
Pointer::new(alloc_id, self.bits as usize)
|
||||||
})
|
}).unwrap_or_else(|| Pointer::from_int(self.bits as usize))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_as_uint<'tcx>(self) -> EvalResult<'tcx, u64> {
|
||||||
|
self.to_ptr().to_int().map(|val| val as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_uint(self, error_msg: &str) -> u64 {
|
pub fn expect_uint(self, error_msg: &str) -> u64 {
|
||||||
if let Some(ptr) = self.try_as_ptr() {
|
if let Ok(int) = self.try_as_uint() {
|
||||||
return ptr.to_int().expect("non abstract ptr") as u64
|
return int;
|
||||||
}
|
}
|
||||||
|
|
||||||
use self::PrimValKind::*;
|
use self::PrimValKind::*;
|
||||||
@ -156,8 +160,8 @@ impl PrimVal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_int(self, error_msg: &str) -> i64 {
|
pub fn expect_int(self, error_msg: &str) -> i64 {
|
||||||
if let Some(ptr) = self.try_as_ptr() {
|
if let Ok(int) = self.try_as_uint() {
|
||||||
return ptr.to_int().expect("non abstract ptr") as i64
|
return int as i64;
|
||||||
}
|
}
|
||||||
|
|
||||||
use self::PrimValKind::*;
|
use self::PrimValKind::*;
|
||||||
@ -188,15 +192,6 @@ impl PrimVal {
|
|||||||
_ => bug!("{}", error_msg),
|
_ => bug!("{}", error_msg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_ptr(self, error_msg: &str) -> Pointer {
|
|
||||||
self.try_as_ptr().expect(error_msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// FIXME(solson): Refactored into a duplicate of `expect_ptr`. Investigate removal.
|
|
||||||
pub fn expect_fn_ptr(self, error_msg: &str) -> Pointer {
|
|
||||||
self.try_as_ptr().expect(error_msg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -277,19 +272,13 @@ pub fn binary_op<'tcx>(
|
|||||||
use rustc::mir::BinOp::*;
|
use rustc::mir::BinOp::*;
|
||||||
use self::PrimValKind::*;
|
use self::PrimValKind::*;
|
||||||
|
|
||||||
match (left.try_as_ptr(), right.try_as_ptr()) {
|
|
||||||
(Some(left_ptr), Some(right_ptr)) => {
|
|
||||||
if left_ptr.alloc_id != right_ptr.alloc_id {
|
|
||||||
return Ok((unrelated_ptr_ops(bin_op)?, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the pointers are into the same allocation, fall through to the more general match
|
// If the pointers are into the same allocation, fall through to the more general match
|
||||||
// later, which will do comparisons on the `bits` fields, which are the pointer offsets
|
// later, which will do comparisons on the `bits` fields, which are the pointer offsets
|
||||||
// in this case.
|
// in this case.
|
||||||
}
|
let left_ptr = left.to_ptr();
|
||||||
|
let right_ptr = right.to_ptr();
|
||||||
(None, None) => {}
|
if left_ptr.alloc_id != right_ptr.alloc_id {
|
||||||
_ => return Err(EvalError::ReadPointerAsBytes),
|
return Ok((unrelated_ptr_ops(bin_op, left_ptr, right_ptr)?, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (l, r) = (left.bits, right.bits);
|
let (l, r) = (left.bits, right.bits);
|
||||||
@ -376,12 +365,15 @@ pub fn binary_op<'tcx>(
|
|||||||
Ok((val, false))
|
Ok((val, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp) -> EvalResult<'tcx, PrimVal> {
|
fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp, left: Pointer, right: Pointer) -> EvalResult<'tcx, PrimVal> {
|
||||||
use rustc::mir::BinOp::*;
|
use rustc::mir::BinOp::*;
|
||||||
match bin_op {
|
match bin_op {
|
||||||
Eq => Ok(PrimVal::from_bool(false)),
|
Eq => Ok(PrimVal::from_bool(false)),
|
||||||
Ne => Ok(PrimVal::from_bool(true)),
|
Ne => Ok(PrimVal::from_bool(true)),
|
||||||
Lt | Le | Gt | Ge => Err(EvalError::InvalidPointerMath),
|
Lt | Le | Gt | Ge => Err(EvalError::InvalidPointerMath),
|
||||||
|
_ if left.to_int().is_ok() ^ right.to_int().is_ok() => {
|
||||||
|
Err(EvalError::ReadPointerAsBytes)
|
||||||
|
},
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7
tests/compile-fail/cast_int_to_fn_ptr.rs
Normal file
7
tests/compile-fail/cast_int_to_fn_ptr.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fn main() {
|
||||||
|
let g = unsafe {
|
||||||
|
std::mem::transmute::<usize, fn(i32)>(42)
|
||||||
|
};
|
||||||
|
|
||||||
|
g(42) //~ ERROR tried to use an integer pointer or a dangling pointer as a function pointer
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user