From 0f25ccb7c3bc9f65fa8eaf538233e8fe344a189a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 2 Sep 2015 20:31:33 +0530 Subject: [PATCH 1/3] Add destructor bombs --- src/lib.rs | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 211e464..2cc5fa1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -161,10 +161,37 @@ pub enum Branch { Right(R) } +impl Drop for Chan { + fn drop(&mut self) { + panic!("Session channel prematurely dropped"); + } +} + impl Chan { /// Close a channel. Should always be used at the end of your program. - pub fn close(self) { - // Consume `c` + pub fn close(mut self) { + // This method cleans up the channel without running the panicky destructor + // In essence, it calls the drop glue bypassing the `Drop::drop` method + use std::mem; + + // Create some dummy values to place the real things inside + // This is safe because nobody will read these + // mem::swap uses a similar technique (also paired with `forget()`) + let mut sender = unsafe { mem::uninitialized() }; + let mut receiver = unsafe { mem::uninitialized() }; + + // Extract the internal sender/receiver so that we can drop them + // We cannot drop directly since moving out of a type + // that implements `Drop` is disallowed + mem::swap(&mut self.0, &mut sender); + mem::swap(&mut self.1, &mut receiver); + + drop(sender);drop(receiver); // drop them + + // Ensure Chan destructors don't run so that we don't panic + // This also ensures that the uninitialized values don't get + // read at any point + mem::forget(self); } } From f75967ddbb27c77e3f04f9ae10cdc851dd99657c Mon Sep 17 00:00:00 2001 From: Philip Munksgaard Date: Tue, 1 Sep 2015 17:35:34 -0700 Subject: [PATCH 2/3] Fix the documentation tests to handle destructor bombs The documentation tests were not correctly closing all of their channels, and with the newly introduced destructor bombs they fail horribly. This fixes the tests, but the result turns out to be exceptionally ugly, and we should definitely try to come up with some better examples that showcase the `chan_select!` macros without being horribly verbose about closing channels. cc: @laumann --- src/lib.rs | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2cc5fa1..b9f1ff1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -588,18 +588,16 @@ macro_rules! offer { /// spawn(move|| send_str(tcs)); /// spawn(move|| send_usize(tcu)); /// -/// loop { -/// chan_select! { -/// (c, s) = rcs.recv() => { -/// assert_eq!("Hello, World!".to_string(), s); -/// c.close(); -/// break -/// }, -/// (c, i) = rcu.recv() => { -/// assert_eq!(42, i); -/// c.close(); -/// break -/// } +/// chan_select! { +/// (c, s) = rcs.recv() => { +/// assert_eq!("Hello, World!".to_string(), s); +/// c.close(); +/// rcu.recv().0.close(); +/// }, +/// (c, i) = rcu.recv() => { +/// assert_eq!(42, i); +/// c.close(); +/// rcs.recv().0.close(); /// } /// } /// } @@ -625,17 +623,33 @@ macro_rules! offer { /// let (c, s) = chan_one.recv(); /// assert_eq!("Hello, World!".to_string(), s); /// c.close(); +/// match chan_two.offer() { +/// Left(c) => c.recv().0.close(), +/// Right(c) => c.recv().0.close(), +/// } /// }, /// Number => { -/// unreachable!() +/// chan_one.recv().0.close(); +/// match chan_two.offer() { +/// Left(c) => c.recv().0.close(), +/// Right(c) => c.recv().0.close(), +/// } /// } /// }, /// _ign = chan_two.offer() => { /// String => { -/// unreachable!() +/// chan_two.recv().0.close(); +/// match chan_one.offer() { +/// Left(c) => c.recv().0.close(), +/// Right(c) => c.recv().0.close(), +/// } /// }, /// Number => { -/// unreachable!() +/// chan_two.recv().0.close(); +/// match chan_one.offer() { +/// Left(c) => c.recv().0.close(), +/// Right(c) => c.recv().0.close(), +/// } /// } /// } /// } @@ -649,6 +663,8 @@ macro_rules! offer { /// let (ca1, ca2) = session_channel(); /// let (cb1, cb2) = session_channel(); /// +/// cb2.sel2().send(42).close(); +/// /// spawn(move|| cli(ca2)); /// /// srv(ca1, cb1); From 20d8d68f003e0f5794fcd950363950a787ef7f18 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 2 Sep 2015 20:32:20 +0530 Subject: [PATCH 3/3] fix unused_mutable warning --- examples/echo-server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/echo-server.rs b/examples/echo-server.rs index 2596ad8..f4a4185 100644 --- a/examples/echo-server.rs +++ b/examples/echo-server.rs @@ -32,7 +32,7 @@ fn srv(c: Chan<(), Rec>) { type Cli = ::Dual; fn cli(c: Chan<(), Rec>) { - let mut stdin = std::io::stdin(); + let stdin = std::io::stdin(); let mut count = 0usize; let mut c = c.enter();