IcanCode
IcanCode

Reputation: 537

Are string literals immutable?

I am reading the Rust book to learn Rust and currently learning about ownership. It mentions that:

We’ve already seen string literals, where a string value is hardcoded into our program. String literals are convenient, but they aren’t suitable for every situation in which we may want to use text. One reason is that they’re immutable.

The code below runs without any problem. Here I changed the value of a, if immutable strings can be changed what’s the problem stated there?

fn main() {
   let mut a = "Hello";
   println!("{}", a);
   a = " World";
   println!("{}", a);
}

Upvotes: 4

Views: 908

Answers (1)

linuskmr
linuskmr

Reputation: 834

The executable binary produced by the rust compiler contains the string literals "Hello" and "World" in the read-only data section rodata.

$ cargo build --release
$ readelf -x .rodata target/release/demo | grep Hello
  0x0003c000 48656c6c 6f000000 0a576f72 6c640000 Hello....World..

Because these literals are placed in an immutable section, the operating system prohibits modifying them.

fn main() {
    let mut a: &'static str = "Hello";
    println!("{}", a);

    unsafe { (a.as_ptr() as *mut u8).write(42) };
    println!("{}", a);
}
$ cargo run
Hello
Segmentation fault

However, the variable a is of type &str, so a pointer to a string slice, and it lives on the stack. Therefore, it is totally valid for a to first point to the address of "Hello", and then to the address of "World".


EDIT: Information about the unsafe block

We want to write something to the address where a points to, to show that it is indeed stored in a read-only section.

a is declared as mut a: &str, meaning the variable is mutable, but the data (string literal) is immutable (in contrast to mut a: &mut str 😉️). Thus, the compiler prevents us from using a.as_mut_ptr() to get a mutable (aka writable) pointer to the underlying bytes.

Instead, we have to do a little trick: Use a.as_ptr() and cast the returned const *u8 to a mut *u8. Finally, writing to a pointer requires an unsafe block, because you can violate Rust's memory safety, which can result in bad things happening, like the Segmentation Fault shown above.

Upvotes: 7

Related Questions