Skip to content

lto = "thin" causes SIGSEGVs when ran under rustdoc #911

@trofi

Description

@trofi

In xiph/rav1e#2851 NixOS found out the crash of rayon-1.5.1 on rav1e doctests. Here is extracted reproducer:

# cat Cargo.toml
[package]
name = "bug"
version = "0.1.0"
edition = "2018"

[dependencies]
rayon = "~1.5.1"

[profile.dev]
#debug = true
#incremental = true
#debug-assertions = true
lto = "thin"
opt-level = 2
overflow-checks = false
codegen-units = 256
// cat src/lib.rs
use rayon::iter::IntoParallelIterator;
use rayon::iter::ParallelIterator;

/// # Examples
///
/// ```
/// use bug::do_bug;
///
/// # fn main() {
/// bug::do_bug()
/// # }
/// ```
pub fn do_bug() {
  (0..1).into_par_iter().for_each(|_| {});
  (0..1).into_par_iter().for_each(|_| {});
  (0..1).into_par_iter().for_each(|_| {});
}

Reproducer run:

$ cargo test --doc
    Updating crates.io index
   Compiling autocfg v1.0.1
   Compiling crossbeam-utils v0.8.6
   Compiling lazy_static v1.4.0
   Compiling cfg-if v1.0.0
   Compiling crossbeam-epoch v0.9.6
   Compiling libc v0.2.112
   Compiling scopeguard v1.1.0
   Compiling rayon-core v1.9.1
   Compiling either v1.6.1
   Compiling memoffset v0.6.5
   Compiling rayon v1.5.1
   Compiling crossbeam-channel v0.5.2
   Compiling crossbeam-deque v0.8.1
   Compiling num_cpus v1.13.1
   Compiling bug v0.1.0 (/tmp/xx)
    Finished test [optimized + debuginfo] target(s) in 5.26s
   Doc-tests bug

running 1 test
test src/lib.rs - do_bug (line 6) ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.10s

$ cargo test --doc
    Finished test [optimized + debuginfo] target(s) in 0.01s
   Doc-tests bug

running 1 test
test src/lib.rs - do_bug (line 6) ... FAILED

failures:

---- src/lib.rs - do_bug (line 6) stdout ----
Test executable failed (terminated by signal).


failures:
    src/lib.rs - do_bug (line 6)

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.20s

error: test failed, to rerun pass '--doc'

Notes:

  • Sometimes it needs a few runs to crash
  • Cargo.toml enabled lto = "thin"; opt-level = 2 but be careful: rustdoc does not seem to pass opt-level = to test itself, only an lto part. That makes it a bit hard to reason about optimisation mix.

Attempt at fetching backtrace:

Thread 2 "rust_out" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffb9a360640 (LWP 662570)]
0x00007ffb9a35f8e8 in ?? ()
(gdb) bt
#0  0x00007ffb9a35f8e8 in ?? ()
#1  0x00007ffb9a3605f8 in ?? ()
#2  0x00007ffb9a35fa30 in ?? ()
#3  0x0000556a1c6df25c in rayon_core::registry::WorkerThread::set_current (thread=0x7ffb9a35f500) at /home/slyfox/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.1/src/registry.rs:636
#4  rayon_core::registry::main_loop (registry=..., index=0, worker=...) at /home/slyfox/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.1/src/registry.rs:807
#5  rayon_core::registry::ThreadBuilder::run (self=...) at /home/slyfox/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.1/src/registry.rs:55
#6  0x0000556a1c70206d in rayon_core::registry::{impl#2}::spawn::{closure#0} () at /home/slyfox/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-core-1.9.1/src/registry.rs:100
#7  std::sys_common::backtrace::__rust_begin_short_backtrace<rayon_core::registry::{impl#2}::spawn::{closure#0}, ()> (f=...) at /build/rustc-1.57.0-src/library/std/src/sys_common/backtrace.rs:123
#8  0x0000556a1c6e493c in std::thread::{impl#0}::spawn_unchecked::{closure#1}::{closure#0}<rayon_core::registry::{impl#2}::spawn::{closure#0}, ()> () at /build/rustc-1.57.0-src/library/std/src/thread/mod.rs:483
#9  core::panic::unwind_safe::{impl#23}::call_once<(), std::thread::{impl#0}::spawn_unchecked::{closure#1}::{closure#0}> (self=..., _args=<optimized out>)
    at /build/rustc-1.57.0-src/library/core/src/panic/unwind_safe.rs:271
#10 0x0000556a1c6e34cf in std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<std::thread::{impl#0}::spawn_unchecked::{closure#1}::{closure#0}>, ()> (data=<optimized out>)
    at /build/rustc-1.57.0-src/library/std/src/panicking.rs:403
#11 std::panicking::try<(), core::panic::unwind_safe::AssertUnwindSafe<std::thread::{impl#0}::spawn_unchecked::{closure#1}::{closure#0}>> (f=...) at /build/rustc-1.57.0-src/library/std/src/panicking.rs:367
#12 0x0000556a1c6fbb30 in std::panic::catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<std::thread::{impl#0}::spawn_unchecked::{closure#1}::{closure#0}>, ()> (f=...)
    at /build/rustc-1.57.0-src/library/std/src/panic.rs:133
#13 0x0000556a1c6da205 in std::thread::{impl#0}::spawn_unchecked::{closure#1}<rayon_core::registry::{impl#2}::spawn::{closure#0}, ()> () at /build/rustc-1.57.0-src/library/std/src/thread/mod.rs:482
#14 core::ops::function::FnOnce::call_once<std::thread::{impl#0}::spawn_unchecked::{closure#1}, ()> () at /build/rustc-1.57.0-src/library/core/src/ops/function.rs:227
#15 0x0000556a1c761515 in std::sys::unix::thread::Thread::new::thread_start ()
#16 0x00007ffb9a67cd40 in start_thread () from /nix/store/s9qbqh7gzacs7h68b2jfmn9l6q4jwfjz-glibc-2.33-59/lib/libpthread.so.0
#17 0x00007ffb9a46343f in clone () from /nix/store/s9qbqh7gzacs7h68b2jfmn9l6q4jwfjz-glibc-2.33-59/lib/libc.so.6

Echoing comment xiph/rav1e#2851 (comment) here:

"""
Specifically rayon-core-1.9.1/src/registry.rs:

    /// Sets `self` as the worker thread index for the current thread.
    /// This is done during worker thread startup.
    unsafe fn set_current(thread: *const WorkerThread) {
        WORKER_THREAD_STATE.with(|t| {
            assert!(t.get().is_null());
            t.set(thread);
        });
    }
...
unsafe fn main_loop(worker: Worker<JobRef>, registry: Arc<Registry>, index: usize) {
    let worker_thread = &WorkerThread {
        worker,
        fifo: JobFifo::new(),
        index,
        rng: XorShift64Star::new(),
        registry: registry.clone(),
    };
    WorkerThread::set_current(worker_thread);
...

Does rust guarantee that raw worker_thread will point to fully constructed object? Or could actual initialization move downward a bit?
"""

Thank you!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions