From 01ca0d1f680cf5aab5d1a81fea9de56d591f6658 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Fri, 3 Aug 2012 11:43:10 -0700 Subject: [PATCH] Be more defensive in pipes (#3098) --- src/libcore/option.rs | 4 ++-- src/libcore/pipes.rs | 19 +++++++++++++------ src/rt/rust_task.cpp | 3 +++ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index bb5cca90cd094..935d22fbaae4a 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -127,9 +127,9 @@ fn swap_unwrap(opt: &mut option) -> T { unwrap(util::replace(opt, none)) } -pure fn unwrap_expect(-opt: option, reason: ~str) -> T { +pure fn unwrap_expect(-opt: option, reason: &str) -> T { //! As unwrap, but with a specified failure message. - if opt.is_none() { fail reason; } + if opt.is_none() { fail reason.to_unique(); } unwrap(opt) } diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index c1f39a9470ca6..6df6df9a6bb20 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -343,7 +343,7 @@ Fails if the sender closes the connection. */ fn recv(-p: recv_packet_buffered) -> T { - option::unwrap(try_recv(p)) + option::unwrap_expect(try_recv(p), "connection closed") } /** Attempts to receive a message from a pipe. @@ -391,10 +391,13 @@ fn try_recv(-p: recv_packet_buffered) full { let mut payload = none; payload <-> p.payload; + p.header.blocked_task = none; p.header.state = empty; return some(option::unwrap(payload)) } terminated { + // This assert detects when we've accidentally unsafely + // casted too big of a number to a state. assert old_state == terminated; return none; } @@ -428,10 +431,13 @@ fn sender_terminate(p: *packet) { } blocked { // wake up the target - let target = p.header.blocked_task.get(); - rustrt::task_signal_event(target, - ptr::addr_of(p.header) as *libc::c_void); - + alt p.header.blocked_task { + some(target) => + rustrt::task_signal_event( + target, + ptr::addr_of(p.header) as *libc::c_void), + none => { debug!{"receiver is already shutting down"} } + } // The receiver will eventually clean up. //unsafe { forget(p) } } @@ -448,6 +454,7 @@ fn sender_terminate(p: *packet) { #[doc(hidden)] fn receiver_terminate(p: *packet) { let p = unsafe { &*p }; + assert p.header.blocked_task == none; alt swap_state_rel(p.header.state, terminated) { empty { // the sender will clean up @@ -514,7 +521,7 @@ fn wait_many(pkts: &[*packet_header]) -> uint { for pkts.each |p| { unsafe{ (*p).unblock()} } - debug!{"%?, %?", ready_packet, pkts[ready_packet]}; + debug!("%?, %?", ready_packet, pkts[ready_packet]); unsafe { assert (*pkts[ready_packet]).state == full diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index 061e87ebff82d..ad2e8a71ae5f5 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -680,6 +680,9 @@ void rust_task::signal_event(void *event) { scoped_lock with(lifecycle_lock); + assert(task_state_blocked == state || + task_state_running == state); + this->event = event; event_reject = true; if(task_state_blocked == state) {