Rust if let =, seems to leak the RHS function result on Ubuntu Linux, is this expected?

Viewed 104

I have the following code, which runs fine on Mac and Windows, but panics on Ubuntu Linux. The panic is at the borrow_mut and the indication is that server is already immutably borrowed. That would seem to indicate that the if leaked the server borrow, which I wasn't expecting it to do. I then wrapped the 3 ifs within a { } and Ubuntu Linux no longer panics. Which I think proves that the if leaked the borrow. Am I wrong? is this expected? Or, is there something else going on with Rust and AtomicRefCell that I'm unaware of?

AtomicRefCell comes from atomic_refcell.

static server: AtomicRefCell<Server> = AtomicRefCell::new(Server {..});
...
if let ServerField::Executor(executor) = &server.borrow().executor {
    executor.stop();
}
if let ServerField::Scheduler(scheduler) = &server.borrow().scheduler {
    scheduler.stop()
}
if let ServerField::Monitor(monitor) = &server.borrow().monitor {
    monitor.stop()
}
let mut s = server.borrow_mut();
...

Here's the code that works with all 3 platforms:

// ensure that server.borrows don't leak out.
{
    if let ServerField::Executor(executor) = &server.borrow().executor {
        executor.stop();
    }
    if let ServerField::Scheduler(scheduler) = &server.borrow().scheduler {
        scheduler.stop()
    }
    if let ServerField::Monitor(monitor) = &server.borrow().monitor {
        monitor.stop()
    }
}
let mut s = server.borrow_mut();
...

Here is a complete impl to illustrate the problem. main.rs:

use atomic_refcell::AtomicRefCell;

#[allow(non_upper_case_globals)]
static server: AtomicRefCell<Server> = AtomicRefCell::new(Server {
    value: ServerField::Uninitialized,
});

#[derive(Debug)]
pub struct Server {
    value: ServerField,
}

#[derive(Debug)]
enum ServerField {
    Uninitialized,
    Value(usize),
}

fn start() {
    server.borrow_mut().value = ServerField::Value(41);
}

fn stop() {
    // enclose this in a scope to not panic
    let borrow = &server.borrow();
    println!("value is {:#?}", borrow.value);
    drop(borrow);
    // end scope
    let mut s = server.borrow_mut();
    s.value = ServerField::Uninitialized;
}

fn main() {
    println!("Hello, world!");
    start();
    stop();
}
#[cfg(test)]
pub mod tests {
    use super::*;
    #[test]
    fn test() {
        start();
        stop();
    }
}

Add this to your Cargo.toml:

[dependencies]
atomic_refcell = "0.1"

In this example an if let is employed with a RHS of &server.borrow().value, which doesn't panic on Mac but may panic on Ubuntu Linux (I don't have a Linux box, and didn't upload to GitHub and create a workflow). However, this mirrors my code that I do have on GitHub with a workflow, where it showed that behavior.

use atomic_refcell::AtomicRefCell;

#[allow(non_upper_case_globals)]
static server: AtomicRefCell<Server> = AtomicRefCell::new(Server {
    value: ServerField::Uninitialized,
});

#[derive(Debug)]
pub struct Server {
    value: ServerField,
}

#[derive(Debug)]
enum ServerField {
    Uninitialized,
    Value(usize),
}

fn start() {
    server.borrow_mut().value = ServerField::Value(41);
}

fn stop() {
    if let ServerField::Value(val) = &server.borrow().value {
        println!("value is {:#?}", val);
    }
    let mut s = server.borrow_mut();
    s.value = ServerField::Uninitialized;
}

fn main() {
    println!("Hello, world!");
    start();
    stop();
}
#[cfg(test)]
pub mod tests {
    use super::*;
    #[test]
    fn test_start_stop() {
        start();
        stop();
    }
}
0 Answers
Related