diff --git a/tokio/src/sync/semaphore.rs b/tokio/src/sync/semaphore.rs index 8cccfab1b8e..317f8c39b8a 100644 --- a/tokio/src/sync/semaphore.rs +++ b/tokio/src/sync/semaphore.rs @@ -626,6 +626,10 @@ impl<'a> SemaphorePermit<'a> { /// /// Permits held by both `self` and `other` are released when `self` drops. pub fn merge(&mut self, mut other: Self) { + assert!( + std::ptr::eq(self.sem, other.sem), + "merging permits from different semaphore instances" + ); self.permits += other.permits; other.permits = 0; } @@ -644,6 +648,10 @@ impl OwnedSemaphorePermit { /// /// Permits held by both `self` and `other` are released when `self` drops. pub fn merge(&mut self, mut other: Self) { + assert!( + Arc::ptr_eq(&self.sem, &other.sem), + "merging permits from different semaphore instances" + ); self.permits += other.permits; other.permits = 0; } diff --git a/tokio/tests/sync_semaphore.rs b/tokio/tests/sync_semaphore.rs index 508d83fbde4..dfd2abaa218 100644 --- a/tokio/tests/sync_semaphore.rs +++ b/tokio/tests/sync_semaphore.rs @@ -77,6 +77,16 @@ fn merge() { assert_eq!(sem.available_permits(), 3); } +#[test] +#[should_panic] +fn merge_unrelated_permits() { + let sem1 = Arc::new(Semaphore::new(3)); + let sem2 = Arc::new(Semaphore::new(3)); + let mut p1 = sem1.try_acquire().unwrap(); + let p2 = sem2.try_acquire().unwrap(); + p1.merge(p2); +} + #[tokio::test] #[cfg(feature = "full")] async fn stress_test() { diff --git a/tokio/tests/sync_semaphore_owned.rs b/tokio/tests/sync_semaphore_owned.rs index 9c828ace3e1..0aa614e4d95 100644 --- a/tokio/tests/sync_semaphore_owned.rs +++ b/tokio/tests/sync_semaphore_owned.rs @@ -103,6 +103,16 @@ fn merge() { assert_eq!(sem.available_permits(), 3); } +#[test] +#[should_panic] +fn merge_unrelated_permits() { + let sem1 = Arc::new(Semaphore::new(3)); + let sem2 = Arc::new(Semaphore::new(3)); + let mut p1 = sem1.clone().try_acquire_owned().unwrap(); + let p2 = sem2.clone().try_acquire_owned().unwrap(); + p1.merge(p2) +} + #[tokio::test] #[cfg(feature = "full")] async fn stress_test() {