Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the book "Rust Essentials" correct about the location of variables in the stack or in the heap?

I found code to get the memory location for variables in the book Rust Essentials by Ivo Balbaert in chapter 2 about "Stack and Heap":

let a = 32;
let mut b = "str";
println!({:p} {:p}, &a, &b);

The book has the output 0x23fba4 0x23fb90 and it states that the first address is location in the stack, and the second one in the heap.

I have some doubt about this statement because I have heard that the stack address grows toward decreasing memory address. The second address above seems to be a location in the stack.

Am I wrong about it?

Quote:

Now, we will run the following program and try to visualize the program's memory: // see Chapter 2/code/references.rs

let health = 32;
let mut game = "Space Invaders";

Values are stored in memory and so they have memory addresses. The health variable contains an integer value 32 that is stored in the stack at location 0x23fba4, while the variable game contains a string, which is stored in the heap starting at location 0x23fb90. (These were the addresses when I executed the program, but they will be different when you run the program.)

The variables to which the values are bound are pointers or references to the values. They point to them; game is a reference to Space Invaders. The address of a value is given by the & operator. So, &health is the address where value 32 is stored, and &game is the address where the Space Invaders' value is stored. We can print these addresses by using the format string {:p} for pointers like this:

println!("address of health-value: {:p}", &health); // prints 0x23fba4
println!("address of game-value: {:p}", &game); // prints 0x23fb90
like image 315
eaniconer Avatar asked May 30 '18 04:05

eaniconer


People also ask

Where will the variables be stored in stack or heap?

stack : stores local variables. heap : dynamic memory for programmer to allocate. data : stores global variables, separated into initialized and uninitialized.

Are rust arrays stored on the stack?

Rust arrays are value types: they are allocated on the stack like other values and an array object is a sequence of values, not a pointer to those values (as in C). So from our examples above, let a = [1_i32, 2, 3, 4]; will allocate 16 bytes on the stack and executing let b = a; will copy 16 bytes.

What is the difference between heap and stack?

The Heap Space contains all objects are created, but Stack contains any reference to those objects. Objects stored in the Heap can be accessed throughout the application. Primitive local variables are only accessed the Stack Memory blocks that contain their methods.

Do variables store objects on the stack?

When a function is called the local variables are stored in a stack, and it is automatically destroyed once returned. A stack is used when a variable is not used outside that function. It allows you to control how memory is allocated and deallocated. Stack automatically cleans up the object.


1 Answers

As user4815162342 commented, the book is wrong. The fat pointer that is the variable b is located on the stack just like a. Only the string data it points to can be somewhere else.

In the example let mut b = "str"; the string data is actually nowhere near the heap. It is statically placed in the data segment of your program. To really place it on the heap we need to use let b = String::from("str");. The resulting memory will look something like in the image below:

enter image description here

Let's manually inspect the memory to see what is going on.

Say a and b are located at addresses 0x7ffeda6df61c and 0x7ffeda6df620.

// print part of stack memory starting at &a
let m: &[u8] = unsafe {
    slice::from_raw_parts(&a as *const _ as *const u8, 4 + 16)
};
println!("{:?}", m);

The output will look something like this:

[32, 0, 0, 0, 128, 85, 251, 177, 191, 85, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0]

  • 32, 0, 0, 0: four bytes of a
  • 128, 85, 251, 177, 191, 85, 0, 0: first part of b, the 64 bit pointer to the string data
  • 3, 0, 0, 0, 0, 0, 0, 0: second part of b, the length of the string

Now follow the data pointer:

// manually follow the data pointer
let address = unsafe {
    *(&b as *const _ as *const usize)
};
let p = address as *const u8;
println!("{:p}", p);  // 0x55bfb1fb5580

While a and b reside in the same memory region (0x7f...), the string data is in a different region (0x7e...).

// print content of pointer
let s: &[u8] = unsafe {
    slice::from_raw_parts(p, 4)
};
println!("{:?}", s);  // [115, 116, 114, 32]

The first three bytes contain the ASCII codes for s, t, and r. The fourth byte is arbitrary garbage.

Below is the complete code.

use std::slice;

fn main() {
    let a: i32 = 32;
    let b = String::from("str");
    println!("{:p} {:p}", &a, &b);

    // print part of stack memory starting at a
    let m: &[u8] = unsafe {
        slice::from_raw_parts(&a as *const _ as *const u8, 4 + 16)
    };
    println!("{:?}", m);

    // manually follow the str pointer
    let address = unsafe {
        *(&b as *const _ as *const usize)
    };
    let p = address as *const u8;
    println!("{:p}", p);

    // print content of pointer
    let s: &[u8] = unsafe {
        slice::from_raw_parts(p, 4)
    };
    println!("{:?}", s);
}

Note that the code example assumes 64 bit pointers and relies on implementation details of the compiler and may break in the future or on other systems. In particular, the layout of the stack frame or the &str are not guaranteed. Please don't use any of these in real code :)

like image 62
MB-F Avatar answered Dec 14 '22 19:12

MB-F