-
Notifications
You must be signed in to change notification settings - Fork 346
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The plan for provenance #2133
Comments
I guess the alternative would be to just have a dedicated flag for them. That is probably best, though I am a bit worried that we are getting too many flags and people will miss the most relevant ones in a soup of flags. |
Maybe we should have a single |
I think that whatever opinion we have about what people should use, should just be the default. But I could imagine splitting the list in the docs into two: common options, and advanced options. |
So then maybe the story should be quite simply like this: by default, we properly implement as best as we can the
|
With #2059 and rust-lang/rust#97219 having landed, we can now at least error for code like this: fn main() {
let x = 42;
let xptr = &x as *const i32;
let xptr_invalid = std::ptr::invalid::<i32>(xptr.expose_addr());
let _val = unsafe { *xptr_invalid }; //~ ERROR is not a valid pointer
} #2151 implements that. This distinguishes Distinguishing |
Alternatively, we might not even need the intrinsic if we make ptr2int transmutes strip provenance. Then This will take a bit of work to implement in Miri though. OTOH that work is totally worth it since we can then also use it to reset padding to uninit on a typed copy! |
I think this is what we should go for. |
Turns out that for So, we are pretty close to having permissive provenance work as intended (properly distinguishing both |
implement ptr.addr() via transmute As per the discussion in rust-lang/unsafe-code-guidelines#286, the semantics for ptr-to-int transmutes that we are going with for now is to make them strip provenance without exposing it. That's exactly what `ptr.addr()` does! So we can implement `ptr.addr()` via `transmute`. This also means that once rust-lang#97684 lands, Miri can distinguish `ptr.addr()` from `ptr.expose_addr()`, and the following code will correctly be called out as having UB (if permissive provenance mode is enabled, which will become the default once the [implementation is complete](rust-lang/miri#2133)): ```rust fn main() { let x: i32 = 3; let x_ptr = &x as *const i32; let x_usize: usize = x_ptr.addr(); // Cast back an address that did *not* get exposed. let ptr = std::ptr::from_exposed_addr::<i32>(x_usize); assert_eq!(unsafe { *ptr }, 3); //~ ERROR Undefined Behavior: dereferencing pointer failed } ``` This completes the Miri implementation of the new distinctions introduced by strict provenance. :) Cc `@Gankra` -- for now I left in your `FIXME(strict_provenance_magic)` saying these should be intrinsics, but I do not necessarily agree that they should be. Or if we have an intrinsic, I think it should behave exactly like the `transmute` does, which makes one wonder why the intrinsic should be needed.
Allow ptr_from_addr_cast to fail This is needed for rust-lang/miri#2133: I would like to have an option in Miri to error when a int2ptr cast is executed.
Allow ptr_from_addr_cast to fail This is needed for rust-lang/miri#2133: I would like to have an option in Miri to error when a int2ptr cast is executed.
#2275 completes this plan. :) |
I think previous SB with Untagged didn't permit Does the fact that permissive provenance with Wildcard enable raw pointer tagging mean that it permits |
I think that once #2275 lands, all Miri modes (that are not explicitly marked as "unsound" in the docs) are sound wrt. We still have the difference that rustc also puts |
Though also note that if you do use int2ptr casts, then Miri is not sound wrt anything. That is just inherent in our spec for those casts. The assumption is that those casts are rare. They are certainly much more rare than use of raw pointers, so we have a lot more precision (fewer false negatives) than the previous default mode. :) The false negatives are limited to memory accesses that directly interact with previously "exposed" memory. But Miri will tell you the first time such a cast happens in your program. (That warning is disabled with |
implement ptr.addr() via transmute As per the discussion in rust-lang/unsafe-code-guidelines#286, the semantics for ptr-to-int transmutes that we are going with for now is to make them strip provenance without exposing it. That's exactly what `ptr.addr()` does! So we can implement `ptr.addr()` via `transmute`. This also means that once rust-lang/rust#97684 lands, Miri can distinguish `ptr.addr()` from `ptr.expose_addr()`, and the following code will correctly be called out as having UB (if permissive provenance mode is enabled, which will become the default once the [implementation is complete](rust-lang/miri#2133)): ```rust fn main() { let x: i32 = 3; let x_ptr = &x as *const i32; let x_usize: usize = x_ptr.addr(); // Cast back an address that did *not* get exposed. let ptr = std::ptr::from_exposed_addr::<i32>(x_usize); assert_eq!(unsafe { *ptr }, 3); //~ ERROR Undefined Behavior: dereferencing pointer failed } ``` This completes the Miri implementation of the new distinctions introduced by strict provenance. :) Cc `@Gankra` -- for now I left in your `FIXME(strict_provenance_magic)` saying these should be intrinsics, but I do not necessarily agree that they should be. Or if we have an intrinsic, I think it should behave exactly like the `transmute` does, which makes one wonder why the intrinsic should be needed.
#2059 is nearing completion, so I figured it would make sense to lay down my current plan for the future of provenance in Miri.
My idea is that, by default, we will work in "permissive" provenance mode, implementing as good as we can the angelic
from_exposed_addr
semantics for int2ptr cast. This is different from now: pointers created in this way get a "wildcard" provenance, and on each access we check if that access happens in the range of some previously exposed provenance. This resolves problems like #1866. There also will be no more "untagged" in Stacked Borrows, but instead Stacked Borrows will have support for the "wildcard" provenance and track which tags have been exposed. That should, hopefully, be much less confusing than the current default. (In particular, if you do not usefrom_expose_addr
/int2ptr casts, it is equivalent to-Zmiri-tag-raw-pointers
.) Meanwhile, if you useaddr
/ptr::invalid
, then the restrictions documented in their spec are actually enforced.When the program actually executes an int2ptr cast or calls
from_exposed_addr
, a warning is shown:-Zmiri-permissive-provenance
literally just disables the warning.-Zmiri-strict-provenance
turnsexpose_addr
into an alias foraddr
(i.e., it no longer tracks which pointers have been exposed), and it turnsptr::from_exposed_addr
into an alias forptr::invalid
(i.e., the pointers produced that way cause UB when being dereferenced, except for ZST accesses). Or maybe it should just makeptr::from_exposed_addr
a hard error? That would be a very clear story ("just make the above warning an error"), but it means code that usesfrom_exposed_addr
but then doesn't actually dereference the pointer stops working. But is there any reason to have such code? I say we try this, and see if it causes any trouble.What I am not entirely sure about is what to do with ptr-to-int transmutes (via
mem::transmute
or other means of type punning). With-Zmiri-strict-provenance
they should trigger UB. They should probably also trigger UB by default because we do have to consider these programs buggy.-Zmiri-permissive-provenance
is meant to be a sound flag so it should not enable them either. For now, we have the-Zmiri-allow-ptr-int-transmute
flag to allow them, but not everything that you think might work will work. (In particular, doing a bytewise copy at typeu8
will never work, that just requires way too deep changes in the interpreter.)TODO:
addr
not expose the provenance: interpret: better control over whether we read data with provenance rust#97684, implement ptr.addr() via transmute rust#97710ptr::invalid
always produce a pointer with invalid provenance: make ptr::invalid not the same as a regular int2ptr cast rust#97219, with permissive-provenance set, we already treat ptr::invalid correctly #2153-Zmiri-strict-provenance
an errorThe text was updated successfully, but these errors were encountered: