]> git.proxmox.com Git - rustc.git/blob - src/doc/nomicon/unchecked-uninit.md
c72ed8a76329982b2582202dbf4d4d1c5b83771f
[rustc.git] / src / doc / nomicon / unchecked-uninit.md
1 % Unchecked Uninitialized Memory
2
3 One interesting exception to this rule is working with arrays. Safe Rust doesn't
4 permit you to partially initialize an array. When you initialize an array, you
5 can either set every value to the same thing with `let x = [val; N]`, or you can
6 specify each member individually with `let x = [val1, val2, val3]`.
7 Unfortunately this is pretty rigid, especially if you need to initialize your
8 array in a more incremental or dynamic way.
9
10 Unsafe Rust gives us a powerful tool to handle this problem:
11 `mem::uninitialized`. This function pretends to return a value when really
12 it does nothing at all. Using it, we can convince Rust that we have initialized
13 a variable, allowing us to do trickier things with conditional and incremental
14 initialization.
15
16 Unfortunately, this opens us up to all kinds of problems. Assignment has a
17 different meaning to Rust based on whether it believes that a variable is
18 initialized or not. If it's believed uninitialized, then Rust will semantically
19 just memcopy the bits over the uninitialized ones, and do nothing else. However
20 if Rust believes a value to be initialized, it will try to `Drop` the old value!
21 Since we've tricked Rust into believing that the value is initialized, we can no
22 longer safely use normal assignment.
23
24 This is also a problem if you're working with a raw system allocator, which
25 returns a pointer to uninitialized memory.
26
27 To handle this, we must use the `ptr` module. In particular, it provides
28 three functions that allow us to assign bytes to a location in memory without
29 dropping the old value: `write`, `copy`, and `copy_nonoverlapping`.
30
31 * `ptr::write(ptr, val)` takes a `val` and moves it into the address pointed
32 to by `ptr`.
33 * `ptr::copy(src, dest, count)` copies the bits that `count` T's would occupy
34 from src to dest. (this is equivalent to memmove -- note that the argument
35 order is reversed!)
36 * `ptr::copy_nonoverlapping(src, dest, count)` does what `copy` does, but a
37 little faster on the assumption that the two ranges of memory don't overlap.
38 (this is equivalent to memcpy -- note that the argument order is reversed!)
39
40 It should go without saying that these functions, if misused, will cause serious
41 havoc or just straight up Undefined Behavior. The only things that these
42 functions *themselves* require is that the locations you want to read and write
43 are allocated. However the ways writing arbitrary bits to arbitrary
44 locations of memory can break things are basically uncountable!
45
46 Putting this all together, we get the following:
47
48 ```rust
49 use std::mem;
50 use std::ptr;
51
52 // size of the array is hard-coded but easy to change. This means we can't
53 // use [a, b, c] syntax to initialize the array, though!
54 const SIZE: usize = 10;
55
56 let mut x: [Box<u32>; SIZE];
57
58 unsafe {
59 // convince Rust that x is Totally Initialized
60 x = mem::uninitialized();
61 for i in 0..SIZE {
62 // very carefully overwrite each index without reading it
63 // NOTE: exception safety is not a concern; Box can't panic
64 ptr::write(&mut x[i], Box::new(i as u32));
65 }
66 }
67
68 println!("{:?}", x);
69 ```
70
71 It's worth noting that you don't need to worry about `ptr::write`-style
72 shenanigans with types which don't implement `Drop` or contain `Drop` types,
73 because Rust knows not to try to drop them. Similarly you should be able to
74 assign to fields of partially initialized structs directly if those fields don't
75 contain any `Drop` types.
76
77 However when working with uninitialized memory you need to be ever-vigilant for
78 Rust trying to drop values you make like this before they're fully initialized.
79 Every control path through that variable's scope must initialize the value
80 before it ends, if it has a destructor.
81 *[This includes code panicking](unwinding.html)*.
82
83 And that's about it for working with uninitialized memory! Basically nothing
84 anywhere expects to be handed uninitialized memory, so if you're going to pass
85 it around at all, be sure to be *really* careful.