Arc<Mutex<T>>, Borrowed value does not live long enough

In the example below, it says openvpn_client does not live long enough. However, it is created before the on_poll_read and on_poll_write. Therefore, it should be destructed after them

use core::task::{Context, Poll};
use hyper::client::connect::{Connection, Connected};
use std::sync::{Arc, Mutex};

pub type OnPollRead = Arc<dyn Fn(&mut Context<'_>, &mut tokio::io::ReadBuf<'_>) -> Poll<std::io::Result<()>> + Send + Sync>;
pub type OnPollWrite = Arc<dyn Fn(&mut Context<'_>, &[u8]) -> Poll<core::result::Result<usize, std::io::Error>> + Send + Sync>;

#[derive(Clone)]
pub struct CustomTransporter {
    on_poll_read: Option<OnPollRead>,
    on_poll_write: Option<OnPollWrite>,
}

pub struct OVPNClient {
}

impl OVPNClient {
    pub fn send(&self, buffer: &[u8]) {
        
    }
}

unsafe impl Send for OVPNClient {}


unsafe impl Send for CustomTransporter {}

impl CustomTransporter {
    pub fn new(on_poll_read: Option<OnPollRead>, on_poll_write: Option<OnPollWrite>) -> CustomTransporter {
        CustomTransporter{
            on_poll_read: on_poll_read,
            on_poll_write: on_poll_write
        }
    }
}

fn main () {
    let openvpn_client = Arc::new(Mutex::new(OVPNClient{}));

    let on_poll_read = Arc::new(|context: &mut Context, buffer: &mut tokio::io::ReadBuf| -> Poll<std::io::Result<()>> {
        Poll::Ready(Ok(()))
    });

    let on_poll_write = Arc::new(|context: &mut Context, buffer: &[u8]| -> Poll<core::result::Result<usize, std::io::Error>>{
        openvpn_client.lock().unwrap().send(buffer);
        Poll::Ready(Ok(0))
    });

    let connector = CustomTransporter::new(Some(on_poll_read), Some(on_poll_write));
}

Error:

error[E0597]: `openvpn_client` does not live long enough
  --> src/main.rs:45:9
   |
44 |     let on_poll_write = Arc::new(|context: &mut Context, buffer: &[u8]| -> Poll<core::result::Result<usize, std::io::Error>>{
   |                                  ------------------------------------------------------------------------------------------- value captured here
45 |         openvpn_client.lock().unwrap().send(buffer);
   |         ^^^^^^^^^^^^^^ borrowed value does not live long enough
...
49 |     let connector = CustomTransporter::new(Some(on_poll_read), Some(on_poll_write));
   |                                                                     ------------- cast requires that `openvpn_client` is borrowed for `'static`
50 | }
   | - `openvpn_client` dropped here while still borrowed

Playground link: Rust Playground

You can fix this by adding the move keyword to move openvpn_client into the closure:

let on_poll_write = Arc::new(move |context: &mut Context, buffer: &[u8]| -> Poll<core::result::Result<usize, std::io::Error>>{
    openvpn_client.lock().unwrap().send(buffer);
    Poll::Ready(Ok(0))
});

playground

1 Like

makes sense. But shouldn't Rust be able to know that the openvpn_client was constructed before the closures and before the object that uses the closures? This object (connector), will be destructed before the openvpn_client because it was created after it, so there should be no problem

The error happened because Arc<dyn Fn(...)> has an implicit 'static bound, so it doesn't allow closures that contain references to local variables.

If you want to allow closures that borrow local variables, you could add a lifetime to your Arc types (but in most cases, this would defeat the purpose of using Arc, since the resulting Arc can't outlive the function that creates it): Playground

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.