Skip to content

Commit 7a2c681

Browse files
committed
Per-thread errno storage
1 parent da2f268 commit 7a2c681

File tree

8 files changed

+53
-16
lines changed

8 files changed

+53
-16
lines changed

src/eval.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -193,12 +193,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
193193
StackPopCleanup::None { cleanup: true },
194194
)?;
195195

196-
// Set the last_error to 0
197-
let errno_layout = ecx.machine.layouts.u32;
198-
let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Machine.into());
199-
ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?;
200-
ecx.machine.last_error = Some(errno_place);
201-
202196
Ok((ecx, ret_place))
203197
}
204198

src/helpers.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -394,17 +394,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
394394
)
395395
}
396396

397+
/// Get last error variable as a place, lazily allocating thread-local storage for it if
398+
/// necessary.
399+
fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> {
400+
let this = self.eval_context_mut();
401+
if let Some(errno_place) = this.active_thread_ref().last_error {
402+
Ok(errno_place)
403+
} else {
404+
let errno_layout = this.machine.layouts.u32;
405+
let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into());
406+
this.write_scalar(Scalar::from_u32(0), errno_place.into())?;
407+
this.active_thread_mut().last_error = Some(errno_place);
408+
Ok(errno_place)
409+
}
410+
}
411+
397412
/// Sets the last error variable.
398413
fn set_last_error(&mut self, scalar: Scalar<Tag>) -> InterpResult<'tcx> {
399414
let this = self.eval_context_mut();
400-
let errno_place = this.machine.last_error.unwrap();
415+
let errno_place = this.last_error_place()?;
401416
this.write_scalar(scalar, errno_place.into())
402417
}
403418

404419
/// Gets the last error variable.
405-
fn get_last_error(&self) -> InterpResult<'tcx, Scalar<Tag>> {
406-
let this = self.eval_context_ref();
407-
let errno_place = this.machine.last_error.unwrap();
420+
fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar<Tag>> {
421+
let this = self.eval_context_mut();
422+
let errno_place = this.last_error_place()?;
408423
this.read_scalar(errno_place.into())?.check_init()
409424
}
410425

src/machine.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,6 @@ pub struct Evaluator<'mir, 'tcx> {
236236
pub(crate) argv: Option<Scalar<Tag>>,
237237
pub(crate) cmd_line: Option<Scalar<Tag>>,
238238

239-
/// Last OS error location in memory. It is a 32-bit integer.
240-
pub(crate) last_error: Option<MPlaceTy<'tcx, Tag>>,
241-
242239
/// TLS state.
243240
pub(crate) tls: TlsData<'tcx>,
244241

@@ -280,7 +277,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
280277
argc: None,
281278
argv: None,
282279
cmd_line: None,
283-
last_error: None,
284280
tls: TlsData::default(),
285281
communicate,
286282
validate,

src/shims/posix/linux/foreign_items.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2121
// errno
2222
"__errno_location" => {
2323
let &[] = check_arg_count(args)?;
24-
let errno_place = this.machine.last_error.unwrap();
24+
let errno_place = this.last_error_place()?;
2525
this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?;
2626
}
2727

src/shims/posix/macos/foreign_items.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2020
// errno
2121
"__error" => {
2222
let &[] = check_arg_count(args)?;
23-
let errno_place = this.machine.last_error.unwrap();
23+
let errno_place = this.last_error_place()?;
2424
this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?;
2525
}
2626

src/thread.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ pub struct Thread<'mir, 'tcx> {
120120
/// the call to `miri_start_panic` (the panic payload) when unwinding.
121121
/// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`.
122122
pub(crate) panic_payload: Option<Scalar<Tag>>,
123+
124+
/// Last OS error location in memory. It is a 32-bit integer.
125+
pub(crate) last_error: Option<MPlaceTy<'tcx, Tag>>,
123126
}
124127

125128
impl<'mir, 'tcx> Thread<'mir, 'tcx> {
@@ -159,6 +162,7 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> {
159162
stack: Vec::new(),
160163
join_status: ThreadJoinStatus::Joinable,
161164
panic_payload: None,
165+
last_error: None,
162166
}
163167
}
164168
}
@@ -583,6 +587,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
583587
this.machine.threads.active_thread_mut()
584588
}
585589

590+
#[inline]
591+
fn active_thread_ref(&self) -> &Thread<'mir, 'tcx> {
592+
let this = self.eval_context_ref();
593+
this.machine.threads.active_thread_ref()
594+
}
595+
586596
#[inline]
587597
fn get_total_thread_count(&self) -> usize {
588598
let this = self.eval_context_ref();

tests/run-pass/libc.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,24 @@ fn test_prctl_thread_name() {
212212
}
213213
}
214214

215+
/// Tests whether each thread has its own `__errno_location`.
216+
fn test_thread_local_errno() {
217+
#[cfg(not(target_os = "macos"))]
218+
use libc::__errno_location;
219+
#[cfg(target_os = "macos")]
220+
use libc::__error as __errno_location;
221+
222+
unsafe {
223+
*__errno_location() = 0xBEEF;
224+
std::thread::spawn(|| {
225+
assert_eq!(*__errno_location(), 0);
226+
*__errno_location() = 0xBAD1DEA;
227+
assert_eq!(*__errno_location(), 0xBAD1DEA);
228+
}).join().unwrap();
229+
assert_eq!(*__errno_location(), 0xBEEF);
230+
}
231+
}
232+
215233
fn main() {
216234
#[cfg(target_os = "linux")]
217235
test_posix_fadvise();
@@ -229,4 +247,6 @@ fn main() {
229247

230248
#[cfg(target_os = "linux")]
231249
test_prctl_thread_name();
250+
251+
test_thread_local_errno();
232252
}

tests/run-pass/libc.stderr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
warning: thread support is experimental. For example, Miri does not detect data races yet.
2+

0 commit comments

Comments
 (0)