Skip to content

Commit d935f62

Browse files
committed
Auto merge of #1157 - divergentdave:shim-pthread-try-lock, r=RalfJung
Add shims for RwLock::try_read/RwLock::try_write This implements proper locking so that we can check for reentrancy and implement the `try_*` methods. Fixes #781
2 parents d25589f + 80497e5 commit d935f62

23 files changed

+891
-42
lines changed

src/diagnostics.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ pub enum TerminationInfo {
1212
Exit(i64),
1313
Abort(Option<String>),
1414
UnsupportedInIsolation(String),
15-
ExperimentalUb { msg: String, url: String }
15+
ExperimentalUb { msg: String, url: String },
16+
Deadlock,
1617
}
1718

1819
impl fmt::Debug for TerminationInfo {
@@ -29,6 +30,8 @@ impl fmt::Debug for TerminationInfo {
2930
write!(f, "{}", msg),
3031
ExperimentalUb { msg, .. } =>
3132
write!(f, "{}", msg),
33+
Deadlock =>
34+
write!(f, "the evaluated program deadlocked"),
3235
}
3336
}
3437
}
@@ -60,6 +63,7 @@ pub fn report_error<'tcx, 'mir>(
6063
"unsupported operation",
6164
ExperimentalUb { .. } =>
6265
"Undefined Behavior",
66+
Deadlock => "deadlock",
6367
};
6468
let helps = match info {
6569
UnsupportedInIsolation(_) =>

src/eval.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
//! Main evaluator loop and setting up the initial stack frame.
22
3-
use std::ffi::OsStr;
43
use std::convert::TryFrom;
4+
use std::ffi::OsStr;
55

66
use rand::rngs::StdRng;
77
use rand::SeedableRng;
88

9-
use rustc_target::abi::LayoutOf;
10-
use rustc_middle::ty::{self, TyCtxt};
119
use rustc_hir::def_id::DefId;
10+
use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt};
11+
use rustc_target::abi::LayoutOf;
1212

1313
use crate::*;
1414

@@ -60,10 +60,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
6060
main_id: DefId,
6161
config: MiriConfig,
6262
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> {
63+
let tcx_at = tcx.at(rustc_span::source_map::DUMMY_SP);
64+
let param_env = ty::ParamEnv::reveal_all();
65+
let layout_cx = LayoutCx { tcx, param_env };
6366
let mut ecx = InterpCx::new(
64-
tcx.at(rustc_span::source_map::DUMMY_SP),
65-
ty::ParamEnv::reveal_all(),
66-
Evaluator::new(config.communicate, config.validate),
67+
tcx_at,
68+
param_env,
69+
Evaluator::new(config.communicate, config.validate, layout_cx),
6770
MemoryExtra::new(
6871
StdRng::seed_from_u64(config.seed.unwrap_or(0)),
6972
config.stacked_borrows,

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub use crate::shims::fs::{DirHandler, EvalContextExt as FileEvalContextExt, Fil
3939
pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt;
4040
pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt;
4141
pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt};
42+
pub use crate::shims::sync::{EvalContextExt as SyncEvalContextExt};
4243
pub use crate::shims::time::EvalContextExt as TimeEvalContextExt;
4344
pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData};
4445
pub use crate::shims::EvalContextExt as ShimsEvalContextExt;

src/machine.rs

+38-4
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,18 @@ use std::time::Instant;
1010
use log::trace;
1111
use rand::rngs::StdRng;
1212

13-
use rustc_data_structures::fx::FxHashMap;
14-
use rustc_middle::{mir, ty};
15-
use rustc_target::abi::{LayoutOf, Size};
1613
use rustc_ast::attr;
14+
use rustc_data_structures::fx::FxHashMap;
15+
use rustc_middle::{
16+
mir,
17+
ty::{
18+
self,
19+
layout::{LayoutCx, LayoutError, TyAndLayout},
20+
TyCtxt,
21+
},
22+
};
1723
use rustc_span::symbol::{sym, Symbol};
24+
use rustc_target::abi::{LayoutOf, Size};
1825

1926
use crate::*;
2027

@@ -146,6 +153,21 @@ impl MemoryExtra {
146153
}
147154
}
148155

156+
/// Precomputed layouts of primitive types
157+
pub(crate) struct PrimitiveLayouts<'tcx> {
158+
pub(crate) i32: TyAndLayout<'tcx>,
159+
pub(crate) u32: TyAndLayout<'tcx>,
160+
}
161+
162+
impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> {
163+
fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, LayoutError<'tcx>> {
164+
Ok(Self {
165+
i32: layout_cx.layout_of(layout_cx.tcx.types.i32)?,
166+
u32: layout_cx.layout_of(layout_cx.tcx.types.u32)?,
167+
})
168+
}
169+
}
170+
149171
/// The machine itself.
150172
pub struct Evaluator<'tcx> {
151173
/// Environment variables set by `setenv`.
@@ -182,10 +204,21 @@ pub struct Evaluator<'tcx> {
182204

183205
/// The "time anchor" for this machine's monotone clock (for `Instant` simulation).
184206
pub(crate) time_anchor: Instant,
207+
208+
/// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri.
209+
/// FIXME: Search through the rest of the codebase for more layout_of() calls that
210+
/// could be stored here.
211+
pub(crate) layouts: PrimitiveLayouts<'tcx>,
185212
}
186213

187214
impl<'tcx> Evaluator<'tcx> {
188-
pub(crate) fn new(communicate: bool, validate: bool) -> Self {
215+
pub(crate) fn new(
216+
communicate: bool,
217+
validate: bool,
218+
layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
219+
) -> Self {
220+
let layouts = PrimitiveLayouts::new(layout_cx)
221+
.expect("Couldn't get layouts of primitive types");
189222
Evaluator {
190223
// `env_vars` could be initialized properly here if `Memory` were available before
191224
// calling this method.
@@ -201,6 +234,7 @@ impl<'tcx> Evaluator<'tcx> {
201234
dir_handler: Default::default(),
202235
panic_payload: None,
203236
time_anchor: Instant::now(),
237+
layouts,
204238
}
205239
}
206240
}

src/shims/foreign_items/posix.rs

+61-15
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,64 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
233233
this.write_null(dest)?;
234234
}
235235

236+
// Synchronization primitives
237+
"pthread_mutexattr_init" => {
238+
let result = this.pthread_mutexattr_init(args[0])?;
239+
this.write_scalar(Scalar::from_i32(result), dest)?;
240+
}
241+
"pthread_mutexattr_settype" => {
242+
let result = this.pthread_mutexattr_settype(args[0], args[1])?;
243+
this.write_scalar(Scalar::from_i32(result), dest)?;
244+
}
245+
"pthread_mutexattr_destroy" => {
246+
let result = this.pthread_mutexattr_destroy(args[0])?;
247+
this.write_scalar(Scalar::from_i32(result), dest)?;
248+
}
249+
"pthread_mutex_init" => {
250+
let result = this.pthread_mutex_init(args[0], args[1])?;
251+
this.write_scalar(Scalar::from_i32(result), dest)?;
252+
}
253+
"pthread_mutex_lock" => {
254+
let result = this.pthread_mutex_lock(args[0])?;
255+
this.write_scalar(Scalar::from_i32(result), dest)?;
256+
}
257+
"pthread_mutex_trylock" => {
258+
let result = this.pthread_mutex_trylock(args[0])?;
259+
this.write_scalar(Scalar::from_i32(result), dest)?;
260+
}
261+
"pthread_mutex_unlock" => {
262+
let result = this.pthread_mutex_unlock(args[0])?;
263+
this.write_scalar(Scalar::from_i32(result), dest)?;
264+
}
265+
"pthread_mutex_destroy" => {
266+
let result = this.pthread_mutex_destroy(args[0])?;
267+
this.write_scalar(Scalar::from_i32(result), dest)?;
268+
}
269+
"pthread_rwlock_rdlock" => {
270+
let result = this.pthread_rwlock_rdlock(args[0])?;
271+
this.write_scalar(Scalar::from_i32(result), dest)?;
272+
}
273+
"pthread_rwlock_tryrdlock" => {
274+
let result = this.pthread_rwlock_tryrdlock(args[0])?;
275+
this.write_scalar(Scalar::from_i32(result), dest)?;
276+
}
277+
"pthread_rwlock_wrlock" => {
278+
let result = this.pthread_rwlock_wrlock(args[0])?;
279+
this.write_scalar(Scalar::from_i32(result), dest)?;
280+
}
281+
"pthread_rwlock_trywrlock" => {
282+
let result = this.pthread_rwlock_trywrlock(args[0])?;
283+
this.write_scalar(Scalar::from_i32(result), dest)?;
284+
}
285+
"pthread_rwlock_unlock" => {
286+
let result = this.pthread_rwlock_unlock(args[0])?;
287+
this.write_scalar(Scalar::from_i32(result), dest)?;
288+
}
289+
"pthread_rwlock_destroy" => {
290+
let result = this.pthread_rwlock_destroy(args[0])?;
291+
this.write_scalar(Scalar::from_i32(result), dest)?;
292+
}
293+
236294
// Better error for attempts to create a thread
237295
"pthread_create" => {
238296
throw_unsup_format!("Miri does not support threading");
@@ -255,25 +313,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
255313
this.write_null(dest)?;
256314
}
257315

258-
// Incomplete shims that we "stub out" just to get pre-main initialziation code to work.
316+
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
259317
// These shims are enabled only when the caller is in the standard library.
260318
| "pthread_attr_init"
261319
| "pthread_attr_destroy"
262320
| "pthread_self"
263-
| "pthread_attr_setstacksize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => {
264-
this.write_null(dest)?;
265-
}
266-
| "pthread_mutexattr_init"
267-
| "pthread_mutexattr_settype"
268-
| "pthread_mutex_init"
269-
| "pthread_mutexattr_destroy"
270-
| "pthread_mutex_lock"
271-
| "pthread_mutex_unlock"
272-
| "pthread_mutex_destroy"
273-
| "pthread_rwlock_rdlock"
274-
| "pthread_rwlock_unlock"
275-
| "pthread_rwlock_wrlock"
276-
| "pthread_rwlock_destroy"
321+
| "pthread_attr_setstacksize"
277322
| "pthread_condattr_init"
278323
| "pthread_condattr_setclock"
279324
| "pthread_cond_init"
@@ -282,6 +327,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
282327
=> {
283328
this.write_null(dest)?;
284329
}
330+
285331
| "signal"
286332
| "sigaction"
287333
| "sigaltstack"

src/shims/foreign_items/posix/linux.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
113113
this.write_scalar(Scalar::from_i32(-1), dest)?;
114114
}
115115

116-
// Incomplete shims that we "stub out" just to get pre-main initialziation code to work.
116+
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
117117
// These shims are enabled only when the caller is in the standard library.
118118
"pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => {
119119
this.write_null(dest)?;

src/shims/foreign_items/posix/macos.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
8888
this.write_scalar(stack_size, dest)?;
8989
}
9090

91-
// Incomplete shims that we "stub out" just to get pre-main initialziation code to work.
91+
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
9292
// These shims are enabled only when the caller is in the standard library.
9393
"mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => {
9494
// 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.

src/shims/foreign_items/windows.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
207207
throw_unsup_format!("Miri does not support threading");
208208
}
209209

210-
// Incomplete shims that we "stub out" just to get pre-main initialziation code to work.
210+
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
211211
// These shims are enabled only when the caller is in the standard library.
212212
"GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => {
213213
// Just fake a HANDLE
@@ -233,6 +233,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
233233
// (Windows locks are reentrant, and we have only 1 thread,
234234
// so not doing any futher checks here is at least not incorrect.)
235235
}
236+
"TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::")
237+
=> {
238+
// There is only one thread, so this always succeeds and returns TRUE
239+
this.write_scalar(Scalar::from_i32(1), dest)?;
240+
}
236241

237242
_ => throw_unsup_format!("can't call foreign function: {}", link_name),
238243
}

src/shims/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub mod fs;
55
pub mod intrinsics;
66
pub mod os_str;
77
pub mod panic;
8+
pub mod sync;
89
pub mod time;
910
pub mod tls;
1011

0 commit comments

Comments
 (0)