rust-lang-nursery / lazy-static.rs

A small macro for defining lazy evaluated static variables in Rust.
Apache License 2.0
1.9k stars 108 forks source link

Multi-threading with lazy_static #176

Open vext01 opened 4 years ago

vext01 commented 4 years ago

Hi,

I'm trying to track down a crash in a test suite that uses lazy_static.

A Once is being poisoned:

thread 'tests::exec_call_symbol_with_many_args_some_ignored' panicked at 'Once instance has previously been poisoned', src/libstd/sync/once.rs:395:21
stack backtrace:
   0: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
   1: core::fmt::write
   2: std::io::Write::write_fmt
   3: std::io::impls::<impl std::io::Write for alloc::boxed::Box<W>>::write_fmt
   4: std::panicking::default_hook::{{closure}}
   5: std::panicking::default_hook
   6: std::panicking::rust_panic_with_hook
   7: std::panicking::begin_panic
   8: std::sync::once::Once::call_inner
   9: std::sync::once::Once::call_once
             at /home/vext01/research/yorick/ykrustc/src/libstd/sync/once.rs:264
  10: lazy_static::lazy::Lazy<T>::get
             at /home/vext01/.cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-1.4.0/src/inline_lazy.rs:30
  11: <yktrace::tir::SIR as core::ops::deref::Deref>::deref::__stability
             at /home/vext01/.cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-1.4.0/src/lib.rs:142
  12: <yktrace::tir::SIR as core::ops::deref::Deref>::deref
             at /home/vext01/.cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-1.4.0/src/lib.rs:144
  13: yktrace::SirTraceIterator::new
             at yktrace/src/lib.rs:85
  14: <&dyn yktrace::SirTrace as core::iter::traits::collect::IntoIterator>::into_iter
             at yktrace/src/lib.rs:62
  15: yktrace::tir::TirTrace::new
             at yktrace/src/tir.rs:110
  16: ykcompile::tests::exec_call_symbol_with_many_args_some_ignored
             at ykcompile/src/lib.rs:906
  17: ykcompile::tests::exec_call_symbol_with_many_args_some_ignored::{{closure}}
             at ykcompile/src/lib.rs:898
  18: core::ops::function::FnOnce::call_once
             at /home/vext01/research/yorick/ykrustc/src/libcore/ops/function.rs:232
  19: test::run_test_in_process

If the tests are run using one thread, all is well.

So I wonder if there are some concurrency rules that need to be documented?

All I could find was:

The Deref implementation uses a hidden static variable that is guarded by an atomic check on each access.

Which suggests there is some form of multi-threading capabilities.

FWIW, my lazy_static usage is here. It's quite long running (a few seconds) in case that is a factor.

This code has been fine up until recently. Perhaps something is racy somewhere?

It wouldn't surprise me if this is user error, so apologies if that's what it turns out to be.

Thanks.

vext01 commented 4 years ago

I don't know what changed, but I can't reproduce this any more.

My theory is that the lazy_static initialiser crashed in one thread, leaving this Once poisoned for other threads.

If that's a thing that can happen, perhaps a more user-friendly message could be printed?

XX commented 2 years ago

In my case, this happened when the lazy_static initializer panicked in one thread.