]> git.proxmox.com Git - rustc.git/blame - src/tools/miri/miri/lib.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / tools / miri / miri / lib.rs
CommitLineData
ea8adc8c
XL
1#![feature(
2 i128_type,
3 rustc_private,
4)]
5
6// From rustc.
7#[macro_use]
8extern crate log;
9#[macro_use]
10extern crate rustc;
11extern crate syntax;
12
13use rustc::ty::{self, TyCtxt};
14use rustc::ty::layout::Layout;
15use rustc::hir::def_id::DefId;
16use rustc::mir;
17
18use syntax::ast::Mutability;
19use syntax::codemap::Span;
20
21use std::collections::{HashMap, BTreeMap};
22
23#[macro_use]
24extern crate rustc_miri;
25pub use rustc_miri::interpret::*;
26
27mod fn_call;
28mod operator;
29mod intrinsic;
30mod helpers;
31mod memory;
32mod tls;
33
34use fn_call::EvalContextExt as MissingFnsEvalContextExt;
35use operator::EvalContextExt as OperatorEvalContextExt;
36use intrinsic::EvalContextExt as IntrinsicEvalContextExt;
37use tls::EvalContextExt as TlsEvalContextExt;
38
39pub fn eval_main<'a, 'tcx: 'a>(
40 tcx: TyCtxt<'a, 'tcx, 'tcx>,
41 main_id: DefId,
42 start_wrapper: Option<DefId>,
43 limits: ResourceLimits,
44) {
45 fn run_main<'a, 'tcx: 'a>(
46 ecx: &mut rustc_miri::interpret::EvalContext<'a, 'tcx, Evaluator>,
47 main_id: DefId,
48 start_wrapper: Option<DefId>,
49 ) -> EvalResult<'tcx> {
50 let main_instance = ty::Instance::mono(ecx.tcx, main_id);
51 let main_mir = ecx.load_mir(main_instance.def)?;
52 let mut cleanup_ptr = None; // Pointer to be deallocated when we are done
53
54 if !main_mir.return_ty.is_nil() || main_mir.arg_count != 0 {
55 return err!(Unimplemented(
56 "miri does not support main functions without `fn()` type signatures"
57 .to_owned(),
58 ));
59 }
60
61 if let Some(start_id) = start_wrapper {
62 let start_instance = ty::Instance::mono(ecx.tcx, start_id);
63 let start_mir = ecx.load_mir(start_instance.def)?;
64
65 if start_mir.arg_count != 3 {
66 return err!(AbiViolation(format!(
67 "'start' lang item should have three arguments, but has {}",
68 start_mir.arg_count
69 )));
70 }
71
72 // Return value
73 let size = ecx.tcx.data_layout.pointer_size.bytes();
74 let align = ecx.tcx.data_layout.pointer_align.abi();
75 let ret_ptr = ecx.memory_mut().allocate(size, align, MemoryKind::Stack)?;
76 cleanup_ptr = Some(ret_ptr);
77
78 // Push our stack frame
79 ecx.push_stack_frame(
80 start_instance,
81 start_mir.span,
82 start_mir,
83 Lvalue::from_ptr(ret_ptr),
84 StackPopCleanup::None,
85 )?;
86
87 let mut args = ecx.frame().mir.args_iter();
88
89 // First argument: pointer to main()
90 let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance);
91 let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
92 let main_ty = main_instance.def.def_ty(ecx.tcx);
93 let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx));
94 ecx.write_value(
95 ValTy {
96 value: Value::ByVal(PrimVal::Ptr(main_ptr)),
97 ty: main_ptr_ty,
98 },
99 dest,
100 )?;
101
102 // Second argument (argc): 1
103 let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
104 let ty = ecx.tcx.types.isize;
105 ecx.write_primval(dest, PrimVal::Bytes(1), ty)?;
106
107 // FIXME: extract main source file path
108 // Third argument (argv): &[b"foo"]
109 let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
110 let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8));
111 let foo = ecx.memory.allocate_cached(b"foo\0")?;
112 let ptr_size = ecx.memory.pointer_size();
113 let foo_ptr = ecx.memory.allocate(ptr_size * 1, ptr_size, MemoryKind::UninitializedStatic)?;
114 ecx.memory.write_primval(foo_ptr.into(), PrimVal::Ptr(foo.into()), ptr_size, false)?;
115 ecx.memory.mark_static_initalized(foo_ptr.alloc_id, Mutability::Immutable)?;
116 ecx.write_ptr(dest, foo_ptr.into(), ty)?;
117 } else {
118 ecx.push_stack_frame(
119 main_instance,
120 main_mir.span,
121 main_mir,
122 Lvalue::undef(),
123 StackPopCleanup::None,
124 )?;
125 }
126
127 while ecx.step()? {}
128 ecx.run_tls_dtors()?;
129 if let Some(cleanup_ptr) = cleanup_ptr {
130 ecx.memory_mut().deallocate(
131 cleanup_ptr,
132 None,
133 MemoryKind::Stack,
134 )?;
135 }
136 Ok(())
137 }
138
139 let mut ecx = EvalContext::new(tcx, limits, Default::default(), Default::default());
140 match run_main(&mut ecx, main_id, start_wrapper) {
141 Ok(()) => {
142 let leaks = ecx.memory().leak_report();
143 if leaks != 0 {
144 tcx.sess.err("the evaluated program leaked memory");
145 }
146 }
147 Err(mut e) => {
148 ecx.report(&mut e);
149 }
150 }
151}
152
153pub struct Evaluator;
154#[derive(Default)]
155pub struct EvaluatorData {
156 /// Environment variables set by `setenv`
157 /// Miri does not expose env vars from the host to the emulated program
158 pub(crate) env_vars: HashMap<Vec<u8>, MemoryPointer>,
159}
160
161pub type TlsKey = usize;
162
163#[derive(Copy, Clone, Debug)]
164pub struct TlsEntry<'tcx> {
165 data: Pointer, // Will eventually become a map from thread IDs to `Pointer`s, if we ever support more than one thread.
166 dtor: Option<ty::Instance<'tcx>>,
167}
168
169#[derive(Default)]
170pub struct MemoryData<'tcx> {
171 /// The Key to use for the next thread-local allocation.
172 next_thread_local: TlsKey,
173
174 /// pthreads-style thread-local storage.
175 thread_local: BTreeMap<TlsKey, TlsEntry<'tcx>>,
176}
177
178impl<'tcx> Machine<'tcx> for Evaluator {
179 type Data = EvaluatorData;
180 type MemoryData = MemoryData<'tcx>;
181 type MemoryKinds = memory::MemoryKind;
182
183 /// Returns Ok() when the function was handled, fail otherwise
184 fn eval_fn_call<'a>(
185 ecx: &mut EvalContext<'a, 'tcx, Self>,
186 instance: ty::Instance<'tcx>,
187 destination: Option<(Lvalue, mir::BasicBlock)>,
188 args: &[ValTy<'tcx>],
189 span: Span,
190 sig: ty::FnSig<'tcx>,
191 ) -> EvalResult<'tcx, bool> {
192 ecx.eval_fn_call(instance, destination, args, span, sig)
193 }
194
195 fn call_intrinsic<'a>(
196 ecx: &mut rustc_miri::interpret::EvalContext<'a, 'tcx, Self>,
197 instance: ty::Instance<'tcx>,
198 args: &[ValTy<'tcx>],
199 dest: Lvalue,
200 dest_ty: ty::Ty<'tcx>,
201 dest_layout: &'tcx Layout,
202 target: mir::BasicBlock,
203 ) -> EvalResult<'tcx> {
204 ecx.call_intrinsic(instance, args, dest, dest_ty, dest_layout, target)
205 }
206
207 fn try_ptr_op<'a>(
208 ecx: &rustc_miri::interpret::EvalContext<'a, 'tcx, Self>,
209 bin_op: mir::BinOp,
210 left: PrimVal,
211 left_ty: ty::Ty<'tcx>,
212 right: PrimVal,
213 right_ty: ty::Ty<'tcx>,
214 ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> {
215 ecx.ptr_op(bin_op, left, left_ty, right, right_ty)
216 }
217
218 fn mark_static_initialized(m: memory::MemoryKind) -> EvalResult<'tcx> {
219 use memory::MemoryKind::*;
220 match m {
221 // FIXME: This could be allowed, but not for env vars set during miri execution
222 Env => err!(Unimplemented("statics can't refer to env vars".to_owned())),
223 _ => Ok(()),
224 }
225 }
226
227 fn box_alloc<'a>(
228 ecx: &mut EvalContext<'a, 'tcx, Self>,
229 ty: ty::Ty<'tcx>,
230 ) -> EvalResult<'tcx, PrimVal> {
231 // FIXME: call the `exchange_malloc` lang item if available
232 let size = ecx.type_size(ty)?.expect("box only works with sized types");
233 let align = ecx.type_align(ty)?;
234 if size == 0 {
235 Ok(PrimVal::Bytes(align.into()))
236 } else {
237 ecx.memory
238 .allocate(size, align, MemoryKind::Machine(memory::MemoryKind::Rust))
239 .map(PrimVal::Ptr)
240 }
241 }
242
243 fn global_item_with_linkage<'a>(
244 ecx: &mut EvalContext<'a, 'tcx, Self>,
245 instance: ty::Instance<'tcx>,
246 mutability: Mutability,
247 ) -> EvalResult<'tcx> {
248 // FIXME: check that it's `#[linkage = "extern_weak"]`
249 trace!("Initializing an extern global with NULL");
250 let ptr_size = ecx.memory.pointer_size();
251 let ptr = ecx.memory.allocate(
252 ptr_size,
253 ptr_size,
254 MemoryKind::UninitializedStatic,
255 )?;
256 ecx.memory.write_ptr_sized_unsigned(ptr, PrimVal::Bytes(0))?;
257 ecx.memory.mark_static_initalized(ptr.alloc_id, mutability)?;
258 ecx.globals.insert(
259 GlobalId {
260 instance,
261 promoted: None,
262 },
263 PtrAndAlign {
264 ptr: ptr.into(),
265 aligned: true,
266 },
267 );
268 Ok(())
269 }
270}