Skip to content

Commit be8a858

Browse files
author
Vytautas Astrauskas
committed
Implement basic support for concurrency (Linux only).
1 parent d1e06b4 commit be8a858

File tree

23 files changed

+602
-104
lines changed

23 files changed

+602
-104
lines changed

src/diagnostics.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub enum NonHaltingDiagnostic {
4343

4444
/// Emit a custom diagnostic without going through the miri-engine machinery
4545
pub fn report_error<'tcx, 'mir>(
46-
ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
46+
ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
4747
mut e: InterpErrorInfo<'tcx>,
4848
) -> Option<i64> {
4949
use InterpError::*;
@@ -108,7 +108,7 @@ pub fn report_error<'tcx, 'mir>(
108108
/// Report an error or note (depending on the `error` argument) at the current frame's current statement.
109109
/// Also emits a full stacktrace of the interpreter stack.
110110
fn report_msg<'tcx, 'mir>(
111-
ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
111+
ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
112112
title: &str,
113113
span_msg: String,
114114
helps: &[String],
@@ -167,7 +167,7 @@ pub fn register_diagnostic(e: NonHaltingDiagnostic) {
167167
DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e));
168168
}
169169

170-
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
170+
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
171171
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
172172
/// Emit all diagnostics that were registed with `register_diagnostics`
173173
fn process_diagnostics(&self) {

src/eval.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
5959
tcx: TyCtxt<'tcx>,
6060
main_id: DefId,
6161
config: MiriConfig,
62-
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> {
62+
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> {
6363
let mut ecx = InterpCx::new(
6464
tcx.at(rustc_span::source_map::DUMMY_SP),
6565
ty::ParamEnv::reveal_all(),
@@ -198,7 +198,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) ->
198198
// Perform the main execution.
199199
let res: InterpResult<'_, i64> = (|| {
200200
// Main loop.
201-
while ecx.step()? {
201+
while ecx.schedule()? {
202+
assert!(ecx.step()?);
202203
ecx.process_diagnostics();
203204
}
204205
// Read the return code pointer *before* we run TLS destructors, to assert

src/helpers.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rand::RngCore;
1616

1717
use crate::*;
1818

19-
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
19+
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
2020

2121
/// Gets an instance for a path.
2222
fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option<DefId> {
@@ -261,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
261261
unsafe_cell_action: F,
262262
}
263263

264-
impl<'ecx, 'mir, 'tcx, F> ValueVisitor<'mir, 'tcx, Evaluator<'tcx>>
264+
impl<'ecx, 'mir, 'tcx: 'mir, F> ValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>>
265265
for UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
266266
where
267267
F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>,

src/intptrcast.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl Default for GlobalState {
4242
impl<'mir, 'tcx> GlobalState {
4343
pub fn int_to_ptr(
4444
int: u64,
45-
memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>,
45+
memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
4646
) -> InterpResult<'tcx, Pointer<Tag>> {
4747
let global_state = memory.extra.intptrcast.borrow();
4848
let pos = global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr);
@@ -74,7 +74,7 @@ impl<'mir, 'tcx> GlobalState {
7474

7575
pub fn ptr_to_int(
7676
ptr: Pointer<Tag>,
77-
memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>,
77+
memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
7878
) -> InterpResult<'tcx, u64> {
7979
let mut global_state = memory.extra.intptrcast.borrow_mut();
8080
let global_state = &mut *global_state;

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ extern crate rustc_ast;
1212
#[macro_use] extern crate rustc_middle;
1313
extern crate rustc_data_structures;
1414
extern crate rustc_hir;
15+
extern crate rustc_index;
1516
extern crate rustc_mir;
1617
extern crate rustc_span;
1718
extern crate rustc_target;
@@ -26,6 +27,7 @@ mod operator;
2627
mod range_map;
2728
mod shims;
2829
mod stacked_borrows;
30+
mod threads;
2931

3032
// Make all those symbols available in the same place as our own.
3133
pub use rustc_mir::interpret::*;
@@ -59,6 +61,7 @@ pub use crate::range_map::RangeMap;
5961
pub use crate::stacked_borrows::{
6062
EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag,
6163
};
64+
pub use crate::threads::EvalContextExt as ThreadsEvalContextExt;
6265

6366
/// Insert rustc arguments at the beginning of the argument list that Miri wants to be
6467
/// set per default, for maximal validation power.

src/machine.rs

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ use rustc_span::{source_map::Span, symbol::{sym, Symbol}};
2222

2323
use crate::*;
2424

25+
pub use crate::threads::{ThreadId, ThreadSet, ThreadLocalStorage};
26+
2527
// Some global facts about the emulated machine.
2628
pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture
2729
pub const STACK_ADDR: u64 = 32 * PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations
@@ -78,6 +80,7 @@ pub struct AllocExtra {
7880
pub struct MemoryExtra {
7981
pub stacked_borrows: Option<stacked_borrows::MemoryExtra>,
8082
pub intptrcast: intptrcast::MemoryExtra,
83+
pub tls: ThreadLocalStorage,
8184

8285
/// Mapping extern static names to their canonical allocation.
8386
extern_statics: FxHashMap<Symbol, AllocId>,
@@ -104,6 +107,7 @@ impl MemoryExtra {
104107
extern_statics: FxHashMap::default(),
105108
rng: RefCell::new(rng),
106109
tracked_alloc_id,
110+
tls: Default::default(),
107111
}
108112
}
109113

@@ -151,7 +155,7 @@ impl MemoryExtra {
151155
}
152156

153157
/// The machine itself.
154-
pub struct Evaluator<'tcx> {
158+
pub struct Evaluator<'mir, 'tcx> {
155159
/// Environment variables set by `setenv`.
156160
/// Miri does not expose env vars from the host to the emulated program.
157161
pub(crate) env_vars: EnvVars<'tcx>,
@@ -186,9 +190,11 @@ pub struct Evaluator<'tcx> {
186190

187191
/// The "time anchor" for this machine's monotone clock (for `Instant` simulation).
188192
pub(crate) time_anchor: Instant,
193+
194+
pub(crate) threads: ThreadSet<'mir, 'tcx>,
189195
}
190196

191-
impl<'tcx> Evaluator<'tcx> {
197+
impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
192198
pub(crate) fn new(communicate: bool, validate: bool) -> Self {
193199
Evaluator {
194200
// `env_vars` could be initialized properly here if `Memory` were available before
@@ -205,12 +211,13 @@ impl<'tcx> Evaluator<'tcx> {
205211
dir_handler: Default::default(),
206212
panic_payload: None,
207213
time_anchor: Instant::now(),
214+
threads: Default::default(),
208215
}
209216
}
210217
}
211218

212219
/// A rustc InterpCx for Miri.
213-
pub type MiriEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, Evaluator<'tcx>>;
220+
pub type MiriEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>;
214221

215222
/// A little trait that's useful to be inherited by extension traits.
216223
pub trait MiriEvalContextExt<'mir, 'tcx> {
@@ -229,7 +236,7 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx>
229236
}
230237

231238
/// Machine hook implementations.
232-
impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
239+
impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
233240
type MemoryKind = MiriMemoryKind;
234241

235242
type FrameExtra = FrameData<'tcx>;
@@ -245,6 +252,19 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
245252

246253
const CHECK_ALIGN: bool = true;
247254

255+
#[inline(always)]
256+
fn stack<'a>(
257+
ecx: &'a InterpCx<'mir, 'tcx, Self>
258+
) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] {
259+
ecx.active_thread_stack()
260+
}
261+
262+
fn stack_mut<'a>(
263+
ecx: &'a mut InterpCx<'mir, 'tcx, Self>
264+
) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>> {
265+
ecx.active_thread_stack_mut()
266+
}
267+
248268
#[inline(always)]
249269
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
250270
ecx.machine.validate
@@ -339,29 +359,39 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
339359

340360
fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId {
341361
let tcx = mem.tcx;
342-
// Figure out if this is an extern static, and if yes, which one.
343-
let def_id = match tcx.alloc_map.lock().get(id) {
344-
Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => def_id,
362+
let alloc = tcx.alloc_map.lock().get(id);
363+
match alloc {
364+
Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => {
365+
// Figure out if this is an extern static, and if yes, which one.
366+
let attrs = tcx.get_attrs(def_id);
367+
let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) {
368+
Some(name) => name,
369+
None => tcx.item_name(def_id),
370+
};
371+
// Check if we know this one.
372+
if let Some(canonical_id) = mem.extra.extern_statics.get(&link_name) {
373+
trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id);
374+
*canonical_id
375+
} else {
376+
// Return original id; `Memory::get_static_alloc` will throw an error.
377+
id
378+
}
379+
},
380+
Some(GlobalAlloc::Static(def_id)) if tcx.has_attr(def_id, sym::thread_local) => {
381+
// We have a thread local, so we need to get a unique allocation id for it.
382+
mem.extra.tls.get_or_register_allocation(*tcx, id)
383+
},
345384
_ => {
346385
// No need to canonicalize anything.
347-
return id;
386+
id
348387
}
349-
};
350-
let attrs = tcx.get_attrs(def_id);
351-
let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) {
352-
Some(name) => name,
353-
None => tcx.item_name(def_id),
354-
};
355-
// Check if we know this one.
356-
if let Some(canonical_id) = mem.extra.extern_statics.get(&link_name) {
357-
trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id);
358-
*canonical_id
359-
} else {
360-
// Return original id; `Memory::get_static_alloc` will throw an error.
361-
id
362388
}
363389
}
364390

391+
fn resolve_thread_local_allocation_id(extra: &Self::MemoryExtra, id: AllocId) -> AllocId {
392+
extra.tls.resolve_allocation(id)
393+
}
394+
365395
fn init_allocation_extra<'b>(
366396
memory_extra: &MemoryExtra,
367397
id: AllocId,

src/shims/dlsym.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ impl Dlsym {
2020
}
2121
}
2222

23-
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
23+
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
2424
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
2525
fn call_dlsym(
2626
&mut self,

src/shims/env.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub struct EnvVars<'tcx> {
3737

3838
impl<'tcx> EnvVars<'tcx> {
3939
pub(crate) fn init<'mir>(
40-
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
40+
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
4141
mut excluded_env_vars: Vec<String>,
4242
) -> InterpResult<'tcx> {
4343
let target_os = ecx.tcx.sess.target.target.target_os.as_str();
@@ -63,7 +63,7 @@ impl<'tcx> EnvVars<'tcx> {
6363
}
6464

6565
pub(crate) fn cleanup<'mir>(
66-
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
66+
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
6767
) -> InterpResult<'tcx> {
6868
// Deallocate individual env vars.
6969
for (_name, ptr) in ecx.machine.env_vars.map.drain() {
@@ -80,7 +80,7 @@ impl<'tcx> EnvVars<'tcx> {
8080
fn alloc_env_var_as_c_str<'mir, 'tcx>(
8181
name: &OsStr,
8282
value: &OsStr,
83-
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
83+
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
8484
) -> InterpResult<'tcx, Pointer<Tag>> {
8585
let mut name_osstring = name.to_os_string();
8686
name_osstring.push("=");
@@ -91,15 +91,15 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>(
9191
fn alloc_env_var_as_wide_str<'mir, 'tcx>(
9292
name: &OsStr,
9393
value: &OsStr,
94-
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
94+
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>,
9595
) -> InterpResult<'tcx, Pointer<Tag>> {
9696
let mut name_osstring = name.to_os_string();
9797
name_osstring.push("=");
9898
name_osstring.push(value);
9999
Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into()))
100100
}
101101

102-
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
102+
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
103103
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
104104
fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar<Tag>> {
105105
let this = self.eval_context_mut();

src/shims/foreign_items.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_ast::attr;
1313

1414
use crate::*;
1515

16-
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
16+
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
1717
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
1818
/// Returns the minimum alignment for the target architecture for allocations of the given size.
1919
fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align {

0 commit comments

Comments
 (0)