@@ -154,7 +154,7 @@ macro_rules! dbghelp {
154
154
// Convenience proxy to use the cleanup locks to reference dbghelp
155
155
// functions.
156
156
#[ allow( dead_code) ]
157
- impl Cleanup {
157
+ impl Init {
158
158
$( pub fn $name( & self ) -> $name {
159
159
unsafe {
160
160
DBGHELP . $name( ) . unwrap( )
@@ -244,75 +244,45 @@ dbghelp! {
244
244
}
245
245
}
246
246
247
- pub struct Cleanup ;
248
-
249
- // Number of times `init` has been called on this thread. This is externally
250
- // synchronized and doesn't use internal synchronization on our behalf.
251
- static mut COUNT : usize = 0 ;
252
-
253
- // Used to restore `SymSetOptions` and `SymGetOptions` values.
254
- static mut OPTS_ORIG : DWORD = 0 ;
247
+ pub struct Init ;
255
248
256
249
/// Unsafe because this requires external synchronization, must be done
257
250
/// inside of the same lock as all other backtrace operations.
258
251
///
259
252
/// Note that the `Dbghelp` returned must also be dropped within the same
260
253
/// lock.
261
254
#[ cfg( all( windows, feature = "dbghelp" ) ) ]
262
- pub unsafe fn init ( ) -> Result < Cleanup , ( ) > {
263
- // Initializing symbols has significant overhead, but initializing only
264
- // once without cleanup causes problems for external sources. For
265
- // example, the standard library checks the result of SymInitializeW
266
- // (which returns an error if attempting to initialize twice) and in
267
- // the event of an error, will not print a backtrace on panic.
268
- // Presumably, external debuggers may have similar issues.
269
- //
270
- // As a compromise, we'll keep track of the number of internal
271
- // initialization requests within a single API call in order to
272
- // minimize the number of init/cleanup cycles.
273
- if COUNT > 0 {
274
- COUNT += 1 ;
275
- return Ok ( Cleanup ) ;
255
+ pub unsafe fn init ( ) -> Result < Init , ( ) > {
256
+ // Calling `SymInitializeW` is quite expensive, so we only do so once per
257
+ // process.
258
+ static mut INITIALIZED : bool = false ;
259
+ if INITIALIZED {
260
+ return Ok ( Init ) ;
276
261
}
277
262
278
263
// Actually load `dbghelp.dll` into the process here, returning an error if
279
264
// that fails.
280
265
DBGHELP . ensure_open ( ) ?;
281
266
282
- OPTS_ORIG = DBGHELP . SymGetOptions ( ) . unwrap ( ) ( ) ;
267
+ let orig = DBGHELP . SymGetOptions ( ) . unwrap ( ) ( ) ;
283
268
284
269
// Ensure that the `SYMOPT_DEFERRED_LOADS` flag is set, because
285
270
// according to MSVC's own docs about this: "This is the fastest, most
286
271
// efficient way to use the symbol handler.", so let's do that!
287
- DBGHELP . SymSetOptions ( ) . unwrap ( ) ( OPTS_ORIG | SYMOPT_DEFERRED_LOADS ) ;
288
-
289
- let ret = DBGHELP . SymInitializeW ( ) . unwrap ( ) ( GetCurrentProcess ( ) , ptr:: null_mut ( ) , TRUE ) ;
290
- if ret != TRUE {
291
- // Symbols may have been initialized by another library or an
292
- // external debugger
293
- DBGHELP . SymSetOptions ( ) . unwrap ( ) ( OPTS_ORIG ) ;
294
- Err ( ( ) )
295
- } else {
296
- COUNT += 1 ;
297
- Ok ( Cleanup )
298
- }
299
- }
272
+ DBGHELP . SymSetOptions ( ) . unwrap ( ) ( orig | SYMOPT_DEFERRED_LOADS ) ;
300
273
301
- impl Drop for Cleanup {
302
- fn drop ( & mut self ) {
303
- unsafe {
304
- COUNT -= 1 ;
305
- if COUNT != 0 {
306
- return ;
307
- }
308
-
309
- // Clean up after ourselves by cleaning up symbols and restoring the
310
- // symbol options to their original value. This is currently
311
- // required to cooperate with libstd as libstd's backtracing will
312
- // assert symbol initialization succeeds and will clean up after the
313
- // backtrace is finished.
314
- DBGHELP . SymCleanup ( ) . unwrap ( ) ( GetCurrentProcess ( ) ) ;
315
- DBGHELP . SymSetOptions ( ) . unwrap ( ) ( OPTS_ORIG ) ;
316
- }
317
- }
274
+ // Actually initialize symbols with MSVC. Note that this can fail, but we
275
+ // ignore it. There's not a ton of prior art for this per se, but LLVM
276
+ // internally seems to ignore the return value here and one of the
277
+ // sanitizer libraries in LLVM prints a scary warning if this fails but
278
+ // basically ignores it in the long run.
279
+ //
280
+ // One case this comes up a lot for Rust is that the standard library and
281
+ // this crate on crates.io both want to compete for `SymInitializeW`. The
282
+ // standard library historically wanted to initialize then cleanup most of
283
+ // the time, but now that it's using this crate it means that someone will
284
+ // get to initialization first and the other will pick up that
285
+ // initialization.
286
+ DBGHELP . SymInitializeW ( ) . unwrap ( ) ( GetCurrentProcess ( ) , ptr:: null_mut ( ) , TRUE ) ;
287
+ Ok ( Init )
318
288
}
0 commit comments