Skip to content

Commit 012c2f1

Browse files
committed
abort, panic and print
1 parent 197c492 commit 012c2f1

File tree

4 files changed

+138
-9
lines changed

4 files changed

+138
-9
lines changed

src/error.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ pub enum EvalError<'tcx> {
5252
ReallocatedFrozenMemory,
5353
DeallocatedFrozenMemory,
5454
Layout(layout::LayoutError<'tcx>),
55+
Abort,
56+
Panic {
57+
file: String,
58+
line: u32,
59+
},
5560
}
5661

5762
pub type EvalResult<'tcx, T> = Result<T, EvalError<'tcx>>;
@@ -122,6 +127,10 @@ impl<'tcx> Error for EvalError<'tcx> {
122127
"rustc layout computation failed",
123128
EvalError::UnterminatedCString(_) =>
124129
"attempted to get length of a null terminated string, but no null found before end of allocation",
130+
EvalError::Abort =>
131+
"`abort` intrinsic reached",
132+
EvalError::Panic { .. } =>
133+
"panic!",
125134
}
126135
}
127136

@@ -154,6 +163,8 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
154163
write!(f, "expected primitive type, got {}", ty),
155164
EvalError::Layout(ref err) =>
156165
write!(f, "rustc layout computation failed: {:?}", err),
166+
EvalError::Panic { ref file, line } =>
167+
write!(f, "panicked at {}:{}", file, line),
157168
_ => write!(f, "{}", self.description()),
158169
}
159170
}

src/eval_context.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ pub struct EvalContext<'a, 'tcx: 'a> {
4343
/// This prevents infinite loops and huge computations from freezing up const eval.
4444
/// Remove once halting problem is solved.
4545
pub(super) steps_remaining: u64,
46+
47+
// FIXME: also add destructors
48+
pub(super) pthread: HashMap<i32, Pointer>,
49+
pub(super) next_pthread_key: i32,
4650
}
4751

4852
/// A stack frame.
@@ -137,6 +141,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
137141
stack: Vec::new(),
138142
stack_limit: limits.stack_limit,
139143
steps_remaining: limits.step_limit,
144+
pthread: HashMap::new(),
145+
next_pthread_key: 0,
140146
}
141147
}
142148

src/step.rs

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use error::{EvalResult, EvalError};
1414
use eval_context::{EvalContext, StackPopCleanup, MirRef};
1515
use lvalue::{Global, GlobalId, Lvalue};
1616
use syntax::codemap::Span;
17+
use syntax::attr;
18+
use value::{Value, PrimVal};
1719

1820
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
1921
pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx, ()> {
@@ -124,6 +126,13 @@ struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b> {
124126
}
125127

126128
impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
129+
fn weak_linkage(&self, def_id: DefId) -> bool {
130+
let attributes = self.ecx.tcx.get_attrs(def_id);
131+
let attr = attr::first_attr_value_str_by_name(&attributes, "linkage");
132+
trace!("linkage: {:?}", attr);
133+
attr.map_or(false, |name| &*name.as_str() == "weak" || &*name.as_str() == "extern_weak")
134+
}
135+
127136
fn global_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span, immutable: bool) {
128137
let cid = GlobalId {
129138
def_id: def_id,
@@ -133,15 +142,34 @@ impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
133142
if self.ecx.globals.contains_key(&cid) {
134143
return;
135144
}
145+
let ty = self.ecx.tcx.item_type(def_id);
146+
let immutable = immutable && !ty.type_contents(self.ecx.tcx).interior_unsafe();
136147
self.try(|this| {
137-
let mir = this.ecx.load_mir(def_id)?;
138-
this.ecx.globals.insert(cid, Global::uninitialized(mir.return_ty));
139-
let cleanup = if immutable && !mir.return_ty.type_contents(this.ecx.tcx).interior_unsafe() {
140-
StackPopCleanup::Freeze
148+
if this.weak_linkage(def_id) {
149+
let data = match this.ecx.type_size(ty)?.expect("statics/consts can't be unsized") {
150+
0...8 => Value::ByVal(PrimVal::new(0)),
151+
n => {
152+
let ptr = this.ecx.memory.allocate(n, 1)?;
153+
this.ecx.memory.write_repeat(ptr, 0, n)?;
154+
Value::ByRef(ptr)
155+
},
156+
};
157+
this.ecx.globals.insert(cid, Global {
158+
data: Some(data),
159+
mutable: !immutable,
160+
ty: ty,
161+
});
162+
Ok(())
141163
} else {
142-
StackPopCleanup::None
143-
};
144-
this.ecx.push_stack_frame(def_id, span, mir, substs, Lvalue::Global(cid), cleanup, Vec::new())
164+
this.ecx.globals.insert(cid, Global::uninitialized(ty));
165+
let cleanup = if immutable {
166+
StackPopCleanup::Freeze
167+
} else {
168+
StackPopCleanup::None
169+
};
170+
let mir = this.ecx.load_mir(def_id)?;
171+
this.ecx.push_stack_frame(def_id, span, mir, substs, Lvalue::Global(cid), cleanup, Vec::new())
172+
}
145173
});
146174
}
147175
fn try<F: FnOnce(&mut Self) -> EvalResult<'tcx, ()>>(&mut self, f: F) {

src/terminator/mod.rs

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use memory::Pointer;
1515
use value::PrimVal;
1616
use value::Value;
1717

18+
use std::str::from_utf8;
19+
1820
mod intrinsic;
1921

2022
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
@@ -200,14 +202,37 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
200202
Abi::RustIntrinsic => {
201203
let ty = fn_ty.sig.0.output();
202204
let layout = self.type_layout(ty)?;
203-
let (ret, target) = destination.unwrap();
205+
let (ret, target) = match destination {
206+
Some(dest) => dest,
207+
None => {
208+
assert_eq!(&self.tcx.item_name(def_id).as_str()[..], "abort");
209+
return Err(EvalError::Abort);
210+
}
211+
};
204212
self.call_intrinsic(def_id, substs, arg_operands, ret, ty, layout, target)?;
205213
Ok(())
206214
}
207215

208216
Abi::C => {
209217
let ty = fn_ty.sig.0.output();
210-
let (ret, target) = destination.unwrap();
218+
let (ret, target) = match destination {
219+
Some(dest) => dest,
220+
None => {
221+
assert_eq!(&self.tcx.item_name(def_id).as_str()[..], "panic_impl");
222+
let args_res: EvalResult<Vec<Value>> = arg_operands.iter()
223+
.map(|arg| self.eval_operand(arg)?.ok_or(EvalError::ReadUndefBytes))
224+
.collect();
225+
let args = args_res?;
226+
// FIXME: process panic text
227+
let file_slice = args[1].expect_slice(&self.memory)?;
228+
let file = from_utf8(self.memory.read_bytes(file_slice.0, file_slice.1)?)
229+
.expect("panic message not utf8")
230+
.to_owned();
231+
let u32 = self.tcx.types.u32;
232+
let line = self.value_to_primval(args[2], u32)?.to_u64() as u32;
233+
return Err(EvalError::Panic { file: file, line: line });
234+
}
235+
};
211236
self.call_c_abi(def_id, arg_operands, ret, ty)?;
212237
self.goto_block(target);
213238
Ok(())
@@ -358,6 +383,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
358383
let args = args_res?;
359384

360385
let usize = self.tcx.types.usize;
386+
let i32 = self.tcx.types.i32;
361387

362388
match &link_name[..] {
363389
"__rust_allocate" => {
@@ -403,6 +429,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
403429
self.write_primval(dest, PrimVal::new(result as u64), dest_ty)?;
404430
}
405431

432+
"memrchr" => {
433+
let ptr = args[0].read_ptr(&self.memory)?;
434+
let val = self.value_to_primval(args[1], usize)?.to_u64() as u8;
435+
let num = self.value_to_primval(args[2], usize)?.to_u64();
436+
if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position(|&c| c == val) {
437+
let new_ptr = ptr.offset(num - idx as u64 - 1);
438+
self.write_value(Value::ByVal(PrimVal::from_ptr(new_ptr)), dest, dest_ty)?;
439+
} else {
440+
self.write_value(Value::ByVal(PrimVal::new(0)), dest, dest_ty)?;
441+
}
442+
}
443+
406444
"memchr" => {
407445
let ptr = args[0].read_ptr(&self.memory)?;
408446
let val = self.value_to_primval(args[1], usize)?.to_u64() as u8;
@@ -415,6 +453,27 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
415453
}
416454
}
417455

456+
"write" => {
457+
// int filedes
458+
let filedes = self.value_to_primval(args[0], usize)?.to_u64();
459+
// const void* buffer
460+
let buffer = args[1].read_ptr(&self.memory)?;
461+
// size_t size
462+
let size = self.value_to_primval(args[0], usize)?.to_u64();
463+
464+
{
465+
let data = self.memory.read_bytes(buffer, size)?;
466+
info!("write to `{:x}`: {:?}", filedes, data);
467+
if filedes == 1 {
468+
for &d in data {
469+
print!("{}", d as char);
470+
}
471+
}
472+
}
473+
474+
self.write_primval(dest, PrimVal::new(size as u64), dest_ty)?;
475+
}
476+
418477
"getenv" => {
419478
{
420479
let name_ptr = args[0].read_ptr(&self.memory)?;
@@ -423,6 +482,31 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
423482
}
424483
self.write_value(Value::ByVal(PrimVal::new(0)), dest, dest_ty)?;
425484
}
485+
"pthread_key_create" => {
486+
// pthread_key_t* key
487+
let key = args[0].read_ptr(&self.memory)?;
488+
let pthread_key_t = self.tcx.types.i32;
489+
self.next_pthread_key += 1;
490+
let new_key = self.next_pthread_key;
491+
self.write_primval(Lvalue::from_ptr(key), PrimVal::new(new_key as u64), pthread_key_t)?;
492+
self.write_primval(dest, PrimVal::new(0), dest_ty)?;
493+
}
494+
495+
"pthread_setspecific" => {
496+
let key = self.value_to_primval(args[0], i32)?.to_u64();
497+
let val = args[1].read_ptr(&self.memory)?;
498+
assert_eq!(key as i32 as u64, key);
499+
self.pthread.insert(key as i32, val);
500+
// FIXME: only keys that were created should exist
501+
self.write_primval(dest, PrimVal::new(0), dest_ty)?;
502+
}
503+
504+
"pthread_getspecific" => {
505+
let key = self.value_to_primval(args[0], i32)?.to_u64();
506+
assert_eq!(key as i32 as u64, key);
507+
let val = self.pthread.get(&(key as i32)).map(|&p| p).unwrap_or(Pointer::from_int(0));
508+
self.write_primval(dest, PrimVal::from_ptr(val), dest_ty)?;
509+
}
426510

427511
// unix panic code inside libstd will read the return value of this function
428512
"pthread_rwlock_rdlock" => {

0 commit comments

Comments
 (0)