Skip to content

Add shims for RwLock::try_read/RwLock::try_write #1157

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

Merged
merged 31 commits into from
Apr 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
46679bc
Add shims for RwLock::try_read/RwLock::try_write
divergentdave Jan 26, 2020
88f319f
Add failing tests for mutex and rwlock
divergentdave Jan 28, 2020
c2683da
Clean up test case
divergentdave Jan 29, 2020
dd9896b
Implement mutex and rwlock functions
divergentdave Feb 18, 2020
765050f
Revise mutex/rwlock memory layout for macOS compat
divergentdave Feb 18, 2020
dca83d7
Add test that exercises ReentrantMutex
divergentdave Feb 21, 2020
c773ca8
Style fixes
divergentdave Feb 22, 2020
5cc091b
Add test of recursive mutex using libc FFI
divergentdave Feb 22, 2020
d11315e
Fix misleading function names
divergentdave Mar 15, 2020
fd94255
Add comments explaining asserts
divergentdave Mar 17, 2020
141319a
Refactor sync shims with setters and getters
divergentdave Mar 22, 2020
ba3884d
Use checked addition/subtraction on lock counts
divergentdave Mar 22, 2020
e5e3256
Address review comments
divergentdave Mar 27, 2020
735fc12
Handle variation in layout of pthread_mutex_t
divergentdave Mar 28, 2020
de29546
Add and rearrange mutex tests
divergentdave Mar 28, 2020
c7466c9
Add TerminationInfo::Deadlock, use in mutex shim
divergentdave Mar 28, 2020
7f6df15
Rearrange functions
divergentdave Mar 28, 2020
bb06a0c
Restrict mutex static initializer test to Linux
divergentdave Mar 28, 2020
37ddde9
Implement TryEnterCriticalSection
divergentdave Mar 28, 2020
e1a1592
Set some explicit return value sizes
divergentdave Mar 28, 2020
8293d80
Set explicit return value size for windows shim
divergentdave Mar 28, 2020
ac8c98d
Store layouts of i32 and u32 inside Evaluator
divergentdave Mar 29, 2020
79f3307
Update comments, rearrange code
divergentdave Apr 5, 2020
100141f
Remove null checks, fall through to UB upon deref
divergentdave Apr 5, 2020
e794441
Use Deadlock machine stop uniformly
divergentdave Apr 5, 2020
d5d5a56
Add tests
divergentdave Apr 5, 2020
f9dc942
Changes to error handling
divergentdave Apr 5, 2020
134d6a2
Add tests, improve test coverage
divergentdave Apr 5, 2020
bc54c76
Eagerly compute i32 and u32 layouts
divergentdave Apr 5, 2020
0f5f0e1
Fix spelling typo
divergentdave Apr 6, 2020
80497e5
Clean up conditional compilation
divergentdave Apr 6, 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
6 changes: 5 additions & 1 deletion src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ pub enum TerminationInfo {
Exit(i64),
Abort(Option<String>),
UnsupportedInIsolation(String),
ExperimentalUb { msg: String, url: String }
ExperimentalUb { msg: String, url: String },
Deadlock,
}

impl fmt::Debug for TerminationInfo {
Expand All @@ -29,6 +30,8 @@ impl fmt::Debug for TerminationInfo {
write!(f, "{}", msg),
ExperimentalUb { msg, .. } =>
write!(f, "{}", msg),
Deadlock =>
write!(f, "the evaluated program deadlocked"),
}
}
}
Expand Down Expand Up @@ -60,6 +63,7 @@ pub fn report_error<'tcx, 'mir>(
"unsupported operation",
ExperimentalUb { .. } =>
"Undefined Behavior",
Deadlock => "deadlock",
};
let helps = match info {
UnsupportedInIsolation(_) =>
Expand Down
15 changes: 9 additions & 6 deletions src/eval.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
//! Main evaluator loop and setting up the initial stack frame.

use std::ffi::OsStr;
use std::convert::TryFrom;
use std::ffi::OsStr;

use rand::rngs::StdRng;
use rand::SeedableRng;

use rustc_target::abi::LayoutOf;
use rustc_middle::ty::{self, TyCtxt};
use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt};
use rustc_target::abi::LayoutOf;

use crate::*;

Expand Down Expand Up @@ -60,10 +60,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
main_id: DefId,
config: MiriConfig,
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> {
let tcx_at = tcx.at(rustc_span::source_map::DUMMY_SP);
let param_env = ty::ParamEnv::reveal_all();
let layout_cx = LayoutCx { tcx, param_env };
let mut ecx = InterpCx::new(
tcx.at(rustc_span::source_map::DUMMY_SP),
ty::ParamEnv::reveal_all(),
Evaluator::new(config.communicate, config.validate),
tcx_at,
param_env,
Evaluator::new(config.communicate, config.validate, layout_cx),
MemoryExtra::new(
StdRng::seed_from_u64(config.seed.unwrap_or(0)),
config.stacked_borrows,
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub use crate::shims::fs::{DirHandler, EvalContextExt as FileEvalContextExt, Fil
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::time::EvalContextExt as TimeEvalContextExt;
pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData};
pub use crate::shims::EvalContextExt as ShimsEvalContextExt;
Expand Down
42 changes: 38 additions & 4 deletions src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,18 @@ use std::time::Instant;
use log::trace;
use rand::rngs::StdRng;

use rustc_data_structures::fx::FxHashMap;
use rustc_middle::{mir, ty};
use rustc_target::abi::{LayoutOf, Size};
use rustc_ast::attr;
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::{
mir,
ty::{
self,
layout::{LayoutCx, LayoutError, TyAndLayout},
TyCtxt,
},
};
use rustc_span::symbol::{sym, Symbol};
use rustc_target::abi::{LayoutOf, Size};

use crate::*;

Expand Down Expand Up @@ -146,6 +153,21 @@ impl MemoryExtra {
}
}

/// Precomputed layouts of primitive types
pub(crate) struct PrimitiveLayouts<'tcx> {
pub(crate) i32: TyAndLayout<'tcx>,
pub(crate) u32: TyAndLayout<'tcx>,
}

impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> {
fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, LayoutError<'tcx>> {
Ok(Self {
i32: layout_cx.layout_of(layout_cx.tcx.types.i32)?,
u32: layout_cx.layout_of(layout_cx.tcx.types.u32)?,
})
}
}

/// The machine itself.
pub struct Evaluator<'tcx> {
/// Environment variables set by `setenv`.
Expand Down Expand Up @@ -182,10 +204,21 @@ pub struct Evaluator<'tcx> {

/// The "time anchor" for this machine's monotone clock (for `Instant` simulation).
pub(crate) time_anchor: Instant,

/// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri.
/// FIXME: Search through the rest of the codebase for more layout_of() calls that
/// could be stored here.
pub(crate) layouts: PrimitiveLayouts<'tcx>,
}

impl<'tcx> Evaluator<'tcx> {
pub(crate) fn new(communicate: bool, validate: bool) -> Self {
pub(crate) fn new(
communicate: bool,
validate: bool,
layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
) -> Self {
let layouts = PrimitiveLayouts::new(layout_cx)
.expect("Couldn't get layouts of primitive types");
Evaluator {
// `env_vars` could be initialized properly here if `Memory` were available before
// calling this method.
Expand All @@ -201,6 +234,7 @@ impl<'tcx> Evaluator<'tcx> {
dir_handler: Default::default(),
panic_payload: None,
time_anchor: Instant::now(),
layouts,
}
}
}
Expand Down
76 changes: 61 additions & 15 deletions src/shims/foreign_items/posix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,64 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.write_null(dest)?;
}

// Synchronization primitives
"pthread_mutexattr_init" => {
let result = this.pthread_mutexattr_init(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutexattr_settype" => {
let result = this.pthread_mutexattr_settype(args[0], args[1])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutexattr_destroy" => {
let result = this.pthread_mutexattr_destroy(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_init" => {
let result = this.pthread_mutex_init(args[0], args[1])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_lock" => {
let result = this.pthread_mutex_lock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_trylock" => {
let result = this.pthread_mutex_trylock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_unlock" => {
let result = this.pthread_mutex_unlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_mutex_destroy" => {
let result = this.pthread_mutex_destroy(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_rdlock" => {
let result = this.pthread_rwlock_rdlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_tryrdlock" => {
let result = this.pthread_rwlock_tryrdlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_wrlock" => {
let result = this.pthread_rwlock_wrlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_trywrlock" => {
let result = this.pthread_rwlock_trywrlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_unlock" => {
let result = this.pthread_rwlock_unlock(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"pthread_rwlock_destroy" => {
let result = this.pthread_rwlock_destroy(args[0])?;
this.write_scalar(Scalar::from_i32(result), dest)?;
}

// Better error for attempts to create a thread
"pthread_create" => {
throw_unsup_format!("Miri does not support threading");
Expand All @@ -255,25 +313,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.write_null(dest)?;
}

// Incomplete shims that we "stub out" just to get pre-main initialziation code to work.
// 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" if this.frame().instance.to_string().starts_with("std::sys::unix::") => {
this.write_null(dest)?;
}
| "pthread_mutexattr_init"
| "pthread_mutexattr_settype"
| "pthread_mutex_init"
| "pthread_mutexattr_destroy"
| "pthread_mutex_lock"
| "pthread_mutex_unlock"
| "pthread_mutex_destroy"
| "pthread_rwlock_rdlock"
| "pthread_rwlock_unlock"
| "pthread_rwlock_wrlock"
| "pthread_rwlock_destroy"
| "pthread_attr_setstacksize"
| "pthread_condattr_init"
| "pthread_condattr_setclock"
| "pthread_cond_init"
Expand All @@ -282,6 +327,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
=> {
this.write_null(dest)?;
}

| "signal"
| "sigaction"
| "sigaltstack"
Expand Down
2 changes: 1 addition & 1 deletion src/shims/foreign_items/posix/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.write_scalar(Scalar::from_i32(-1), dest)?;
}

// Incomplete shims that we "stub out" just to get pre-main initialziation code to work.
// 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_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => {
this.write_null(dest)?;
Expand Down
2 changes: 1 addition & 1 deletion src/shims/foreign_items/posix/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.write_scalar(stack_size, dest)?;
}

// Incomplete shims that we "stub out" just to get pre-main initialziation code to work.
// 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.
"mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => {
// This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value.
Expand Down
7 changes: 6 additions & 1 deletion src/shims/foreign_items/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
throw_unsup_format!("Miri does not support threading");
}

// Incomplete shims that we "stub out" just to get pre-main initialziation code to work.
// 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.
"GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
// Just fake a HANDLE
Expand All @@ -233,6 +233,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// (Windows locks are reentrant, and we have only 1 thread,
// so not doing any futher checks here is at least not incorrect.)
}
"TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::")
=> {
// There is only one thread, so this always succeeds and returns TRUE
this.write_scalar(Scalar::from_i32(1), dest)?;
}

_ => throw_unsup_format!("can't call foreign function: {}", link_name),
}
Expand Down
1 change: 1 addition & 0 deletions src/shims/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod fs;
pub mod intrinsics;
pub mod os_str;
pub mod panic;
pub mod sync;
pub mod time;
pub mod tls;

Expand Down
Loading