Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upUnitialized memory #42
Comments
This comment has been minimized.
This comment has been minimized.
Amanieu
commented
Jun 28, 2017
|
I would this one to your list:
Ideally, it would be nice to ensure that simply moving/copying an uninitialized value is fine, as long as you don't "use" it. This includes passing it as a parameter to another function, again as long as that function doesn't "use" the value. |
This comment has been minimized.
This comment has been minimized.
|
What counts as using, then? Writing to a TCP socket for example is fundamentally a copy. |
This comment has been minimized.
This comment has been minimized.
nagisa
commented
Jun 28, 2017
|
Yeah, that would still be a copy, provided the socket is operating in cooked packet mode. In raw mode the OS will inspect at least the contents of the TCP header. |
This comment has been minimized.
This comment has been minimized.
|
So here's what miri implements; IMHO that's a good starting point and it should be mostly compatible with LLVM... Every byte (we ignore bit-wise accesses for now; anyway Rust doesn't have bitfields) is either some value (0 <= x < 256) or "undefined" (or call it unitialized or whatever you like). Loading four undef bytes into a I invite you to play around with miri and run your toy examples though it; if you run into missing functionality, just report a bug. :) My goal is for miri to explicitly be a tool to test such questions; of course, there's still a long way to go. Now, when we are talking abut safe code, I think this is related to #12 (comment). I would also like to propose that passing some safe external function that expects a |
This comment has been minimized.
This comment has been minimized.
eddyb
commented
Jul 11, 2017
AFAIK that's |
This comment has been minimized.
This comment has been minimized.
|
I was referring to miri's undef, which indeed in LLVM is closest to posion. |
This comment has been minimized.
This comment has been minimized.
|
So it sounds like branching is key to triggering UB, but arithmetic "merely" propagates poisoned values?
I’m worried about this distinction. How is it defined? In an implementation of |
This comment has been minimized.
This comment has been minimized.
That's a difference between LLVM poison and miri undef -- the latter is UB on arithmetic.
Good question. We haven't figured out all the details yet. Notice however that most of the time, thse functions assume additional invariants on top of what the type says, which would be fine with a model that checks if at least the normal type interpretation holds. |
This comment has been minimized.
This comment has been minimized.
|
Paraphrasing http://shape-of-code.coding-guidelines.com/2017/06/18/how-indeterminate-is-an-indeterminate-value/ for brevity:
|
This comment has been minimized.
This comment has been minimized.
eddyb
commented
Jul 15, 2017
|
@SimonSapin Instead of XOR one could also use |
SimonSapin commentedJun 28, 2017
Under what conditions is it valid to use any of these?
let x: T = std::mem::uninitialized();on the stackBox::new(std::mem::uninitialized())Vecbetween.len()and.capacity()alloc::heap::allocate()without first writing to itLet’s assume
!Drop(or that we usestd::mem::forgetand are being very careful about panic-safety), and types (likeu32) for which all bit patterns are valid.Reading uninitialized memory is Bad and should be avoided, but what’s the worst that could happen? Undefined values might fine in many cases. Or is it Undefined Behavior of the “the optimizer is allowed to eat your lunch and elide half your program” kind?
As a concrete example, consider
reallocatewhich when copying reads from the source pointer. That data is not necessarily entirely initialized:Vec::with_capacity(10).reserve(100)