Skip to content
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

Implement basic support for concurrency (Linux/macos only) #1284

Merged
merged 77 commits into from
Apr 30, 2020
Merged
Show file tree
Hide file tree
Changes from 74 commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
82f17ab
Implement basic support for concurrency (Linux only).
Mar 16, 2020
58a6a27
Add a warning that Miri does not check for data-races.
Apr 1, 2020
8dd8f19
Update to support the updated API.
Apr 1, 2020
92946b5
Add a test for thread locals.
Apr 1, 2020
aef4c95
Fix the problem of sending pointed to thread local statics. Add a reg…
Apr 3, 2020
1f33f04
Move pthread_create and related shims to a separate file.
Apr 6, 2020
ed9c7d1
Report that we do not support foreign thread local statics.
Apr 6, 2020
5218419
Fix comments in TLS.
Apr 6, 2020
f21197f
Store the thread name.
Apr 6, 2020
b04bf8a
Rustfmt the test.
Apr 6, 2020
2202278
Fix pthread_self.
Apr 6, 2020
1c8a59c
Rebase on PR 1157.
Apr 8, 2020
d907fb5
Rename ThreadSet to ThreadManager.
Apr 9, 2020
0c4303c
Small refactoring in pthread sync: extract common functionallity to s…
Apr 9, 2020
963e969
Generate fresh allocation ids for thread locals in eval_maybe_thread_…
Apr 15, 2020
51b16e5
Generate thread local allocations in eval_maybe_thread_local_static_c…
Apr 15, 2020
325c31e
Address some of the reviewers comments.
Apr 16, 2020
4609c3c
Rename eval_maybe_thread_local_static_const to adjust_global_const.
Apr 16, 2020
d9ec0f2
Add a missing newline in the test.
Apr 16, 2020
552080a
Fix imports.
Apr 16, 2020
94118d4
Make an assert message consistent with other asserts.
Apr 16, 2020
1d0eb93
Fix typo in a comment.
Apr 16, 2020
688cacb
Cleanup the implementation of adjust_global_const.
Apr 16, 2020
a585dc8
Add a missing newline.
Apr 16, 2020
44e9305
Rename threads to thread to match the Rust standard library.
Apr 16, 2020
d062f63
Fix support for MacOS.
Apr 17, 2020
134533d
Add a comment explaining global destructors on MacOS.
Apr 17, 2020
46fd333
Implement thread::yield_now.
Apr 18, 2020
421be27
Add concurrency tests.
Apr 18, 2020
c84b289
Update a comment in README about what concurrency checks we support.
Apr 19, 2020
d6c0392
Rename MacOS set global dtor function.
Apr 19, 2020
69df2e1
Move prctl to Linux specific shims.
Apr 19, 2020
eab38df
Change the warning message.
Apr 19, 2020
75e6549
Improve prctl, add a test.
Apr 19, 2020
94cbe88
Many small changes to thread management.
Apr 19, 2020
80459bb
Improve concurrency tests.
Apr 19, 2020
17f7bc8
Fix how a pthread_create function argument is constructed.
Apr 19, 2020
5b55e07
Add more concurrency tests.
Apr 19, 2020
e4dc356
Track if a thread was already joined.
Apr 19, 2020
9a01c3f
Clarify comments about TLS destructor handling in Windows, add a test…
Apr 20, 2020
3bb1657
Small style fix.
Apr 20, 2020
452e36e
Print the thread name in Debug.
Apr 20, 2020
69eaaad
Fix merge error.
Apr 20, 2020
e7c2694
Make the main thread detached.
Apr 20, 2020
e7b82fd
Fix the test annotation.
Apr 20, 2020
40e50bf
Clarify test comments.
Apr 20, 2020
8a7dbde
Check prctl argument types and fix the test.
Apr 20, 2020
d45e985
Clarify FIXME.
Apr 20, 2020
eaa6326
Make multiple threads to try to join a thread while it is still running.
Apr 21, 2020
cc9248a
Ignore prctl test on MacOS because it does not support it.
Apr 21, 2020
90e9a87
Add an explanatory comment to the test.
Apr 21, 2020
8240ed2
Change the test not to rely on internals.
Apr 21, 2020
feb1883
Unify TLS dtors; move stepping outside.
Apr 24, 2020
04abf06
Move copying of the thread name to the client side.
Apr 24, 2020
bc9d007
Improve Debug formatting of the thread name.
Apr 24, 2020
ff5e35b
Added a test that joining main is UB.
Apr 26, 2020
64164b1
Improve comments.
Apr 26, 2020
60cd8aa
Delete a duplicate test.
Apr 26, 2020
39efdf3
Move prctl test to the same file as other libc tests.
Apr 26, 2020
6842eb2
Rename global tls dtor to thread dtor.
Apr 26, 2020
c4574dd
Many small changes to clean up code.
Apr 26, 2020
911ff7e
Improve style and comments.
Apr 27, 2020
d9e18ad
Make sure to remove thread local data only if we have destructor.
Apr 27, 2020
174adad
Use DLL_THREAD_DETACH when calling windows TLS destructor.
Apr 27, 2020
9ba3ef2
Change representation and conversion of ThreadId and BlockSetId.
Apr 27, 2020
207c6e7
Improve comments and code clarity.
Apr 27, 2020
356aecc
Add a FIXME.
Apr 27, 2020
f204b67
Merge dtors_running and last_dtor_key fields.
Apr 27, 2020
331dbd1
Add a test for joining in a destructor.
Apr 27, 2020
c56ef31
Improve comments.
Apr 27, 2020
df2ca53
Make From implementations non-failing.
Apr 27, 2020
1355574
Delete remaining tls entries after all destructors completed.
Apr 27, 2020
3b58541
Fix MacOS and Windows builds.
Apr 27, 2020
46b0317
Improve code readability and comments.
Apr 29, 2020
0e052ab
Use Entry API in set_dtors_running.
Apr 29, 2020
603ec0b
Fix a regression in Windows dtors.
Apr 29, 2020
48da0cf
Fix prctl SET_NAME and GET_NAME behaviour.
Apr 30, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ in your program, and cannot run all programs:
* Miri runs the program as a platform-independent interpreter, so the program
has no access to most platform-specific APIs or FFI. A few APIs have been
implemented (such as printing to stdout) but most have not: for example, Miri
currently does not support concurrency, or SIMD, or networking.
currently does not support SIMD or networking.
* Miri currently does not check for data-races and most other concurrency
related issues.

[rust]: https://www.rust-lang.org/
[mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md
Expand Down
4 changes: 2 additions & 2 deletions src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ fn report_msg<'tcx, 'mir>(
mut helps: Vec<String>,
error: bool,
) {
let span = if let Some(frame) = ecx.machine.stack.last() {
let span = if let Some(frame) = ecx.active_thread_stack().last() {
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
frame.current_source_info().unwrap().span
} else {
DUMMY_SP
Expand Down Expand Up @@ -171,7 +171,7 @@ fn report_msg<'tcx, 'mir>(

err.emit();

for (i, frame) in ecx.machine.stack.iter().enumerate() {
for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
trace!("-------------------");
trace!("Frame {}", i);
trace!(" return: {:?}", frame.return_place.map(|p| *p));
Expand Down
20 changes: 15 additions & 5 deletions src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,24 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) ->
// Perform the main execution.
let res: InterpResult<'_, i64> = (|| {
// Main loop.
while ecx.step()? {
loop {
match ecx.schedule()? {
SchedulingAction::ExecuteStep => {
assert!(ecx.step()?, "a terminated thread was scheduled for execution");
}
SchedulingAction::ExecuteDtors => {
// This will either enable the thread again (so we go back
// to `ExecuteStep`), or determine that this thread is done
// for good.
ecx.schedule_next_tls_dtor_for_active_thread()?;
vakaras marked this conversation as resolved.
Show resolved Hide resolved
}
SchedulingAction::Stop => {
break;
}
}
ecx.process_diagnostics();
}
// Read the return code pointer *before* we run TLS destructors, to assert
// that it was written to by the time that `start` lang item returned.
let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?;
// Global destructors.
ecx.run_tls_dtors()?;
Ok(return_code)
})();

Expand Down
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extern crate rustc_ast;
#[macro_use] extern crate rustc_middle;
extern crate rustc_data_structures;
extern crate rustc_hir;
extern crate rustc_index;
extern crate rustc_mir;
extern crate rustc_span;
extern crate rustc_target;
Expand All @@ -26,6 +27,7 @@ mod operator;
mod range_map;
mod shims;
mod stacked_borrows;
mod thread;

// Make all those symbols available in the same place as our own.
pub use rustc_mir::interpret::*;
Expand All @@ -40,6 +42,7 @@ pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt;
pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt;
pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt};
pub use crate::shims::sync::{EvalContextExt as SyncEvalContextExt};
pub use crate::shims::thread::EvalContextExt as ThreadShimsEvalContextExt;
pub use crate::shims::time::EvalContextExt as TimeEvalContextExt;
pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData};
pub use crate::shims::EvalContextExt as ShimsEvalContextExt;
Expand All @@ -60,6 +63,9 @@ pub use crate::range_map::RangeMap;
pub use crate::stacked_borrows::{
EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag,
};
pub use crate::thread::{
EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, ThreadState,
};

/// Insert rustc arguments at the beginning of the argument list that Miri wants to be
/// set per default, for maximal validation power.
Expand Down
24 changes: 15 additions & 9 deletions src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,8 @@ pub struct Evaluator<'mir, 'tcx> {
/// The "time anchor" for this machine's monotone clock (for `Instant` simulation).
pub(crate) time_anchor: Instant,

/// The call stack.
pub(crate) stack: Vec<Frame<'mir, 'tcx, Tag, FrameData<'tcx>>>,
/// The set of threads.
pub(crate) threads: ThreadManager<'mir, 'tcx>,

/// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri.
pub(crate) layouts: PrimitiveLayouts<'tcx>,
Expand Down Expand Up @@ -282,7 +282,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
panic_payload: None,
time_anchor: Instant::now(),
layouts,
stack: Vec::default(),
threads: ThreadManager::default(),
}
}
}
Expand Down Expand Up @@ -416,6 +416,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
Ok(())
}

fn adjust_global_const(
ecx: &InterpCx<'mir, 'tcx, Self>,
mut val: mir::interpret::ConstValue<'tcx>,
) -> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> {
ecx.remap_thread_local_alloc_ids(&mut val)?;
Ok(val)
}

fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId {
let tcx = mem.tcx;
// Figure out if this is an extern static, and if yes, which one.
Expand Down Expand Up @@ -525,18 +533,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
Ok(frame.with_extra(extra))
}

#[inline(always)]
fn stack<'a>(
ecx: &'a InterpCx<'mir, 'tcx, Self>,
ecx: &'a InterpCx<'mir, 'tcx, Self>
) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] {
&ecx.machine.stack
ecx.active_thread_stack()
}

#[inline(always)]
fn stack_mut<'a>(
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
ecx: &'a mut InterpCx<'mir, 'tcx, Self>
) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>> {
&mut ecx.machine.stack
ecx.active_thread_stack_mut()
}

#[inline(always)]
Expand Down
44 changes: 36 additions & 8 deletions src/shims/foreign_items/posix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
"pthread_getspecific" => {
let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?;
let ptr = this.machine.tls.load_tls(key, this)?;
let active_thread = this.get_active_thread()?;
let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
this.write_scalar(ptr, dest)?;
}
"pthread_setspecific" => {
let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?;
let active_thread = this.get_active_thread()?;
let new_ptr = this.read_scalar(args[1])?.not_undef()?;
this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?;
this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?;

// Return success (`0`).
this.write_null(dest)?;
Expand Down Expand Up @@ -291,9 +293,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.write_scalar(Scalar::from_i32(result), dest)?;
}

// Better error for attempts to create a thread
// Threading
vakaras marked this conversation as resolved.
Show resolved Hide resolved
"pthread_create" => {
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
throw_unsup_format!("Miri does not support threading");
assert_eq!(args.len(), 4);
let result = this.pthread_create(args[0], args[1], args[2], args[3])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_join" => {
assert_eq!(args.len(), 2);
let result = this.pthread_join(args[0], args[1])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_detach" => {
assert_eq!(args.len(), 1);
let result = this.pthread_detach(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_self" => {
assert_eq!(args.len(), 0);
this.pthread_self(dest)?;
}
"sched_yield" => {
vakaras marked this conversation as resolved.
Show resolved Hide resolved
assert_eq!(args.len(), 0);
let result = this.sched_yield()?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}

// Miscellaneous
Expand All @@ -312,15 +335,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// We do not support forking, so there is nothing to do here.
this.write_null(dest)?;
}
"sched_yield" => {
this.write_null(dest)?;
}

// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
// These shims are enabled only when the caller is in the standard library.
| "pthread_attr_init"
| "pthread_attr_destroy"
| "pthread_self"
| "pthread_attr_setstacksize"
| "pthread_condattr_init"
| "pthread_condattr_setclock"
Expand All @@ -330,6 +349,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
=> {
this.write_null(dest)?;
}
"pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::")
=> {
let guard_size = this.deref_operand(args[1])?;
let guard_size_layout = this.libc_ty_layout("size_t")?;
vakaras marked this conversation as resolved.
Show resolved Hide resolved
this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), guard_size.into())?;

// Return success (`0`).
this.write_null(dest)?;
}

| "signal"
| "sigaction"
Expand Down
7 changes: 7 additions & 0 deletions src/shims/foreign_items/posix/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.write_null(dest)?;
}

// Threading
"prctl" => {
assert_eq!(args.len(), 5);
let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}

// Dynamically invoked syscalls
"syscall" => {
let sys_getrandom = this
Expand Down
3 changes: 2 additions & 1 deletion src/shims/foreign_items/posix/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let dtor = this.read_scalar(args[0])?.not_undef()?;
let dtor = this.memory.get_fn(dtor)?.as_instance()?;
let data = this.read_scalar(args[1])?.not_undef()?;
this.machine.tls.set_global_dtor(dtor, data)?;
let active_thread = this.get_active_thread()?;
this.machine.tls.set_thread_dtor(active_thread, dtor, data)?;
}

// Querying system information
Expand Down
6 changes: 4 additions & 2 deletions src/shims/foreign_items/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
"TlsGetValue" => {
let key = u128::from(this.read_scalar(args[0])?.to_u32()?);
let ptr = this.machine.tls.load_tls(key, this)?;
let active_thread = this.get_active_thread()?;
let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
this.write_scalar(ptr, dest)?;
}
"TlsSetValue" => {
let key = u128::from(this.read_scalar(args[0])?.to_u32()?);
let active_thread = this.get_active_thread()?;
let new_ptr = this.read_scalar(args[1])?.not_undef()?;
this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?;
this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?;

// Return success (`1`).
this.write_scalar(Scalar::from_i32(1), dest)?;
Expand Down
1 change: 1 addition & 0 deletions src/shims/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod intrinsics;
pub mod os_str;
pub mod panic;
pub mod sync;
pub mod thread;
pub mod time;
pub mod tls;

Expand Down
Loading