Skip to content

Commit 9564052

Browse files
committed
Auto merge of #132738 - cuviper:channel-heap-init, r=<try>
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 #102246 try-job: test-various
2 parents b91a3a0 + 03383ad commit 9564052

File tree

2 files changed

+32
-4
lines changed

2 files changed

+32
-4
lines changed

library/std/src/sync/mpmc/list.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,14 @@ struct Block<T> {
6363

6464
impl<T> Block<T> {
6565
/// Creates an empty block.
66-
fn new() -> Block<T> {
66+
fn new() -> Box<Block<T>> {
6767
// SAFETY: This is safe because:
6868
// [1] `Block::next` (AtomicPtr) may be safely zero initialized.
6969
// [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4].
7070
// [3] `Slot::msg` (UnsafeCell) may be safely zero initialized because it
7171
// holds a MaybeUninit.
7272
// [4] `Slot::state` (AtomicUsize) may be safely zero initialized.
73-
unsafe { MaybeUninit::zeroed().assume_init() }
73+
unsafe { Box::new_zeroed().assume_init() }
7474
}
7575

7676
/// Waits until the next pointer is set.
@@ -199,13 +199,13 @@ impl<T> Channel<T> {
199199
// If we're going to have to install the next block, allocate it in advance in order to
200200
// make the wait for other threads as short as possible.
201201
if offset + 1 == BLOCK_CAP && next_block.is_none() {
202-
next_block = Some(Box::new(Block::<T>::new()));
202+
next_block = Some(Block::<T>::new());
203203
}
204204

205205
// If this is the first message to be sent into the channel, we need to allocate the
206206
// first block and install it.
207207
if block.is_null() {
208-
let new = Box::into_raw(Box::new(Block::<T>::new()));
208+
let new = Box::into_raw(Block::<T>::new());
209209

210210
if self
211211
.tail
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//@ run-pass
2+
//@ compile-flags: -Copt-level=0
3+
4+
// The channel's `Block::new` was causing a stack overflow because it held 32 item slots, which is
5+
// 1MiB for this test's `BigStruct` -- instantiated on the stack before moving to `Box::new`.
6+
//
7+
// That block is now initialized directly on the heap.
8+
//
9+
// Ref: https://github.com/rust-lang/rust/issues/102246
10+
11+
use std::sync::mpsc::channel;
12+
use std::thread;
13+
14+
const N: usize = 32_768;
15+
struct BigStruct {
16+
_data: [u8; N],
17+
}
18+
19+
fn main() {
20+
let (sender, receiver) = channel::<BigStruct>();
21+
22+
let thread1 = thread::spawn(move || {
23+
sender.send(BigStruct { _data: [0u8; N] }).unwrap();
24+
});
25+
26+
thread1.join().unwrap();
27+
for _data in receiver.try_iter() {}
28+
}

0 commit comments

Comments
 (0)