Skip to content

Commit 876bded

Browse files
committed
run Windows TLS dtor function
1 parent 02897e0 commit 876bded

File tree

5 files changed

+55
-17
lines changed

5 files changed

+55
-17
lines changed

src/eval.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
184184
/// Returns `Some(return_code)` if program executed completed.
185185
/// Returns `None` if an evaluation error occured.
186186
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
187-
// FIXME: We always ignore leaks on some OSs where we do not
188-
// correctly implement TLS destructors.
189-
let target_os = &tcx.sess.target.target.target_os;
190-
let ignore_leaks = config.ignore_leaks || target_os == "windows";
187+
// FIXME: on Windows, locks and TLS dtor management allocate and leave that memory in `static`s.
188+
// So we need https://github.com/rust-lang/miri/issues/940 to fix the leaks there.
189+
let ignore_leaks = config.ignore_leaks || tcx.sess.target.target.target_os == "windows";
191190

192191
let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
193192
Ok(v) => v,

src/helpers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
413413
fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> {
414414
use std::io::ErrorKind::*;
415415
let this = self.eval_context_mut();
416-
let target = &this.tcx.tcx.sess.target.target;
416+
let target = &this.tcx.sess.target.target;
417417
let last_error = if target.options.target_family == Some("unix".to_owned()) {
418418
this.eval_libc(match e.kind() {
419419
ConnectionRefused => "ECONNREFUSED",

src/machine.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,20 @@ impl MemoryExtra {
102102
}
103103
}
104104

105+
fn add_extern_static<'tcx, 'mir>(
106+
this: &mut MiriEvalContext<'mir, 'tcx>,
107+
name: &str,
108+
ptr: Scalar<Tag>,
109+
) {
110+
let ptr = ptr.assert_ptr();
111+
assert_eq!(ptr.offset, Size::ZERO);
112+
this.memory
113+
.extra
114+
.extern_statics
115+
.insert(Symbol::intern(name), ptr.alloc_id)
116+
.unwrap_none();
117+
}
118+
105119
/// Sets up the "extern statics" for this machine.
106120
pub fn init_extern_statics<'tcx, 'mir>(
107121
this: &mut MiriEvalContext<'mir, 'tcx>,
@@ -113,17 +127,17 @@ impl MemoryExtra {
113127
let layout = this.layout_of(this.tcx.types.usize)?;
114128
let place = this.allocate(layout, MiriMemoryKind::Machine.into());
115129
this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?;
116-
this.memory
117-
.extra
118-
.extern_statics
119-
.insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id)
120-
.unwrap_none();
130+
Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr);
121131
// "environ"
122-
this.memory
123-
.extra
124-
.extern_statics
125-
.insert(Symbol::intern("environ"), this.machine.env_vars.environ.unwrap().ptr.assert_ptr().alloc_id)
126-
.unwrap_none();
132+
Self::add_extern_static(this, "environ", this.machine.env_vars.environ.unwrap().ptr);
133+
}
134+
"windows" => {
135+
// "_tls_used"
136+
// This is some obscure hack that is part of the Windows TLS story. It's a `u8`.
137+
let layout = this.layout_of(this.tcx.types.u8)?;
138+
let place = this.allocate(layout, MiriMemoryKind::Machine.into());
139+
this.write_scalar(Scalar::from_u8(0), place.into())?;
140+
Self::add_extern_static(this, "_tls_used", place.ptr);
127141
}
128142
_ => {} // No "extern statics" supported on this target
129143
}

src/shims/foreign_items.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
1919
fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align {
2020
let this = self.eval_context_ref();
2121
// List taken from `libstd/sys_common/alloc.rs`.
22-
let min_align = match this.tcx.tcx.sess.target.target.arch.as_str() {
22+
let min_align = match this.tcx.sess.target.target.arch.as_str() {
2323
"x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8,
2424
"x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16,
2525
arch => bug!("Unsupported target architecture: {}", arch),

src/shims/tls.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
159159
assert!(!this.machine.tls.dtors_running, "running TLS dtors twice");
160160
this.machine.tls.dtors_running = true;
161161

162+
if this.tcx.sess.target.target.target_os == "windows" {
163+
// Windows has a special magic linker section that is run on certain events.
164+
// Instead of searching for that section and supporting arbitrary hooks in there
165+
// (that would be basically https://github.com/rust-lang/miri/issues/450),
166+
// we specifically look up the static in libstd that we know is placed
167+
// in that section.
168+
let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local", "p_thread_callback"])?;
169+
let thread_callback = this.memory.get_fn(thread_callback.not_undef()?)?.as_instance()?;
170+
171+
// The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`.
172+
let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_PROCESS_DETACH"])?;
173+
let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into();
174+
this.call_function(
175+
thread_callback,
176+
&[Scalar::ptr_null(this).into(), reason.into(), Scalar::ptr_null(this).into()],
177+
Some(ret_place),
178+
StackPopCleanup::None { cleanup: true },
179+
)?;
180+
181+
// step until out of stackframes
182+
this.run()?;
183+
184+
// Windows doesn't have other destructors.
185+
return Ok(());
186+
}
187+
162188
// The macOS global dtor runs "before any TLS slots get freed", so do that first.
163189
if let Some((instance, data)) = this.machine.tls.global_dtor {
164190
trace!("Running global dtor {:?} on {:?}", instance, data);
@@ -199,7 +225,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
199225
None => this.machine.tls.fetch_tls_dtor(None),
200226
};
201227
}
202-
// FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`.
203228
Ok(())
204229
}
205230
}

0 commit comments

Comments
 (0)