I'm hitting a lifetime error when compiling a change I made for Firecracker (on aarch64, but I doubt the issue is architecture-dependent):
error[E0716]: temporary value dropped while borrowed
--> src/vmm/src/device_manager/mmio.rs:174:24
|
174 | let int_evt = &serial
| ________________________^
175 | | .lock()
176 | | .expect("Poisoned legacy serial lock")
| |__________________________________________________^ creates a temporary which is freed while still in use
177 | .interrupt_evt();
| - temporary value is freed at the end of this statement
178 | vm.register_irqfd(int_evt, self.irq)
| ------- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
The original code (which compiles fine) is:
vm.register_irqfd(&serial
.lock()
.expect("Poisoned legacy serial lock")
.interrupt_evt(), self.irq)
.map_err(Error::RegisterIrqFd)?;
I don't understand the difference. The error message seems to state that expect() is returning a temporary and that I'm taking a const reference to it, in C++ this would extend the lifetime of the temporary, does it not in Rust? Either way, why does it work in the original code but not after I bind to an l-value (C++ parlance, I'm not sure if it is the same for Rust)?
I tried creating a SSCE here, but it worked as expected!
A simple, reproducible example of the problem (playground):
// create array inside mutex
let mutex = Mutex::new([ 0i32 ]);
// get reference to item inside array
let item: &i32 = mutex.lock().unwrap().get(0).unwrap();
// use reference for something
println!("item = {:?}", item);
mutex.lock().unwrap() returns a MutexGuard<'_, Option<i32>>, which borrows the data inside the mutex. It also owns a lock on the data, that is released when the guard is dropped, which means that noone else may borrow the data at the same time.
When you call a method of the inner type on that guard (like .get in the above example, or .interrupt_evt in your code), it will borrow with the lifetime of the guard, since you can only access the data safely while the guard exist. But the guard isn't stored in any variable, so it only exists temporarily for that statement, and is immediately dropped at the end of it. So you cannot get a reference to the data outside of the statement.
To solve this problem is very simple: first store the guard in a variable, and then borrow from it. That will ensure that the guard lives longer than the references you get from it (playground):
// create array inside mutex
let mutex = Mutex::new([ 0i32 ]);
// get reference to item inside array
let guard = mutex.lock().unwrap();
let item: &i32 = guard.get(0).unwrap();
// use reference for something
println!("item = {:?}", item);
// guard is now destroyed at end of scope
// and mutex lock is released here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With