Skip to content

Commit e3c3a56

Browse files
committed
Merge branch 'tokio-1.43.x' into forward-port-1.43.x
2 parents d413c9c + a7b658c commit e3c3a56

File tree

4 files changed

+73
-54
lines changed

4 files changed

+73
-54
lines changed

Diff for: .github/workflows/ci.yml

+18-3
Original file line numberDiff line numberDiff line change
@@ -475,10 +475,18 @@ jobs:
475475
runs-on: ubuntu-latest
476476
steps:
477477
- uses: actions/checkout@v4
478-
- name: Check semver
478+
- name: Check `tokio` semver
479479
uses: obi1kenobi/cargo-semver-checks-action@v2
480480
with:
481481
rust-toolchain: ${{ env.rust_stable }}
482+
package: tokio
483+
release-type: minor
484+
- name: Check semver for rest of the workspace
485+
if: ${{ !startsWith(github.event.pull_request.base.ref, 'tokio-1.') }}
486+
uses: obi1kenobi/cargo-semver-checks-action@v2
487+
with:
488+
rust-toolchain: ${{ env.rust_stable }}
489+
exclude: tokio
482490
release-type: minor
483491

484492
cross-check:
@@ -718,7 +726,14 @@ jobs:
718726
toolchain: ${{ env.rust_min }}
719727
- uses: Swatinem/rust-cache@v2
720728
- name: "check --workspace --all-features"
721-
run: cargo check --workspace --all-features
729+
run: |
730+
if [[ "${{ github.event.pull_request.base.ref }}" =~ ^tokio-1\..* ]]; then
731+
# Only check `tokio` crate as the PR is backporting to an earlier tokio release.
732+
cargo check -p tokio --all-features
733+
else
734+
# Check all crates in the workspace
735+
cargo check --workspace --all-features
736+
fi
722737
env:
723738
RUSTFLAGS: "" # remove -Dwarnings
724739

@@ -1014,7 +1029,7 @@ jobs:
10141029
targets: ${{ matrix.target }}
10151030

10161031
# Install dependencies
1017-
- name: Install cargo-hack, wasmtime, and cargo-wasi
1032+
- name: Install cargo-hack, wasmtime
10181033
uses: taiki-e/install-action@v2
10191034
with:
10201035
tool: cargo-hack,wasmtime

Diff for: tokio/CHANGELOG.md

+28
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,20 @@ comment on [#7172].
8585
[#7186]: https://github.com/tokio-rs/tokio/pull/7186
8686
[#7192]: https://github.com/tokio-rs/tokio/pull/7192
8787

88+
# 1.43.1 (April 2nd, 2025)
89+
90+
This release fixes a soundness issue in the broadcast channel. The channel
91+
accepts values that are `Send` but `!Sync`. Previously, the channel called
92+
`clone()` on these values without synchronizing. This release fixes the channel
93+
by synchronizing calls to `.clone()` (Thanks Austin Bonander for finding and
94+
reporting the issue).
95+
96+
### Fixed
97+
98+
- sync: synchronize `clone()` call in broadcast channel ([#7232])
99+
100+
[#7232]: https://github.com/tokio-rs/tokio/pull/7232
101+
88102
# 1.43.0 (Jan 8th, 2025)
89103

90104
### Added
@@ -390,6 +404,20 @@ Yanked. Please use 1.39.1 instead.
390404
[#6709]: https://github.com/tokio-rs/tokio/pull/6709
391405
[#6710]: https://github.com/tokio-rs/tokio/pull/6710
392406

407+
# 1.38.2 (April 2nd, 2025)
408+
409+
This release fixes a soundness issue in the broadcast channel. The channel
410+
accepts values that are `Send` but `!Sync`. Previously, the channel called
411+
`clone()` on these values without synchronizing. This release fixes the channel
412+
by synchronizing calls to `.clone()` (Thanks Austin Bonander for finding and
413+
reporting the issue).
414+
415+
### Fixed
416+
417+
- sync: synchronize `clone()` call in broadcast channel ([#7232])
418+
419+
[#7232]: https://github.com/tokio-rs/tokio/pull/7232
420+
393421
# 1.38.1 (July 16th, 2024)
394422

395423
This release fixes the bug identified as ([#6682]), which caused timers not

Diff for: tokio/src/runtime/tests/queue.rs

-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::runtime::scheduler::multi_thread::{queue, Stats};
2-
use crate::runtime::task::{self, Schedule, Task, TaskHarnessScheduleHooks};
32

43
use std::cell::RefCell;
54
use std::thread;
@@ -272,22 +271,3 @@ fn stress2() {
272271
assert_eq!(num_pop, NUM_TASKS);
273272
}
274273
}
275-
276-
#[allow(dead_code)]
277-
struct Runtime;
278-
279-
impl Schedule for Runtime {
280-
fn release(&self, _task: &Task<Self>) -> Option<Task<Self>> {
281-
None
282-
}
283-
284-
fn schedule(&self, _task: task::Notified<Self>) {
285-
unreachable!();
286-
}
287-
288-
fn hooks(&self) -> TaskHarnessScheduleHooks {
289-
TaskHarnessScheduleHooks {
290-
task_terminate_callback: None,
291-
}
292-
}
293-
}

Diff for: tokio/src/sync/broadcast.rs

+27-31
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@
118118
119119
use crate::loom::cell::UnsafeCell;
120120
use crate::loom::sync::atomic::{AtomicBool, AtomicUsize};
121-
use crate::loom::sync::{Arc, Mutex, MutexGuard, RwLock, RwLockReadGuard};
121+
use crate::loom::sync::{Arc, Mutex, MutexGuard};
122122
use crate::task::coop::cooperative;
123123
use crate::util::linked_list::{self, GuardedLinkedList, LinkedList};
124124
use crate::util::WakeList;
@@ -340,7 +340,7 @@ use super::Notify;
340340
/// Data shared between senders and receivers.
341341
struct Shared<T> {
342342
/// slots in the channel.
343-
buffer: Box<[RwLock<Slot<T>>]>,
343+
buffer: Box<[Mutex<Slot<T>>]>,
344344

345345
/// Mask a position -> index.
346346
mask: usize,
@@ -390,7 +390,7 @@ struct Slot<T> {
390390
///
391391
/// The value is set by `send` when the write lock is held. When a reader
392392
/// drops, `rem` is decremented. When it hits zero, the value is dropped.
393-
val: UnsafeCell<Option<T>>,
393+
val: Option<T>,
394394
}
395395

396396
/// An entry in the wait queue.
@@ -428,7 +428,7 @@ generate_addr_of_methods! {
428428
}
429429

430430
struct RecvGuard<'a, T> {
431-
slot: RwLockReadGuard<'a, Slot<T>>,
431+
slot: MutexGuard<'a, Slot<T>>,
432432
}
433433

434434
/// Receive a value future.
@@ -437,11 +437,15 @@ struct Recv<'a, T> {
437437
receiver: &'a mut Receiver<T>,
438438

439439
/// Entry in the waiter `LinkedList`.
440-
waiter: UnsafeCell<Waiter>,
440+
waiter: WaiterCell,
441441
}
442442

443-
unsafe impl<'a, T: Send> Send for Recv<'a, T> {}
444-
unsafe impl<'a, T: Send> Sync for Recv<'a, T> {}
443+
// The wrapper around `UnsafeCell` isolates the unsafe impl `Send` and `Sync`
444+
// from `Recv`.
445+
struct WaiterCell(UnsafeCell<Waiter>);
446+
447+
unsafe impl Send for WaiterCell {}
448+
unsafe impl Sync for WaiterCell {}
445449

446450
/// Max number of receivers. Reserve space to lock.
447451
const MAX_RECEIVERS: usize = usize::MAX >> 2;
@@ -509,15 +513,6 @@ pub fn channel<T: Clone>(capacity: usize) -> (Sender<T>, Receiver<T>) {
509513
(tx, rx)
510514
}
511515

512-
unsafe impl<T: Send> Send for Sender<T> {}
513-
unsafe impl<T: Send> Sync for Sender<T> {}
514-
515-
unsafe impl<T: Send> Send for WeakSender<T> {}
516-
unsafe impl<T: Send> Sync for WeakSender<T> {}
517-
518-
unsafe impl<T: Send> Send for Receiver<T> {}
519-
unsafe impl<T: Send> Sync for Receiver<T> {}
520-
521516
impl<T> Sender<T> {
522517
/// Creates the sending-half of the [`broadcast`] channel.
523518
///
@@ -556,10 +551,10 @@ impl<T> Sender<T> {
556551
let mut buffer = Vec::with_capacity(capacity);
557552

558553
for i in 0..capacity {
559-
buffer.push(RwLock::new(Slot {
554+
buffer.push(Mutex::new(Slot {
560555
rem: AtomicUsize::new(0),
561556
pos: (i as u64).wrapping_sub(capacity as u64),
562-
val: UnsafeCell::new(None),
557+
val: None,
563558
}));
564559
}
565560

@@ -647,7 +642,7 @@ impl<T> Sender<T> {
647642
tail.pos = tail.pos.wrapping_add(1);
648643

649644
// Get the slot
650-
let mut slot = self.shared.buffer[idx].write();
645+
let mut slot = self.shared.buffer[idx].lock();
651646

652647
// Track the position
653648
slot.pos = pos;
@@ -656,7 +651,7 @@ impl<T> Sender<T> {
656651
slot.rem.with_mut(|v| *v = rem);
657652

658653
// Write the value
659-
slot.val = UnsafeCell::new(Some(value));
654+
slot.val = Some(value);
660655

661656
// Release the slot lock before notifying the receivers.
662657
drop(slot);
@@ -755,7 +750,7 @@ impl<T> Sender<T> {
755750
while low < high {
756751
let mid = low + (high - low) / 2;
757752
let idx = base_idx.wrapping_add(mid) & self.shared.mask;
758-
if self.shared.buffer[idx].read().rem.load(SeqCst) == 0 {
753+
if self.shared.buffer[idx].lock().rem.load(SeqCst) == 0 {
759754
low = mid + 1;
760755
} else {
761756
high = mid;
@@ -797,7 +792,7 @@ impl<T> Sender<T> {
797792
let tail = self.shared.tail.lock();
798793

799794
let idx = (tail.pos.wrapping_sub(1) & self.shared.mask as u64) as usize;
800-
self.shared.buffer[idx].read().rem.load(SeqCst) == 0
795+
self.shared.buffer[idx].lock().rem.load(SeqCst) == 0
801796
}
802797

803798
/// Returns the number of active receivers.
@@ -1230,7 +1225,7 @@ impl<T> Receiver<T> {
12301225
let idx = (self.next & self.shared.mask as u64) as usize;
12311226

12321227
// The slot holding the next value to read
1233-
let mut slot = self.shared.buffer[idx].read();
1228+
let mut slot = self.shared.buffer[idx].lock();
12341229

12351230
if slot.pos != self.next {
12361231
// Release the `slot` lock before attempting to acquire the `tail`
@@ -1247,7 +1242,7 @@ impl<T> Receiver<T> {
12471242
let mut tail = self.shared.tail.lock();
12481243

12491244
// Acquire slot lock again
1250-
slot = self.shared.buffer[idx].read();
1245+
slot = self.shared.buffer[idx].lock();
12511246

12521247
// Make sure the position did not change. This could happen in the
12531248
// unlikely event that the buffer is wrapped between dropping the
@@ -1581,12 +1576,12 @@ impl<'a, T> Recv<'a, T> {
15811576
fn new(receiver: &'a mut Receiver<T>) -> Recv<'a, T> {
15821577
Recv {
15831578
receiver,
1584-
waiter: UnsafeCell::new(Waiter {
1579+
waiter: WaiterCell(UnsafeCell::new(Waiter {
15851580
queued: AtomicBool::new(false),
15861581
waker: None,
15871582
pointers: linked_list::Pointers::new(),
15881583
_p: PhantomPinned,
1589-
}),
1584+
})),
15901585
}
15911586
}
15921587

@@ -1598,7 +1593,7 @@ impl<'a, T> Recv<'a, T> {
15981593
is_unpin::<&mut Receiver<T>>();
15991594

16001595
let me = self.get_unchecked_mut();
1601-
(me.receiver, &me.waiter)
1596+
(me.receiver, &me.waiter.0)
16021597
}
16031598
}
16041599
}
@@ -1632,6 +1627,7 @@ impl<'a, T> Drop for Recv<'a, T> {
16321627
// `Shared::notify_rx` before we drop the object.
16331628
let queued = self
16341629
.waiter
1630+
.0
16351631
.with(|ptr| unsafe { (*ptr).queued.load(Acquire) });
16361632

16371633
// If the waiter is queued, we need to unlink it from the waiters list.
@@ -1646,6 +1642,7 @@ impl<'a, T> Drop for Recv<'a, T> {
16461642
// `Relaxed` order suffices because we hold the tail lock.
16471643
let queued = self
16481644
.waiter
1645+
.0
16491646
.with_mut(|ptr| unsafe { (*ptr).queued.load(Relaxed) });
16501647

16511648
if queued {
@@ -1654,7 +1651,7 @@ impl<'a, T> Drop for Recv<'a, T> {
16541651
// safety: tail lock is held and the wait node is verified to be in
16551652
// the list.
16561653
unsafe {
1657-
self.waiter.with_mut(|ptr| {
1654+
self.waiter.0.with_mut(|ptr| {
16581655
tail.waiters.remove((&mut *ptr).into());
16591656
});
16601657
}
@@ -1706,16 +1703,15 @@ impl<'a, T> RecvGuard<'a, T> {
17061703
where
17071704
T: Clone,
17081705
{
1709-
self.slot.val.with(|ptr| unsafe { (*ptr).clone() })
1706+
self.slot.val.clone()
17101707
}
17111708
}
17121709

17131710
impl<'a, T> Drop for RecvGuard<'a, T> {
17141711
fn drop(&mut self) {
17151712
// Decrement the remaining counter
17161713
if 1 == self.slot.rem.fetch_sub(1, SeqCst) {
1717-
// Safety: Last receiver, drop the value
1718-
self.slot.val.with_mut(|ptr| unsafe { *ptr = None });
1714+
self.slot.val = None;
17191715
}
17201716
}
17211717
}

0 commit comments

Comments
 (0)