add draft on Tree Borrows
[web.git] / personal / _posts / 2019-07-14-uninit.md
index b25a0524263e4ad734b8c25a230b45c1cbd5073c..bbb1468535f65b94a406fcf6b2d2205485484842 100644 (file)
@@ -1,6 +1,6 @@
 ---
 title: '"What The Hardware Does" is not What Your Program Does: Uninitialized Memory'
 ---
 title: '"What The Hardware Does" is not What Your Program Does: Uninitialized Memory'
-categories: rust research
+categories: rust research programming
 forum: https://internals.rust-lang.org/t/what-the-hardware-does-is-not-what-your-program-does-uninitialized-memory/10561
 ---
 
 forum: https://internals.rust-lang.org/t/what-the-hardware-does-is-not-what-your-program-does-uninitialized-memory/10561
 ---
 
@@ -36,20 +36,22 @@ Here is an example to demonstrate why "random bit pattern" cannot describe unini
 use std::mem;
 
 fn always_returns_true(x: u8) -> bool {
 use std::mem;
 
 fn always_returns_true(x: u8) -> bool {
-    x < 150 || x > 120
+    x < 120 || x == 120 || x > 120
 }
 
 fn main() {
 }
 
 fn main() {
-    let x: u8 = unsafe { mem::uninitialized() };
+    let x: u8 = unsafe { mem::MaybeUninit::uninit().assume_init() };
     assert!(always_returns_true(x));
 }
 {% endhighlight %}
     assert!(always_returns_true(x));
 }
 {% endhighlight %}
+**Update (2022-11-17):** Switched to `MaybeUninit` to keep the example working in newer versions of Rust.
+
 `always_returns_true` is a function that, clearly, will return `true` for any possible 8-bit unsigned integer.
 `always_returns_true` is a function that, clearly, will return `true` for any possible 8-bit unsigned integer.
-After all, *every* possible value for `x` will be less than 150 or bigger than 120.
-A quick loop [confirms this](https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=58168009e601a2f01b08981f907a473c).
-However, if you [run the example](https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=da278adb50142d14909df74ea1e43069), you can see the assertion fail.[^godbolt]
+After all, *every* possible value for `x` will be either less than 120, equal to 120, or bigger than 120.
+A quick loop [confirms this](https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=65b690fa3c1691e11d4d45955358cdbe).
+However, if you [run the example](https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=c17d299cacd626c572def0c4262aed69), you can see the assertion fail.[^godbolt]
 
 
-[^godbolt]: In case this changes with future Rust versions, [here is the same example on godbolt](https://godbolt.org/z/JX4B4N); the `xor eax, eax` indicates that the function returns 0, aka `false`. And [here is a version for C++](https://godbolt.org/z/PvZGQB); imagine calling `make_true(true)` which *should* always return `true` but as the assembly shows will return `false`.
+[^godbolt]: In case this changes with future Rust versions, [here is the same example on godbolt](https://godbolt.org/z/9G67hP); the `xor eax, eax` indicates that the function returns 0, aka `false`. And [here is a version for C++](https://godbolt.org/z/TWrvcq).
 
 ## What *is* uninitialized memory?
 
 
 ## What *is* uninitialized memory?
 
@@ -122,7 +124,7 @@ The Rust abstract machine *does* make a distinction between "relaxed" and "relea
 After all, x86 does not have "uninitialized bytes" either, and still our example program above went wrong.
 
 Of course, to explain *why* the abstract machine is defined the way it is, we have to look at optimizations and hardware-level concerns.
 After all, x86 does not have "uninitialized bytes" either, and still our example program above went wrong.
 
 Of course, to explain *why* the abstract machine is defined the way it is, we have to look at optimizations and hardware-level concerns.
-But without an abstract machine, it is very hard to ensure that all the optimizations a compiler performs are consistent---in fact, both [LLVM](https://bugs.llvm.org/show_bug.cgi?id=35229) and [GCC](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65752) suffer from miscompilations caused by combining optimizations that all seem fine in isolation, but together cause incorrect code generation.
+But without an abstract machine, it is very hard to ensure that all the optimizations a compiler performs are consistent---in fact, both [LLVM](https://bugs.llvm.org/show_bug.cgi?id=35229) and [GCC](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65752) suffer from miscompilations caused by combining optimizations that all seem [fine in isolation, but together cause incorrect code generation]({% post_url 2020-12-14-provenance %}).
 The abstract machine is needed as an ultimate arbiter that determines which optimizations can be safely combined with each other.
 I also think that when writing unsafe code, it is much easier to keep in your head a fixed abstract machine as opposed to a set of optimizations that might change any time, and might or might not be applied in any order.
 
 The abstract machine is needed as an ultimate arbiter that determines which optimizations can be safely combined with each other.
 I also think that when writing unsafe code, it is much easier to keep in your head a fixed abstract machine as opposed to a set of optimizations that might change any time, and might or might not be applied in any order.