What are scoping rules for temporary objects inside function call in Rust? What I actually interested in whether it is safe to do following:
fn foo() -> CString { /* */ }
fn bar(arg: *const libc::c_char) { /* */ }
bar(foo().as_ptr())
I created minimal example, and it works as I want -- object is dropped after function call returns.
struct Bar {
pub x: u32
}
impl Bar {
pub fn new(x: u32) -> Self {
println!("New Bar made!");
Bar { x }
}
pub fn extract(&self) -> u32{
self.x
}
}
impl Drop for Bar {
fn drop(&mut self) {
println!("Bar dropped!");
}
}
pub fn foo(arg: u32) {
println!("Function called with arg = {}", arg);
}
fn main () {
foo(Bar::new(12).extract());
}
Can I rely on this behaviour?
In the rust reference, under 'Temporary Lifetimes', it says:
... the lifetime of temporary values is typically
the innermost enclosing statement; the tail expression of a block is considered part of the statement that encloses the block, or
The innermost enclosing statement in your case is the call to bar( ). There are examples in the same section very similar to your case.
The compiler would not have compiled your code if this were not the case.
Related
What are scoping rules for temporary objects inside function call in Rust? What I actually interested in whether it is safe to do following:
fn foo() -> CString { /* */ }
fn bar(arg: *const libc::c_char) { /* */ }
bar(foo().as_ptr())
I created minimal example, and it works as I want -- object is dropped after function call returns.
struct Bar {
pub x: u32
}
impl Bar {
pub fn new(x: u32) -> Self {
println!("New Bar made!");
Bar { x }
}
pub fn extract(&self) -> u32{
self.x
}
}
impl Drop for Bar {
fn drop(&mut self) {
println!("Bar dropped!");
}
}
pub fn foo(arg: u32) {
println!("Function called with arg = {}", arg);
}
fn main () {
foo(Bar::new(12).extract());
}
Can I rely on this behaviour?
In the rust reference, under 'Temporary Lifetimes', it says:
... the lifetime of temporary values is typically
the innermost enclosing statement; the tail expression of a block is considered part of the statement that encloses the block, or
The innermost enclosing statement in your case is the call to bar( ). There are examples in the same section very similar to your case.
The compiler would not have compiled your code if this were not the case.
I'm trying to recreate a simple callback pattern in Rust using 2 structs. One will pass a bit of logic to execute whenever the other one is ready. The issue here is that the logic will run only if a certain value from the struct is true.
I can understand why the reference to Foo needs to live for 'static in this case, but I'm not sure how to refactor so that it compiles.
Seems like a pretty regular use case, but maybe I'm missing something since I'm new to Rust.
struct Foo {
value: bool,
}
struct Bar {
closure: Box<dyn Fn() -> ()>,
}
impl Foo {
fn new() -> Self {
Foo {
value: false,
}
}
fn set_closure(&self, b: &mut Bar) {
b.closure = self.get_closure();
}
fn get_closure(&self) -> Box<dyn Fn() -> ()> {
return Box::new(|| {
if self.value {
println!("true");
} else {
println!("false");
}
});
}
}
impl Bar {
fn new() -> Self {
Bar {
closure: Box::new(|| {})
}
}
}
fn main() {
let foo = Foo::new();
let mut bar = Bar::new();
foo.set_closure(&mut bar);
let closure = bar.closure;
closure();
}
Playground link -> here
You need to move the value into the closure:
fn get_closure(&self) -> Box<dyn Fn() -> ()> {
let value = self.value;
Box::new(move || {
if value {
println!("true");
} else {
println!("false");
}
})
}
Notice that in your example value is a bool which is Copy. If not you can either capture a reference or clone it. (If capturing a reference you may need to adjust some lifetimes there).
Playground
I have some code like this:
foo.move_right_by(10);
//do some stuff
foo.move_left_by(10);
It's really important that I perform both of those operations eventually, but I often forget to do the second one after the first. It causes a lot of bugs and I'm wondering if there is an idiomatic Rust way to avoid this problem. Is there a way to get the rust compiler to let me know when I forget?
My idea was to maybe somehow have something like this:
// must_use will prevent us from forgetting this if it is returned by a function
#[must_use]
pub struct MustGoLeft {
steps: usize;
}
impl MustGoLeft {
fn move(&self, foo: &mut Foo) {
foo.move_left_by(self.steps);
}
}
// If we don't use left, we'll get a warning about an unused variable
let left = foo.move_left_by(10);
// Downside: move() can be called multiple times which is still a bug
// Downside: left is still available after this call, it would be nice if it could be dropped when move is called
left.move();
Is there a better way to accomplish this?
Another idea is to implement Drop and panic! if the struct is dropped without having called that method. This isn't as good though because it's a runtime check and that is highly undesirable.
Edit: I realized my example may have been too simple. The logic involved can get quite complex. For example, we have something like this:
foo.move_right_by(10);
foo.open_box(); // like a cardboard box, nothing to do with Box<T>
foo.move_left_by(10);
// do more stuff...
foo.close_box();
Notice how the operations aren't performed in a nice, properly nested order. The only thing that's important is that the inverse operation is always called afterwards. The order sometimes needs to be specified in a certain way in order to make the code work as expected.
We can even have something like this:
foo.move_right_by(10);
foo.open_box(); // like a cardboard box, nothing to do with Box<T>
foo.move_left_by(10);
// do more stuff...
foo.move_right_by(10);
foo.close_box();
foo.move_left_by(10);
// do more stuff...
You can use phantom types to carry around additional information, which can be used for type checking without any runtime cost. A limitation is that move_left_by and move_right_by must return a new owned object because they need to change the type, but often this won't be a problem.
Additionally, the compiler will complain if you don't actually use the types in your struct, so you have to add fields that use them. Rust's std provides the zero-sized PhantomData type as a convenience for this purpose.
Your constraint could be encoded like this:
use std::marker::PhantomData;
pub struct GoneLeft;
pub struct GoneRight;
pub type Completed = (GoneLeft, GoneRight);
pub struct Thing<S = ((), ())> {
pub position: i32,
phantom: PhantomData<S>,
}
// private to control how Thing can be constructed
fn new_thing<S>(position: i32) -> Thing<S> {
Thing {
position: position,
phantom: PhantomData,
}
}
impl Thing {
pub fn new() -> Thing {
new_thing(0)
}
}
impl<L, R> Thing<(L, R)> {
pub fn move_left_by(self, by: i32) -> Thing<(GoneLeft, R)> {
new_thing(self.position - by)
}
pub fn move_right_by(self, by: i32) -> Thing<(L, GoneRight)> {
new_thing(self.position + by)
}
}
You can use it like this:
// This function can only be called if both move_right_by and move_left_by
// have been called on Thing already
fn do_something(thing: &Thing<Completed>) {
println!("It's gone both ways: {:?}", thing.position);
}
fn main() {
let thing = Thing::new()
.move_right_by(4)
.move_left_by(1);
do_something(&thing);
}
And if you miss one of the required methods,
fn main(){
let thing = Thing::new()
.move_right_by(3);
do_something(&thing);
}
then you'll get a compile error:
error[E0308]: mismatched types
--> <anon>:49:18
|
49 | do_something(&thing);
| ^^^^^^ expected struct `GoneLeft`, found ()
|
= note: expected type `&Thing<GoneLeft, GoneRight>`
= note: found type `&Thing<(), GoneRight>`
I don't think #[must_use] is really what you want in this case. Here's two different approaches to solving your problem. The first one is to just wrap up what you need to do in a closure, and abstract away the direct calls:
#[derive(Debug)]
pub struct Foo {
x: isize,
y: isize,
}
impl Foo {
pub fn new(x: isize, y: isize) -> Foo {
Foo { x: x, y: y }
}
fn move_left_by(&mut self, steps: isize) {
self.x -= steps;
}
fn move_right_by(&mut self, steps: isize) {
self.x += steps;
}
pub fn do_while_right<F>(&mut self, steps: isize, f: F)
where F: FnOnce(&mut Self)
{
self.move_right_by(steps);
f(self);
self.move_left_by(steps);
}
}
fn main() {
let mut x = Foo::new(0, 0);
println!("{:?}", x);
x.do_while_right(10, |foo| {
println!("{:?}", foo);
});
println!("{:?}", x);
}
The second approach is to create a wrapper type which calls the function when dropped (similar to how Mutex::lock produces a MutexGuard which unlocks the Mutex when dropped):
#[derive(Debug)]
pub struct Foo {
x: isize,
y: isize,
}
impl Foo {
fn new(x: isize, y: isize) -> Foo {
Foo { x: x, y: y }
}
fn move_left_by(&mut self, steps: isize) {
self.x -= steps;
}
fn move_right_by(&mut self, steps: isize) {
self.x += steps;
}
pub fn returning_move_right(&mut self, x: isize) -> MovedFoo {
self.move_right_by(x);
MovedFoo {
inner: self,
move_x: x,
move_y: 0,
}
}
}
#[derive(Debug)]
pub struct MovedFoo<'a> {
inner: &'a mut Foo,
move_x: isize,
move_y: isize,
}
impl<'a> Drop for MovedFoo<'a> {
fn drop(&mut self) {
self.inner.move_left_by(self.move_x);
}
}
fn main() {
let mut x = Foo::new(0, 0);
println!("{:?}", x);
{
let wrapped = x.returning_move_right(5);
println!("{:?}", wrapped);
}
println!("{:?}", x);
}
I only looked at the initial description and probably missed the details in the conversation but one way to enforce the actions is to consume the original object (going right) and replace it with one that forces you to to move left by same amount before you can do whatever you wanted to do to finish the task.
The new type can forbid / require different calls to be made before getting to a finished state. For example (untested):
struct CanGoRight { .. }
impl CanGoRight {
fn move_right_by(self, steps: usize) -> MustGoLeft {
// Note: self is consumed and only `MustGoLeft` methods are allowed
MustGoLeft{steps: steps}
}
}
struct MustGoLeft {
steps: usize;
}
impl MustGoLeft {
fn move_left_by(self, steps: usize) -> Result<CanGoRight, MustGoLeft> {
// Totally making this up as I go here...
// If you haven't moved left at least the same amount of steps,
// you must move a bit further to the left; otherwise you must
// switch back to `CanGoRight` again
if steps < self.steps {
Err(MustGoLeft{ steps: self.steps - steps })
} else {
Ok(CanGoRight{ steps: steps - self.steps })
}
}
fn open_box(self) -> MustGoLeftCanCloseBox {..}
}
let foo = foo.move_right_by(10); // can't move right anymore
At this point foo can no longer move right as it isn't allowed by MustGoLeft but it can move left or open the box. If it moves left far enough it gets back to the CanGoRight state again. But if it opens the box then totally new rules apply. Either way you'll have to deal with both possibilities.
There's probably going to be some duplication between the states, but should be easy enough to refactor. Adding a custom trait might help.
In the end it sounds like you're making a state machine of sorts. Maybe https://hoverbear.org/2016/10/12/rust-state-machine-pattern/ will be of use.
I'm wrapping a C library that has two structs: one has a pointer to the other.
struct StructA {
void * some_mem;
};
struct StructB {
void * some_mem;
struct StructA * some_struct;
};
Both of these structs own memory, so my wrapper has constructors and destructors for both of them.
struct StructA(*mut c_void);
impl StructA {
fn new() -> Self {
StructA(c_constructor())
}
}
impl Drop for StructA {
fn drop(&mut self) {
let StructA(ptr) = self;
c_destructor(ptr);
}
}
There's also a function that takes a pointer to StructB and returns its pointer to StructA:
const struct StructA * get_struct(const struct StructB * obj);
The user of this function should not free the returned pointer, since it will be freed when the user frees obj.
How can I wrap this function? The problem is that the destructor for StructB frees all its memory, including the one for StructA. So if my wrapping of get_struct returns an object, then the wrapped StructA will be freed twice (right?). It could instead return a reference to an object, but where would that object live?
I could have separate structs for StructA based on whether it's standalone and needs to be freed or if it's a reference, but I'm hoping that's unnecessary.
I could have separate structs for StructA based on whether it's standalone and needs to be freed or if it's a reference, but I'm hoping that's unnecessary.
It's necessary. The difference between an owned StructA * and a borrowed StructA * is precisely the same as the difference between a Box<T> and a &T. They're both "just a pointer", but the semantics are completely different.
Something along these lines is probably what you want:
use std::marker::PhantomData;
struct OwnedA(*mut c_void);
impl Drop for OwnedA {
fn drop(&mut self) { }
}
impl OwnedA {
fn deref(&self) -> RefA { RefA(self.0, PhantomData) }
}
struct RefA<'a>(*mut c_void, PhantomData<&'a u8>);
struct OwnedB(*mut c_void);
impl Drop for OwnedB {
fn drop(&mut self) { }
}
impl OwnedB {
fn get_a(&self) -> RefA { RefA(get_struct(self.0), PhantomData) }
}
In particular, it's worth noting that lifetime parameter on RefA lets the compiler make sure you don't use a RefA after the backing structure has been freed.
I could have separate structs for StructA based on whether it's standalone and needs to be freed or if it's a reference, but I'm hoping that's unnecessary.
I believe this would be the accepted pattern. For backup, I'd point to the fact that this is a normal pattern in the Rust library. &str and String, &[T] and Vec<T>, Path and PathBuf, and probably lots of others I can't think of.
The good news is that you can use similar patterns as these pairs, leveraging Deref or DerefMut to call down to shared implementation:
use std::ops::{Deref, DerefMut};
enum RawFoo {}
fn c_foo_new() -> *const RawFoo { std::ptr::null() }
fn c_foo_free(_f: *const RawFoo) {}
fn c_foo_count(_f: *const RawFoo) -> u8 { 42 }
fn c_foo_make_awesome(_f: *const RawFoo, _v: bool) { }
struct OwnedFoo(Foo);
impl OwnedFoo {
fn new() -> OwnedFoo {
OwnedFoo(Foo(c_foo_new()))
}
}
impl Drop for OwnedFoo {
fn drop(&mut self) { c_foo_free((self.0).0) }
}
impl Deref for OwnedFoo {
type Target = Foo;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl DerefMut for OwnedFoo {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}
struct Foo(*const RawFoo);
impl Foo {
fn count(&self) -> u8 { c_foo_count(self.0) }
fn make_awesome(&mut self, v: bool) { c_foo_make_awesome(self.0, v) }
}
fn main() {
let mut f = OwnedFoo::new();
println!("{}", f.count());
f.make_awesome(true);
}
Then, when you get a borrowed pointer from your other object, just wrap it up in a &Foo:
use std::mem;
fn c_bar_foo_ref() -> *const RawFoo { std::ptr::null() }
// Ignoring boilerplate for wrapping the raw Bar pointer
struct Bar;
impl Bar {
fn new() -> Bar { Bar }
fn foo(&self) -> &Foo {
unsafe { mem::transmute(c_bar_foo_ref()) }
}
fn foo_mut(&mut self) -> &mut Foo {
unsafe { mem::transmute(c_bar_foo_ref()) }
}
}
fn main() {
let mut b = Bar::new();
println!("{}", b.foo().count());
b.foo_mut().make_awesome(true);
// Doesn't work - lifetime constrained to Bar
// let nope = Bar::new().foo();
}
I'd like to write a safe Rust wrapper for a C library. I need to express the C's library raw pointer ownership rules in Rust's terms.
The library has its private structure such as: struct handle {void *_data} and exposes setter as set_data(struct handle*, void *data).
I'd like to make Rust version of that method with signature that says "data must live at least as long as the handle".
I've tried:
set_data(&'a self, &'a data:…)
but borrow checker seems to apply that to lifetime within that function, not overall lifetime of the object.
I've also tried to add lifetime to impl, but that's still no good. Full test case:
#![allow(unused_variables)]
struct Handle<'a>;
impl<'a> Handle<'a> {
pub fn set_data(&'a mut self, data: &'a DropCanary) {
// save data raw ptr
}
pub fn use_data(&'a self) {
// use data raw ptr
println!("alive?");
}
}
fn main() {
let mut handle = Handle;
let long_enough_lifetime = DropCanary{label:"long"};
{
let short_lifetime = DropCanary{label:"short"};
handle.set_data(&short_lifetime); // This shouldn't be allowed!
handle.set_data(&long_enough_lifetime); // This is OK
}
handle.use_data();
}
/// --- just for testing ---
struct DropCanary {
label: &'static str,
}
impl Drop for DropCanary {
fn drop(&mut self) {
println!("dropped: {}", self.label);
}
}
The problem is that the following code compiles and outputs:
dropped: short
alive?
dropped: long
So it causes use-after-free, because Rust doesn't know that short_lifetime must outlive handle.
This should work for you (playpen).
The reason that your example compiles is simply because you do not use the lifetime inside the struct inside your example. Since you do not use it there is no constraint on it and it could just as well have been omitted. If you do not store any data with a lifetime inside your struct there is marker types which you can substitute for the Option I used here.
#![allow(unused_variables)]
struct Handle<'a>(Option<&'a DropCanary>);
impl<'a> Handle<'a> {
pub fn set_data(&mut self, data: &'a DropCanary) {
self.0 = Some(data);
// save data raw ptr
}
pub fn use_data(&self) {
// use data raw ptr
println!("alive?");
}
}
fn main() {
let mut handle = Handle(None);
let long_enough_lifetime = DropCanary{label:"long"};
{
let short_lifetime = DropCanary{label:"short"};
//handle.set_data(&short_lifetime); // This shouldn't be allowed!
handle.set_data(&long_enough_lifetime); // This is OK
}
handle.use_data();
}
/// --- just for testing ---
struct DropCanary {
label: &'static str,
}
impl Drop for DropCanary {
fn drop(&mut self) {
println!("dropped: {}", self.label);
}
}