-
Notifications
You must be signed in to change notification settings - Fork 360
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cleanup overflow binop code #28
Changes from 11 commits
58b4fac
3ba4f6d
6376ef4
4f48bef
e3a2bf8
00eb198
874d683
d977642
e90ee16
a1082b9
ed4af21
b9ac85d
68469be
0821a15
3e3aeab
a088f10
001ae69
c7039db
65de5dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,9 @@ use std::fmt; | |
use rustc::mir::repr as mir; | ||
use rustc::ty::BareFnTy; | ||
use memory::Pointer; | ||
use rustc_const_math::ConstMathErr; | ||
use syntax::codemap::Span; | ||
use primval::PrimVal; | ||
|
||
#[derive(Clone, Debug)] | ||
pub enum EvalError<'tcx> { | ||
|
@@ -24,6 +27,10 @@ pub enum EvalError<'tcx> { | |
Unimplemented(String), | ||
DerefFunctionPointer, | ||
ExecuteMemory, | ||
ArrayIndexOutOfBounds(Span, u64, u64), | ||
Math(Span, ConstMathErr), | ||
InvalidBitShiftRhs(PrimVal), | ||
Overflow(PrimVal, PrimVal, mir::BinOp, PrimVal), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this get ignored outside of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the current tests are only run in debug mode, the overflow checks prevent the overflow error from ever triggering. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think I want to avoid using |
||
} | ||
|
||
pub type EvalResult<'tcx, T> = Result<T, EvalError<'tcx>>; | ||
|
@@ -58,6 +65,14 @@ impl<'tcx> Error for EvalError<'tcx> { | |
"tried to dereference a function pointer", | ||
EvalError::ExecuteMemory => | ||
"tried to treat a memory pointer as a function pointer", | ||
EvalError::ArrayIndexOutOfBounds(..) => | ||
"array index out of bounds", | ||
EvalError::Math(..) => | ||
"mathematical operation failed", | ||
EvalError::InvalidBitShiftRhs(..) => | ||
"bit shift rhs negative or not an int", | ||
EvalError::Overflow(..) => | ||
"mathematical operation overflowed", | ||
} | ||
} | ||
|
||
|
@@ -73,6 +88,12 @@ impl<'tcx> fmt::Display for EvalError<'tcx> { | |
}, | ||
EvalError::FunctionPointerTyMismatch(expected, got) => | ||
write!(f, "tried to call a function of type {:?} through a function pointer of type {:?}", expected, got), | ||
EvalError::ArrayIndexOutOfBounds(span, len, index) => | ||
write!(f, "array index {} out of bounds {} at {:?}", index, len, span), | ||
EvalError::Math(span, ref err) => | ||
write!(f, "mathematical operation at {:?} failed with {:?}", span, err), | ||
EvalError::Overflow(l, r, op, val) => | ||
write!(f, "mathematical operation overflowed: {:?} {} {:?} => {:?}", l, op.to_hir_binop().as_str(), r, val), | ||
_ => write!(f, "{}", self.description()), | ||
} | ||
} | ||
|
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,6 @@ | |
btree_range, | ||
collections, | ||
collections_bound, | ||
core_intrinsics, | ||
filling_drop, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yay. I hated this hack and the unsafe code I added with it. |
||
question_mark, | ||
rustc_private, | ||
|
@@ -14,6 +13,7 @@ | |
extern crate rustc_data_structures; | ||
extern crate rustc_mir; | ||
extern crate rustc_trans; | ||
extern crate rustc_const_math; | ||
extern crate syntax; | ||
#[macro_use] extern crate log; | ||
extern crate log_settings; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,7 +42,7 @@ impl Pointer { | |
} | ||
} | ||
|
||
#[derive(Debug, Copy, Clone)] | ||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] | ||
pub struct FunctionDefinition<'tcx> { | ||
pub def_id: DefId, | ||
pub substs: &'tcx Substs<'tcx>, | ||
|
@@ -59,6 +59,8 @@ pub struct Memory<'tcx> { | |
/// Function "allocations". They exist solely so pointers have something to point to, and | ||
/// we can figure out what they point to. | ||
functions: HashMap<AllocId, FunctionDefinition<'tcx>>, | ||
/// Inverse map of `functions` so we don't allocate a new pointer every time we need one | ||
function_definitions: HashMap<FunctionDefinition<'tcx>, AllocId>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer a name like |
||
next_id: AllocId, | ||
pub pointer_size: usize, | ||
} | ||
|
@@ -69,22 +71,29 @@ impl<'tcx> Memory<'tcx> { | |
Memory { | ||
alloc_map: HashMap::new(), | ||
functions: HashMap::new(), | ||
function_definitions: HashMap::new(), | ||
next_id: AllocId(0), | ||
pointer_size: pointer_size, | ||
} | ||
} | ||
|
||
// FIXME: never create two pointers to the same def_id + substs combination | ||
// maybe re-use the statics cache of the EvalContext? | ||
pub fn create_fn_ptr(&mut self, def_id: DefId, substs: &'tcx Substs<'tcx>, fn_ty: &'tcx BareFnTy<'tcx>) -> Pointer { | ||
let id = self.next_id; | ||
debug!("creating fn ptr: {}", id); | ||
self.next_id.0 += 1; | ||
self.functions.insert(id, FunctionDefinition { | ||
let def = FunctionDefinition { | ||
def_id: def_id, | ||
substs: substs, | ||
fn_ty: fn_ty, | ||
}); | ||
}; | ||
if let Some(&alloc_id) = self.function_definitions.get(&def) { | ||
return Pointer { | ||
alloc_id: alloc_id, | ||
offset: 0, | ||
}; | ||
} | ||
let id = self.next_id; | ||
debug!("creating fn ptr: {}", id); | ||
self.next_id.0 += 1; | ||
self.functions.insert(id, def); | ||
self.function_definitions.insert(def, id); | ||
Pointer { | ||
alloc_id: id, | ||
offset: 0, | ||
|
@@ -361,6 +370,7 @@ impl<'tcx> Memory<'tcx> { | |
PrimVal::U32(n) => self.write_uint(ptr, n as u64, 4), | ||
PrimVal::U64(n) => self.write_uint(ptr, n as u64, 8), | ||
PrimVal::IntegerPtr(n) => self.write_uint(ptr, n as u64, pointer_size), | ||
PrimVal::FnPtr(_p) | | ||
PrimVal::AbstractPtr(_p) => unimplemented!(), | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// just making sure that fn -> unsafe fn casts are handled by rustc so miri doesn't have to | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm confused by these two tests. Whether There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's fine, I just wanted to make sure it's not possible to cause a mir safe to unsafe cast. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I realized just after I posted that, this would matter for implementing casting. I guess that's fine. |
||
fn main() { | ||
fn f() {} | ||
|
||
let g = f as fn() as unsafe fn(i32); //~ERROR: non-scalar cast: `fn()` as `unsafe fn(i32)` | ||
|
||
unsafe { | ||
g(42); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// just making sure that fn -> unsafe fn casts are handled by rustc so miri doesn't have to | ||
fn main() { | ||
fn f() {} | ||
|
||
let g = f as fn() as fn(i32) as unsafe fn(i32); //~ERROR: non-scalar cast: `fn()` as `fn(i32)` | ||
|
||
unsafe { | ||
g(42); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
//error-pattern: no mir for `std | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My
😃 I need to prepare that PR for enabling this in rustc optionally soon. |
||
|
||
fn main() { | ||
let x = std::env::args(); | ||
assert_eq!(x.count(), 1); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
fn main() { | ||
fn f() {} | ||
|
||
let g = f as fn() as unsafe fn(); | ||
unsafe { | ||
g(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not actually a thing, the semantics of shifting in Rust is that the RHS gets masked with
BITS - 1
(assuming bit widths are always a power of 2) and interpreted as unsigned.EDIT: corrected description of the mask.
(misplaced on another PR)