trpl: Fix off-by-one highest memory address
This commit is contained in:
parent
2be0d0ad92
commit
6d2cb6c688
@ -217,18 +217,18 @@ on the heap. The actual value of the box is a structure which has a pointer to
|
||||
it allocates some memory for the heap, and puts `5` there. The memory now looks
|
||||
like this:
|
||||
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|------------------|
|
||||
| 2<sup>30</sup> | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 1 | y | 42 |
|
||||
| 0 | x | → 2<sup>30</sup> |
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 1 | y | 42 |
|
||||
| 0 | x | → (2<sup>30</sup>) - 1 |
|
||||
|
||||
We have 2<sup>30</sup> in our hypothetical computer with 1GB of RAM. And since
|
||||
We have (2<sup>30</sup>) - 1 in our hypothetical computer with 1GB of RAM. And since
|
||||
our stack grows from zero, the easiest place to allocate memory is from the
|
||||
other end. So our first value is at the highest place in memory. And the value
|
||||
of the struct at `x` has a [raw pointer][rawpointer] to the place we’ve
|
||||
allocated on the heap, so the value of `x` is 2<sup>30</sup>, the memory
|
||||
allocated on the heap, so the value of `x` is (2<sup>30</sup>) - 1, the memory
|
||||
location we’ve asked for.
|
||||
|
||||
[rawpointer]: raw-pointers.html
|
||||
@ -244,18 +244,18 @@ layout of a program which has been running for a while now:
|
||||
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| 2<sup>30</sup> | | 5 |
|
||||
| (2<sup>30</sup>) - 1 | | |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| (2<sup>30</sup>) - 2 | | |
|
||||
| (2<sup>30</sup>) - 3 | | 42 |
|
||||
| (2<sup>30</sup>) - 3 | | |
|
||||
| (2<sup>30</sup>) - 4 | | 42 |
|
||||
| ... | ... | ... |
|
||||
| 3 | y | → (2<sup>30</sup>) - 3 |
|
||||
| 3 | y | → (2<sup>30</sup>) - 4 |
|
||||
| 2 | y | 42 |
|
||||
| 1 | y | 42 |
|
||||
| 0 | x | → 2<sup>30</sup> |
|
||||
| 0 | x | → (2<sup>30</sup>) - 1 |
|
||||
|
||||
In this case, we’ve allocated four things on the heap, but deallocated two of
|
||||
them. There’s a gap between 2<sup>30</sup> and (2<sup>30</sup>) - 3 which isn’t
|
||||
them. There’s a gap between (2<sup>30</sup>) - 1 and (2<sup>30</sup>) - 4 which isn’t
|
||||
currently being used. The specific details of how and why this happens depends
|
||||
on what kind of strategy you use to manage the heap. Different programs can use
|
||||
different ‘memory allocators’, which are libraries that manage this for you.
|
||||
@ -366,29 +366,29 @@ fn main() {
|
||||
|
||||
First, we call `main()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| (2<sup>30</sup>) - 1 | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → (2<sup>30</sup>) - 1 |
|
||||
| 0 | h | 3 |
|
||||
|
||||
We allocate memory for `j`, `i`, and `h`. `i` is on the heap, and so has a
|
||||
value pointing there.
|
||||
|
||||
Next, at the end of `main()`, `foo()` gets called:
|
||||
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|-----------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup>|
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| (2<sup>30</sup>) - 1 | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → (2<sup>30</sup>) - 1 |
|
||||
| 0 | h | 3 |
|
||||
|
||||
Space gets allocated for `x`, `y`, and `z`. The argument `x` has the same value
|
||||
as `j`, since that’s what we passed it in. It’s a pointer to the `0` address,
|
||||
@ -396,42 +396,42 @@ since `j` points at `h`.
|
||||
|
||||
Next, `foo()` calls `baz()`, passing `z`:
|
||||
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 7 | g | 100 |
|
||||
| 6 | f | → 4 |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| (2<sup>30</sup>) - 1 | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 7 | g | 100 |
|
||||
| 6 | f | → 4 |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → (2<sup>30</sup>) - 1 |
|
||||
| 0 | h | 3 |
|
||||
|
||||
We’ve allocated memory for `f` and `g`. `baz()` is very short, so when it’s
|
||||
over, we get rid of its stack frame:
|
||||
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| (2<sup>30</sup>) - 1 | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → (2<sup>30</sup>) - 1 |
|
||||
| 0 | h | 3 |
|
||||
|
||||
Next, `foo()` calls `bar()` with `x` and `z`:
|
||||
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| (2<sup>30</sup>) - 1 | | 20 |
|
||||
| (2<sup>30</sup>) - 2 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 10 | e | → 9 |
|
||||
| 9 | d | → (2<sup>30</sup>) - 1 |
|
||||
| 9 | d | → (2<sup>30</sup>) - 2 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | → 4 |
|
||||
| 6 | a | → 0 |
|
||||
@ -439,24 +439,24 @@ Next, `foo()` calls `bar()` with `x` and `z`:
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 1 | i | → (2<sup>30</sup>) - 1 |
|
||||
| 0 | h | 3 |
|
||||
|
||||
We end up allocating another value on the heap, and so we have to subtract one
|
||||
from 2<sup>30</sup>. It’s easier to just write that than `1,073,741,823`. In any
|
||||
from (2<sup>30</sup>) - 1. It’s easier to just write that than `1,073,741,822`. In any
|
||||
case, we set up the variables as usual.
|
||||
|
||||
At the end of `bar()`, it calls `baz()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| (2<sup>30</sup>) - 1 | | 20 |
|
||||
| (2<sup>30</sup>) - 2 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 12 | g | 100 |
|
||||
| 11 | f | → 9 |
|
||||
| 10 | e | → 9 |
|
||||
| 9 | d | → (2<sup>30</sup>) - 1 |
|
||||
| 9 | d | → (2<sup>30</sup>) - 2 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | → 4 |
|
||||
| 6 | a | → 0 |
|
||||
@ -464,7 +464,7 @@ At the end of `bar()`, it calls `baz()`:
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 1 | i | → (2<sup>30</sup>) - 1 |
|
||||
| 0 | h | 3 |
|
||||
|
||||
With this, we’re at our deepest point! Whew! Congrats for following along this
|
||||
@ -474,11 +474,11 @@ After `baz()` is over, we get rid of `f` and `g`:
|
||||
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| (2<sup>30</sup>) - 1 | | 20 |
|
||||
| (2<sup>30</sup>) - 2 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 10 | e | → 9 |
|
||||
| 9 | d | → (2<sup>30</sup>) - 1 |
|
||||
| 9 | d | → (2<sup>30</sup>) - 2 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | → 4 |
|
||||
| 6 | a | → 0 |
|
||||
@ -486,32 +486,32 @@ After `baz()` is over, we get rid of `f` and `g`:
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 1 | i | → (2<sup>30</sup>) - 1 |
|
||||
| 0 | h | 3 |
|
||||
|
||||
Next, we return from `bar()`. `d` in this case is a `Box<T>`, so it also frees
|
||||
what it points to: (2<sup>30</sup>) - 1.
|
||||
what it points to: (2<sup>30</sup>) - 2.
|
||||
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| (2<sup>30</sup>) - 1 | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → (2<sup>30</sup>) - 1 |
|
||||
| 0 | h | 3 |
|
||||
|
||||
And after that, `foo()` returns:
|
||||
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| (2<sup>30</sup>) - 1 | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → (2<sup>30</sup>) - 1 |
|
||||
| 0 | h | 3 |
|
||||
|
||||
And then, finally, `main()`, which cleans the rest up. When `i` is `Drop`ped,
|
||||
it will clean up the last of the heap too.
|
||||
|
Loading…
Reference in New Issue
Block a user