Rust equivalent for C++ code to demonstrate protection against UAF - rust

I am trying to understand how Rust's lifetime annotations help catch use-after-free (UAF) issues without compromising on functionality. Here is the code I have :
use std::rc::Rc;
struct Foo {
data: usize,
}
impl Foo {
pub fn begin_foo(&self) {
println!("Begin Foo");
}
pub fn end_foo(&self) {
println!("End Foo");
}
}
struct Bar {
foo: Option<Foo>,
}
impl Bar {
pub fn new(foo: Foo) -> Self {
Bar {
foo : Some(foo),
}
}
pub fn get_foo(&self) -> Option<& Foo>
{
match &self.foo {
Some(foo) => return Some(&foo),
None => return None,
}
}
}
struct FooBar<'a> {
bar : Option<Rc<Bar>>,
foo : Option<&'a Foo>,
}
impl<'a> FooBar<'a> {
pub fn new(bar : Option<Rc<Bar>>) -> Self {
FooBar {
bar : bar,
foo : None,
}
}
pub fn update_foo_1(&'a mut self)
{
if let Some(b) = &self.bar {
self.foo = b.get_foo();
}
}
// ERROR1
/*
pub fn update_foo_2(&mut self)
{
if let Some(b) = &self.bar {
self.foo = b.get_foo();
}
}
*/
pub fn invalidate_bar_1(&mut self) {
self.bar.take();
}
// Inorder to drop the RC, we have to pass self and not &self, which consumes the object.
pub fn invalidate_bar_2(self) {
if let Some(bar) = &self.bar {
println!("Strong ref count = {}", Rc::strong_count(bar));
drop(self.bar.unwrap());
}
}
pub fn use_foo(&self) {
match self.foo {
Some(foo) => println!("Foo.data = {}", foo.data),
None => println!("Foo is None"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn works()
{
println!("Works...");
let foo = Foo {data : 42};
let bar = Bar::new(foo);
let bar_rc = Rc::new(bar);
assert_eq!(1, Rc::strong_count(&bar_rc));
let mut foo_bar: FooBar = FooBar::new(Some(bar_rc));
foo_bar.update_foo_1();
foo_bar.use_foo();
foo_bar.invalidate_bar_1();
println!("Exiting works()...");
}
#[test]
fn fails()
{
println!("Fails...");
let foo = Foo {data : 42};
let bar = Bar::new(foo);
let bar_rc = Rc::new(bar);
assert_eq!(1, Rc::strong_count(&bar_rc));
let mut foo_bar: FooBar = FooBar::new(Some(bar_rc));
foo_bar.update_foo_1();
foo_bar.invalidate_bar_1();
foo_bar.use_foo();
println!("Exiting fails()...");
}
}
The requirement is that FooBar holds Bar but also a reference to Foo to avoid calling Bar::get_foo() multiple times. FooBar::invalidate_bar_*() invalidates Bar leaving the reference Foo dangling.
Given the above requirement, the following sequence of calls should be valid :
foobar.update_foo();
foobar.use_foo();
foobar.invalidate_foo();
The following is an invalid sequence of calls and must be caught at compile-time :
foobar.update_foo();
foobar.invalidate_foo();
foobar.use_foo();
But this doesn't quite happen with my code above. The challenges that I am facing are:
In FooBar::update_foo_1() I am forced to annotate self with lifetime &'a. Otherwise I get the following error :
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/lib.rs:52:26
|
52 | if let Some(b) = &self.bar {
| ^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 50:5...
--> src/lib.rs:50:5
|
50 | / pub fn update_foo_1(& mut self)
51 | | {
52 | | if let Some(b) = &self.bar {
53 | | self.foo = b.get_foo();
54 | | }
55 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:52:26
|
52 | if let Some(b) = &self.bar {
| ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 42:6...
--> src/lib.rs:42:6
|
42 | impl<'a> FooBar<'a> {
| ^^
note: ...so that the expression is assignable
--> src/lib.rs:53:24
|
53 | self.foo = b.get_foo();
| ^^^^^^^^^^^
= note: expected `std::option::Option<&'a Foo>`
found `std::option::Option<&Foo>`
When I use the &'a to resolve the above error, I cannot make any other calls that require exclusive reference to self in the same scope :
error[E0502]: cannot borrow `foo_bar` as immutable because it is also borrowed as mutable
--> src/lib.rs:104:9
|
103 | foo_bar.update_foo_1();
| ------- mutable borrow occurs here
104 | foo_bar.use_foo();
| ^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here

By calling this, you are making FooBar a self referential struct which is hard to define in safe rust.
pub fn update_foo_1(&'a mut self)
{
if let Some(b) = &self.bar {
self.foo = b.get_foo();
}
}
The compiler gives the error correctly here:
error[E0502]: cannot borrow `foo_bar` as immutable because it is also borrowed as mutable
--> src/lib.rs:104:9
|
103 | foo_bar.update_foo_1();
| ------- mutable borrow occurs here
104 | foo_bar.use_foo();
| ^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
because if it did allow any immutable borrows after the update call, it would mean that there is no mutable borrow at that point, which also means that you can do mutable borrows after that.
What happens if the bar field's strong count was 1 and you did this:
drop(foo_bar.bar.take());
You'd have a dangling reference in the foo field of FooBar, which Rust forbids.

Rust's lifetime annotations help catch use-after-free (UAF) issues without compromising on functionality.
Rust's lifetime annotations don't "catch" anything. What they do is tell the compiler about things it may not be able to infer (namely how long borrows span).
What "catches" UAF issues is the affine type system, that is, after a move (aka taking something by value unless it's Copy), the source is inaccessible, and you can't move a structure which are active users (aka for which there are active references, all borrows must end before a structure is moved).
You're not using moves anywhere, so your FooBar object is guaranteed to always be valid.
As for the update_foo_1 issue, I think it's a logical consequence of what you're telling rust:
pub fn update_foo_1(&'a mut self)
means that method is creating a borrow which lasts all of 'a.
'a is a parameter to the structure so it needs to "outlive" the structure itself, and you're saying that you're exclusively borrowing the structure for that lifetime, which means 'a is exactly the same lifetime as the structure (which makes sense since what you're borrowing is part of the structure) and the only thing you've done is statically locked yourself out of using said structure.
Expressing graphs (/ self-referential structures) is difficult to do in Rust, and that's exactly what you're trying to do here, but more fundamentally your entire endeavour seems misguided and based on misunderstandings.

Related

How too loop over a function that requires a mutable refrence?

I am quite new to rust and I have a problem with the borrow checker.
I have a function like this:
impl<'a> DFA<'a> {
fn solve_next(&mut self, c: Option<char>) -> Option<TokenType> {
let node = self.state.unwrap_or_else(|| &self.start_node);
let checks: Vec<char> = node.connections.iter().map(|x| x.1).collect();
let mut position = None;
if let Some(c) = c {
position = checks.iter().position(|x| *x == c);
}
if let Some(i) = position {
let node = &node.connections[i].0;
self.state = Some(node);
None
} else {
if node.is_end {
return Some(TokenType::Keyword);
}
panic!("Invalid charter for current set");
}
}
}
This function either returns a TokenType (which is a enum) when the loop is complete or None when it is not.
its is on this struct:
struct DFA<'a> {
state: Option<&'a Node>,
start_node: Node,
}
Node is:
struct Node {
connections: Vec<(Node, char)>,
is_end: bool,
token_type: TokenType,
}
with the method
fn insert(&mut self, _match: char, end: bool) -> &mut Node {
which creates and return a new node and adds this node into its own connections.
So when I wanted to loop over the solve next function I tried:
impl<'a> Lexer<'a> {
fn next_char(&self) -> Option<char> {
let mut r: Option<char> = None;
for c in &self.chars {
match c {
' ' | '\n' | '\r' => {
continue;
}
_ => {
r = Some(c.clone());
break;
}
}
}
return r;
}
fn next_token(&'a mut self) {
let somechar = 'c';
let mut x = self.dfa.solve_next(self.next_char());
while let None = x {
x = self.dfa.solve_next(self.next_char());
}
}
}
which is a method of
struct Lexer<'a> {
//the output of the lexer
pub tokens: Vec<Token>,
chars: Vec<char>,
dfa: DFA<'a>,
}
the compile error's with
error[E0499]: cannot borrow `self.dfa` as mutable more than once at a time
--> src/main.rs:177:17
|
146 | impl<'a> Lexer<'a> {
| -- lifetime `'a` defined here
...
175 | let mut x = self.dfa.solve_next(self.next_char());
| -------------------------------------
| |
| first mutable borrow occurs here
| argument requires that `self.dfa` is borrowed for `'a`
176 | while let None = x {
177 | x = self.dfa.solve_next(self.next_char());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src/main.rs:177:37
|
146 | impl<'a> Lexer<'a> {
| -- lifetime `'a` defined here
...
175 | let mut x = self.dfa.solve_next(self.next_char());
| -------------------------------------
| |
| mutable borrow occurs here
| argument requires that `self.dfa` is borrowed for `'a`
176 | while let None = x {
177 | x = self.dfa.solve_next(self.next_char());
| ^^^^^^^^^^^^^^^^ immutable borrow occurs here
So is their any way I can use solve_next in this loop? as I would not know how to make a function that can be used like this without having it take a mutable refrence.
The actual error you get with your code is the following (playground):
error: lifetime may not live long enough
--> src/lib.rs:27:49
|
25 | impl<'a> DFA<'a> {
| -- lifetime `'a` defined here
26 | fn solve_next(&mut self, c: Option<char>) -> Option<TokenType> {
| - let's call the lifetime of this reference `'1`
27 | let node = self.state.unwrap_or_else(|| &self.start_node);
| ^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
This is actually complaining about the reference to self.start_node not living long enough, that is for at least 'a.
The reason for that is that your local variable node, that is of type &'x Node, being the lifetime 'x the shorter of that of self.state.unwrap() and &self.start_node. The first one is 'a and the second one is the unnamed lifetime of &self (from now on 's).
But by the rules of Rust lifetimes, 'a outlives DFA<'a> and Self outlives 's, and Self is equal to DFA<'a>, then we conclude that 'a outlives 's. So the lifetime of the local node is actually 's.
Now, the other key line is this one:
self.state = Some(node);
being self.state of type Option<&'a Node>, that requires that the lifetime of node, that is 's, outlives 'a. But that cannot be, we already determined that it is the other way around: 'a outlives 's. Thus a compiler error.
In a nutshell, you are trying to write a self-referential struct, storing in one field a reference to the other field. And that is well known to be impossible.
In the original version of your question, you tried to solve it adding an extra lifetime to the solve_next() function:
fn solve_next(&'a mut self, c: Option<char>) -> Option<TokenType>
Doing that you force the 's from my explanation above to be exactly equal to 'a, so the body of this function is actually correct. Unfortunately if you try to call it normally with:
fn next_token(&mut self) {
let mut x = self.dfa.solve_next(self.next_char());
}
It fails with:
error: lifetime may not live long enough
--> src/lib.rs:63:21
|
46 | impl<'a> Lexer<'a> {
| -- lifetime `'a` defined here
...
62 | fn next_token(&mut self) {
| - let's call the lifetime of this reference `'1`
63 | let mut x = self.dfa.solve_next(self.next_char());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a`
Exactly for the same reason as above: the anonymous lifetime of self must outlive 'a but the compiler deduces it the other way around.
Naturally you can fix it the same way:
fn next_token(&'a mut self) {
And that will compile... as long as you do not try to call solve_next() twice.
I'm not sure why calling solve_next() once it compiles, but calling it twice fails with. But it does not actually matter because even if this function worked, with this extra &'a mut self you'd still have the same problem calling this function from the external code.
What about the solution? Well, I think you need to refactor the code so that you never try to add a reference start_node in the same struct.
For example, you can store the start_node outside this struct:
struct DFA<'a> {
state: Option<&'a Node>,
start_node: &'a Node,
}
This, and remove all the lifetime annotations from &'a self and it will just compile (playground).

how to refactor rust code to resolve borrow that reference parent in closure?

trait OnUpdate {
fn on_update(&mut self, x: &i32);
}
struct Foo {
field: i32,
cbs: Vec<Box<OnUpdate>>,
}
struct Bar {
foos: Vec<Foo>,
}
impl Bar {
fn call_foo_cb(&mut self) {
self.foos
.iter_mut()
.for_each(|foo| foo.cbs.iter_mut().for_each(|cb| cb.on_update(&self.value(*foo)))) // compile error see below
// .for_each(|foo| foo.cbs.iter_mut().for_each(|cb| cb.on_update(&10))) // works
}
fn value(&self, foo: Foo) -> i32 {
foo.field + self.foos.len() as i32 // pretend some calculation based on the current foo and self
}
}
The above code is to demonstrate my problem. I am new to rust and I am wondering what is the best way to refactor in idiomatic rust way.
Thanks in advance.
--> src/lib.rs:348:23
|
346 | self.foos
| --------- mutable borrow occurs here
347 | .iter_mut()
348 | .for_each(|foo| foo.cbs.iter_mut().for_each(|cb| cb.on_update(&self.value(*foo))))
| -------- ^^^^^ immutable borrow occurs here ---- second borrow occurs due to use of `self` in closure
| |
| mutable borrow later used by call
Its easier for me to reason about this with for loops, so consider this equivalent:
for foo in &mut self.foos {
for cb in &mut foo.cbs {
cb.on_update(&self.value(foo));
}
}
If the calculated value doesn't depend on cb, then it can be moved out of the loop:
for foo in &mut self.foos {
let x = self.value(foo);
for cb in &mut foo.cbs {
cb.on_update(&x);
}
}
And then, you can change out the mutable loop for one using indexes to avoid creating a mutable borrow until later:
for i in 0..self.foos.len() {
let x = self.value(&self.foos[i]);
for cb in &mut self.foos[i].cbs {
cb.on_update(&x);
}
}
This code assumes that the value function actually takes the Foo by reference since its not Copy or Clone.

Why do I get the error "cannot infer an appropriate lifetime for lifetime parameter in generic type" when using nested mutable references?

While coding along to get used to Rust, I stumbled upon a compiler error. I want to understand why I get the error and what to do about it:
cannot infer an appropriate lifetime for lifetime parameter in generic
type due to conflicting requirements
I've been looking at a lot of questions covering similar errors, but most seem related to cyclic dependencies and I don't think this is what's going on here.
This is my attempt at a MWE, which still might be further reducible:
Playground link (slightly different error message)
pub struct InnerMut<T> {
state: u32,
stored_fn: fn(&mut T, u32),
}
impl<T> InnerMut<T> {
pub fn new(stored_fn: fn(&mut T, u32)) -> InnerMut<T> {
return InnerMut {
state: std::u32::MAX,
stored_fn,
};
}
pub fn mutate(&mut self, data: &mut T) {
(self.stored_fn)(data, self.state);
self.state -= 1;
}
}
pub struct StoreFnMut<F>
where
F: FnMut(&mut [u8]),
{
mutable_closure: F,
}
impl<F> StoreFnMut<F>
where
F: FnMut(&mut [u8]),
{
pub fn new(mutable_closure: F) -> StoreFnMut<F> {
StoreFnMut { mutable_closure }
}
fn run_closure_on_mutable_borrow(&mut self) {
let mut buf = vec![0; 100];
(self.mutable_closure)(&mut buf[..]);
}
}
fn foo(borrow: &mut &mut [u8], val: u32) {
borrow[0] = (val & 0xff) as u8;
}
fn main() {
let mut capturing_closure;
let mut store_fn_mut;
let mut inner_mut;
inner_mut = InnerMut::new(foo);
capturing_closure = move |mut borrow: &mut [u8]| {
inner_mut.mutate(&mut borrow);
};
store_fn_mut = StoreFnMut::new(capturing_closure);
store_fn_mut.run_closure_on_mutable_borrow();
}
I get this helpful looking yet confusing error message when compiling with Rust 1.24.1:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements
--> src/main.rs:48:31
|
48 | inner_mut = InnerMut::new(foo);
| ^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 49:25...
--> src/main.rs:49:25
|
49 | capturing_closure = move |mut borrow: &mut [u8]| {
| _________________________^
50 | | inner_mut.mutate(&mut borrow);
51 | | };
| |_____^
note: ...so that expression is assignable (expected &mut &mut [u8], found &mut &mut [u8])
--> src/main.rs:50:26
|
50 | inner_mut.mutate(&mut borrow);
| ^^^^^^^^^^^
note: but, the lifetime must be valid for the block suffix following statement 2 at 46:5...
--> src/main.rs:46:5
|
46 | / let mut inner_mut;
47 | |
48 | | inner_mut = InnerMut::new(foo);
49 | | capturing_closure = move |mut borrow: &mut [u8]| {
... |
53 | | store_fn_mut.run_closure_on_mutable_borrow();
54 | | }
| |_^
note: ...so that variable is valid at time of its declaration
--> src/main.rs:46:9
|
46 | let mut inner_mut;
| ^^^^^^^^^^^^^
I can't possibly think of use case for &mut &mut _.
If you change foo to
fn foo(borrow: &mut [u8], val: u32);
Then you get another error:
error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied
--> src/main.rs:46:25
|
46 | let mut inner_mut = InnerMut::new(foo);
| ^^^^^^^^^^^^^ `[u8]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
note: required by `<InnerMut<T>>::new`
Well, nothing requires T to be Sized in this code as it's only used in references, so let's add the constraint T: ?Sized:
pub struct InnerMut<T: ?Sized> {
state: u32,
stored_fn: fn(&mut T, u32),
}
impl<T: ?Sized> InnerMut<T> {
// …
}
And this works.
What you are experiencing is that the compiler cannot prove that you are not storing a reference to &mut borrow inside mutate() into your InnerMut instance. This would be problematic as for all it knows the parameter to your closure lives shorter than the closure itself. But InnerMut was moved to the closure and must live longer than borrow.
Basically Rust prevents closure arguments from escaping the closure because it does not know how to infer lifetimes then.
Consider this minimal example:
struct Test<T> {
field: fn(T),
}
impl<T> Test<T> {
fn foo(&self, _val: T) {}
}
fn calc(_: &mut i32) {}
fn main() {
let test: Test<&mut i32> = Test { field: calc };
let _ = move |y: i32| {
test.foo(&mut y);
};
}
It is written in a way so that the compiler understands it better so we can understand the error:
error[E0597]: `y` does not live long enough
--> src/main.rs:15:23
|
15 | test.foo(&mut y);
| ^ borrowed value does not live long enough
16 | };
| - `y` dropped here while still borrowed
17 | }
| - borrowed value needs to live until here
But I do not even have fields of that type in my struct
One key principle of Rust is that your function signature is the barrier for error reporting. The function itself is checked against the signature and the callers are checked against the signature. That prevents reporting confusing errors about function bodies to the caller of functions (who did not even write them).
For all that Rust knows, your T is inferred as &mut u[8] and your mutate() captures a mutable self. That is suspicious. Better prevent that potential escape of closure variables.
But slightly changing the code makes it work
Rejecting all programs that are incorrect and accepting all programs that are correct is not decidable. Therefore Rust errs on the side of caution and rejects correct programs. Therefore some slight changes can make it possible for Rust to accept the program even if the program was correct before.
What does this mean for my code?
I really do not know the compiler well enough to answer this question. My guess is that by changing T to [u8] and the absence of explicit lifetimes from the InnerMut type the compiler can prove that your closure variables are not escaping.

cannot borrow `self` as immutable because `self.chars` is also borrowed as mutable [duplicate]

This question already has answers here:
Mutably borrow one struct field while borrowing another in a closure
(2 answers)
Closed 5 years ago.
I need immutable access to one struct field and mutable access to another one, but they have to be stacked on each other. I've had this problem multiple times and I don't know how to fix this.
use std::collections::HashMap;
struct Bar;
impl Bar {
fn get(&self) -> i32 {
100
}
}
struct Foo {
chars: HashMap<char, i32>,
b: Bar,
}
impl Foo {
fn run(&mut self) {
self.chars.entry('c').or_insert_with(|| self.b.get() * 100);
}
}
fn main() {
let mut m = Foo {
chars: HashMap::new(),
b: Bar,
};
m.run();
}
error[E0502]: cannot borrow `self` as immutable because `self.chars` is also borrowed as mutable
--> src/main.rs:16:46
|
16 | self.chars.entry('c').or_insert_with(|| self.b.get() * 100);
| ---------- ^^ ---- - mutable borrow ends here
| | | |
| | | borrow occurs due to use of `self` in closure
| | immutable borrow occurs here
| mutable borrow occurs here
The problem is that you're trying to borrow self mutably and immutably, as the compiler says. As pointed out by Stefan, the borrow checker can't distinguish access to fields across closure boundaries, so we need to help it a bit by being more explicit about what we want to borrow and pass to the closure.
A way to do this is to take out a reference to self.b and use that inside the or_insert_with():
use std::collections::HashMap;
struct Bar;
impl Bar {
fn get(&self) -> i32 {
100
}
}
struct Foo {
chars: HashMap<char, i32>,
b: Bar,
}
impl Foo {
fn run(&mut self) {
let b = &self.b;
self.chars.entry('c').or_insert_with(|| b.get() * 100);
}
}
fn main() {
let mut m = Foo {
chars: HashMap::new(),
b: Bar,
};
m.run();
}

How do I give a mutable reference to a builder but only an immutable reference to the built object?

When constructing a FooBuilder, I want to provide a &mut Bar. When I build Foo I want to provide a &Bar and Foo should be able to invoke &self methods from Bar. In other words, the mutable borrow should only during exist during the life of FooBuilder.
struct FooBuilder<'a> {
bar: &'a mut Bar,
}
impl<'a> FooBuilder<'a> {
fn new(bar: &'a mut Bar) -> Self {
FooBuilder { bar: bar }
}
fn build(&'a self) -> Foo<'a> {
Foo { bar: &self.bar }
}
}
struct Foo<'a> {
bar: &'a Bar,
}
struct Bar;
impl Bar {
fn bar(&self) {}
}
fn main() {
let mut bar = Bar;
let foo = FooBuilder::new(&mut bar).build();
bar.bar();
}
This code has the error:
error: borrowed value does not live long enough
--> <anon>:24:15
|
24 | let foo = FooBuilder::new(&mut bar).build();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ does not live long enough
|
note: reference must be valid for the block suffix following statement 1 at 24:48...
--> <anon>:24:49
|
24 | let foo = FooBuilder::new(&mut bar).build();
| ^
note: ...but borrowed value is only valid for the statement at 24:4
--> <anon>:24:5
|
24 | let foo = FooBuilder::new(&mut bar).build();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider using a `let` binding to increase its lifetime
--> <anon>:24:5
|
24 | let foo = FooBuilder::new(&mut bar).build();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0502]: cannot borrow `bar` as immutable because it is also borrowed as mutable
--> <anon>:25:5
|
24 | let foo = FooBuilder::new(&mut bar).build();
| --- mutable borrow occurs here
25 | bar.bar();
| ^^^ immutable borrow occurs here
26 | }
| - mutable borrow ends here
error: aborting due to 2 previous errors
The first step is to fix build.
In order to transform a &mut T into a &T you need to consume &mut T (otherwise you would have aliasing and mutability). This means:
consuming the builder, not taking a reference to it
passing the mutable reference, not taking a reference to it
In short, you go from:
fn build(&'a self) -> Foo<'a> {
Foo { bar: &self.bar }
}
to:
fn build(self) -> Foo<'a> {
Foo { bar: self.bar }
}
This leaves you with a single error:
error: cannot borrow `bar` as immutable because it is also borrowed as mutable [--explain E0502]
--> <anon>:25:5
24 |> let foo = FooBuilder::new(&mut bar).build();
|> --- mutable borrow occurs here
25 |> bar.bar();
|> ^^^ immutable borrow occurs here
26 |> //foo.bar.bar();
27 |> }
|> - mutable borrow ends here
As far as the compiler can see from the method signatures, bar is borrowed mutably and therefore cannot be used directly. The borrow extends until foo is dropped.
The fix is very simple: instead of using bar directly, use bar from its reference in foo. Or to make it clear that scope matters:
fn main() {
let mut bar = Bar;
{
let foo = FooBuilder::new(&mut bar).build();
// `bar` currently borrow (mutably) by `foo`, cannot use it directly
foo.bar.bar();
}
// `bar` no longer borrowed, use at your heart's content
bar.bar();
}
You can do something similar if you don't mind wrapping bar in an Rc. The trick is that if there's only one Rc reference, you can get an &mut reference to the contents. This is sort of backwards; instead of downgrading &mut to & at compile time, it's making use of runtime information (reference counts) to "upgrade" from an immutable reference to mutable.
use std::rc::Rc;
struct FooBuilder<'a> {
bar: &'a mut Rc<Bar>,
}
impl<'a> FooBuilder<'a> {
fn new(bar: &'a mut Rc<Bar>) -> Self {
FooBuilder { bar: bar }
}
fn f(mut self) -> Self {
Rc::get_mut(self.bar).unwrap().mut_method();
self
}
fn build(&'a self) -> Foo {
Foo { bar: self.bar.clone() }
}
}
struct Foo {
bar: Rc<Bar>,
}
struct Bar;
impl Bar {
fn bar(&self) {}
fn mut_method(&mut self) {}
}
fn main() {
let mut bar = Rc::new(Bar);
let foo = FooBuilder::new(&mut bar).f().build();
bar.bar();
}
Play link
Once the Foo has been constructed with an Rc clone, there is more than one reference and a later attempt to get a mut reference would panic (or at least return None from Rc::get_mut()).
This means that you can only do this once; if you want a second FooBuilder to create a second Foo from the same bar it won't work, as you're not allowed any other references if you have an &mut T.
This is a little clumsy, though, and there are likely to be better ways of solving the actual problem, depending on the circumstances.

Resources