Open captkuykuy opened 11 months ago
Currently reading through that chapter myself. First and foremost, as the authors state
Below are four snippets which are rejected by the Rust compiler. Imagine that Rust instead allowed these snippets to compile and run. Select each snippet that would cause undefined behavior
I also selected
let b = Box::new(0);
let b2 = b;
println!("{}", b);
move_a_box(b2);
And got quite confused why this was wrong. To my understanding, it's a bit on the verge of "Assume Rust allows this to be compiled". This allows the Rust compiler to for a moment ignore that we may access an address that isn't owned anymore, which generally isn't guaranteed to be safe, but for that snippet, it is.
Although ownership has changed at this point in time, two key things happen:
0
is written in, hence println!
will not read undefined memory0
is written to will only be attempted to be freed exactly once.
When trying to free a memory address that isn't assigned anymore it results in undefined behavior, e.g. freeing it twice, which is not the case here.To explain the second point, what happens is line-by-line, assuming 0xF
is where the value is stored:
0xF
contains 0
, and b
is pointing to 0xF
, and b
is the owner of 0xF
0xF
contains 0
, and b
is pointing to 0xF
, and b2
is pointing to 0xF
, and b2
is the owner of 0xF
println!("{}", b);
results in println!("{}", 0xF);
since b
still points to 0xF
, b2
is the owner of 0xF
b2
loses ownership to move_a_box
, now neither b
or b2
own 0xF
anymoreThus, Rust attempts to free 0xF
exactly once, and that is when the frame of move_a_box
ends.
Note: This is my mental model of how Rust works so far, hence my attempt is also from a non-experienced Rust point of view.
@MisterDerpie's answer is spot-on. This program is rejected by the Rust compiler, but would not cause undefined behavior because the data pointed-to by b
is not deallocated until after move_a_box
has been called.
I think the quiz the OP mentions has a similar assumption encoded into it as the one in "Boxes Live in the Heap". The program would compile in that quiz, but we are asked about a
which would not be accessible to us at that point.
Both of these quizzes ask the reader to reason about abstract states Rust would not actually allow to exist, and that is somewhat of a difficult charge in the context of "learning Rust". I fully understand this chapter is the inflection point in Rust's learning difficulty curve. I would propose that a quiz question could be tagged as "You cannot actually do this in Rust, but imagine you can" (perhaps "Abstract"?).
Ironically, typing this all out helped me accept the answer and this book's pedagogical style, but I feel like others coming here will eventually run into similar issues, so I am committing to leaving this comment anyway.
Finally I count the question as "imagine the rust compiler does not use ownership to limit heap access, but still use ownership to free memory." This works, but still weird😂 All in all I don't think this is a good example as a quiz. Add an explanation of the word "imagine" as before would improve it.
I have searched open and closed issues and pull requests for duplicates, using these search terms:
-
I have checked the latest
main
branch to see if this has already been fixed, in this file:URL to the section(s) of the book with this problem:
https://rust-book.cs.brown.edu/ch04-01-what-is-ownership.html
Description of the problem:
the last quiz, question 4. it says this is NOT undefined behaviour:
let b = Box::new(0); let b2 = b; println!("{}", b); move_a_box(b2);
why? "b" is assigned and then used at a function call to println. therefore, "b" already looses ownership.
also, in a smartphone, quiz #4 submit button is not showing.
Suggested fix: