-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Stack overflow for big types in mpsc channels on separate thread #102246
Comments
I've run into this when upgrading from |
I've not been able to reproduce this using the program in the OP. I've tried on both rustc 1.73.0-nightly (439d066bc 2023-08-10)
binary: rustc
commit-hash: 439d066bcf9496b1b8c8dde8bef3bce607a621bb
commit-date: 2023-08-10
host: x86_64-pc-windows-msvc
release: 1.73.0-nightly
LLVM version: 17.0.0 |
@ChrisDenton OP's didn't trigger it for me either, but after playing with it I was able to reproduce: Reprouse std::sync::mpsc::*;
struct BigStruct {
_data: [u8; 32768],
}
fn main() {
let (sender, receiver) = channel::<BigStruct>();
let thread1 = std::thread::spawn(move || {
let data = BigStruct { _data: [0u8; 32768] };
sender.send(data).unwrap();
});
thread1.join().unwrap();
for _data in receiver.try_iter() {
}
println!("Done :)");
} Output
|
Also this may be system dependent, but I was playing with slice sizes and the trigger seems to be |
Ok, I've not yet investigated but my guess would be something about how it's not being optimized in @ibraheemdev might have some ideas. Note though this only affects |
The reproduer can be simplifed to: // We must keep receiver alive
#[allow(unused_variables)]
fn main() {
let (sender, receiver) = std::sync::mpsc::channel::<[u8; 32768]>();
let thread = std::thread::spawn(move || {
sender.send([0u8; 32768]).unwrap();
});
thread.join().unwrap();
println!("Done :)");
} Regressed versionsThe code runs fine in debug builds with 1.66 but not with 1.67. So this is a regression-from-stable-to-stable, but arguably not very severe since this seemingly has gone mostly unnoticed for a considerable amount of time. With
of which #93563 seems most likely. To demonstrate: for toolchain in 1.66 \
1.67 \
nightly-2022-11-13 \
nightly-2022-11-14 ; do
rm -rf target
echo "\nUsing $toolchain"
cargo +$toolchain run --quiet
done
DisassemblyThe disassembly of
So we SIGSEGV when In the LLVM IR we can find:
I looked at the MIR too but couldn't find anything suspicious. Maybe someone used to debuggging monomorphization/codegen can easily find out why the stack grows by 2MB. My system$ cargo +1.67 rustc -- -vV
rustc 1.67.1 (d5a82bbd2 2023-02-07)
binary: rustc
commit-hash: d5a82bbd26e1ad8b7401f6a718a9c57c96905483
commit-date: 2023-02-07
host: x86_64-unknown-linux-gnu
release: 1.67.1
LLVM version: 15.0.6
$ uname -a
Linux martins-dator 5.15.153.1-microsoft-standard-WSL2 #1 SMP Fri Mar 29 23:14:13 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux |
The cause seems to be due to the definition of |
The channel's `Block::new` was causing a stack overflow because it held 32 item slots, instantiated on the stack before moving to `Box::new`. The 32x multiplier made modestly-large item sizes untenable. That block is now initialized directly on the heap. Fixes rust-lang#102246
See #132738
I'll bet in release mode the optimizer was figuring out that direct initialization, since it knows about heap allocations. There will remain some unstated limitation on item size due to copies in the call stack, especially in debug mode when it's not inlined, but at least we won't have that multiplier from the |
The list channel's `Block::new` was causing a stack overflow because it held 32 item slots, instantiated on the stack before moving to `Box::new`. The 32x multiplier made modestly-large item sizes untenable. That block is now initialized directly on the heap. References from the `std` channel implementation: * rust-lang/rust#102246 * rust-lang/rust#132738
…eemdev Initialize channel `Block`s directly on the heap The channel's `Block::new` was causing a stack overflow because it held 32 item slots, instantiated on the stack before moving to `Box::new`. The 32x multiplier made modestly-large item sizes untenable. That block is now initialized directly on the heap. Fixes rust-lang#102246
The list channel's `Block::new` was causing a stack overflow because it held 32 item slots, instantiated on the stack before moving to `Box::new`. The 32x multiplier made modestly-large item sizes untenable. That block is now initialized directly on the heap. References from the `std` channel implementation: * rust-lang/rust#102246 * rust-lang/rust#132738
Initialize channel `Block`s directly on the heap The channel's `Block::new` was causing a stack overflow because it held 32 item slots, instantiated on the stack before moving to `Box::new`. The 32x multiplier made modestly-large item sizes untenable. That block is now initialized directly on the heap. Fixes rust-lang#102246 try-job: test-various
The list channel's `Block::new` was causing a stack overflow because it held 32 item slots, instantiated on the stack before moving to `Box::new`. The 32x multiplier made modestly-large item sizes untenable. That block is now initialized directly on the heap. References from the `std` channel implementation: * rust-lang/rust#102246 * rust-lang/rust#132738
…eemdev Initialize channel `Block`s directly on the heap The channel's `Block::new` was causing a stack overflow because it held 32 item slots, instantiated on the stack before moving to `Box::new`. The 32x multiplier made modestly-large item sizes untenable. That block is now initialized directly on the heap. Fixes rust-lang#102246 try-job: test-various
Rollup merge of rust-lang#132738 - cuviper:channel-heap-init, r=ibraheemdev Initialize channel `Block`s directly on the heap The channel's `Block::new` was causing a stack overflow because it held 32 item slots, instantiated on the stack before moving to `Box::new`. The 32x multiplier made modestly-large item sizes untenable. That block is now initialized directly on the heap. Fixes rust-lang#102246 try-job: test-various
…eemdev Initialize channel `Block`s directly on the heap The channel's `Block::new` was causing a stack overflow because it held 32 item slots, instantiated on the stack before moving to `Box::new`. The 32x multiplier made modestly-large item sizes untenable. That block is now initialized directly on the heap. Fixes rust-lang#102246 try-job: test-various
The list channel's `Block::new` was causing a stack overflow because it held 32 item slots, instantiated on the stack before moving to `Box::new`. The 32x multiplier made modestly-large item sizes untenable. That block is now initialized directly on the heap. References from the `std` channel implementation: * rust-lang/rust#102246 * rust-lang/rust#132738
The list channel's `Block::new` was causing a stack overflow because it held 32 item slots, instantiated on the stack before moving to `Box::new`. The 32x multiplier made modestly-large item sizes untenable. That block is now initialized directly on the heap. References from the `std` channel implementation: * rust-lang/rust#102246 * rust-lang/rust#132738
I tried this code:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7ebdbceac5477ebb48a65f5ecacb5c62
I expected to see this happen:
The program shouldn't do much beside printing a friendly message.
Instead, this happened:
When running in Debug mode, the program crashes due to a stack overflow. In release mode it behaves as expected. Looping over the data in the receiver in combination with being on a separate thread triggers it.
I tried running on nightly too, which produces the same results.
I've now switched to crossbeam as a workaround, which does not suffer from the same issue fortunately.
rustc --version --verbose
:Backtrace
The text was updated successfully, but these errors were encountered: