Skip to content
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

enable number validity checking and ptr::invalid checking by default #2151

Merged
merged 1 commit into from
May 25, 2022

Conversation

RalfJung
Copy link
Member

@RalfJung RalfJung commented May 23, 2022

This removes the -Zmiri-check-number-validity flag, enabling its effects by default. (We don't error when the flag is passed, for backwards compatibility.) We also enable by default that transmuting an integer to a pointer now creates a pointer with None provenance, which is invalid to dereference (and, in the case of a function pointer, invalid to call). I did this together since it is all related to ptr2int/int2ptr transmutation.

Two new flags are added to optionally take back these stricter checks:

  • -Zmiri-allow-uninit-numbers makes Miri accept uninit data in integers and floats
  • -Zmiri-allow-ptr-int-transmute makes Miri accept pointers (provenance data) in integers and floats, and makes Miri treat int2ptr transmutes as equivalent to a cast.

The flag names make sense IMO, but they are somewhat inconsistent with our existing flags since we usually call things -Zmiri-disable-$CHECK rather than -Zmiri-allow-$THING. But -Zmiri-disable-uninit-number-check sounds silly?

(Whenever I say "transmute" this includes union and pointer based type punning.)
Cc @saethlin I hope this won't break everything?^^ I think the most risky part is the int2ptr transmute aspect, in particular around function pointers where no as casts are possible. The correct pattern is to first cast to a raw ptr and then transmute that to a fn ptr. We should probably document this better, in the transmute documentation and maybe in the documentation for the fn() type. I should run this PR against the std test suite before we land it.
r? @oli-obk

@RalfJung RalfJung marked this pull request as draft May 23, 2022 13:53
@RalfJung RalfJung mentioned this pull request May 23, 2022
6 tasks
@saethlin
Copy link
Member

The transmutes/type-punning are pretty rare to hit with Miri, but they're still used by futures-timer which is a pretty major crate but it hasn't seen a commit in just over 2 years and I have a PR up to fix it. As far as I can tell the most widespread use of these transmutes is turning a std::sync::Weak<T> into a usize so that it can be stored in an atomic type (this is the same pattern that std::sync::mpsc did).

Uninitialized numbers are a bit more complicated. http seems to be the biggest current user of mem::uninitialized, with rust-crypto a very distant second (which hasn't seen a commit in 6 years). There are some old versions of itoa and generic-array still in use but people with a direct dependency on those should just be able to bump their version.

@RalfJung
Copy link
Member Author

So would you recommend we leave -Zmiri-allow-uninit-numbers on by default?
A bunch of crates have Miri in CI so this change might break their CI.

But of course if the fallout is so big that we hear about it, we can also always change the default later. And I would like uninit numbers to raise errors by default at some point...

@saethlin
Copy link
Member

I think that it is much better to break a lot of CI in advance of adding an LLVM attribute which makes existing dubious code definitely UB. As you say, if it's really that bad we can back out the default. I suspect the CI fallout won't be that bad. I can't find Miri in http's CI and Miri doesn't support networking so I doubt a lot of the projects I see failures in have it in their CI. I use -Zmiri-panic-on-unsupported and --no-fail-fast which is not something I would expect anyone to do in CI.

Also, a PR to fix the use of mem::uninitialized has been up for 2 years, and the community has multiple times asked the maintainer to review the PR. We've already waited so long that I don't see any reason to keep waiting.

@RalfJung
Copy link
Member Author

The stdlib test suite is happy with this change. :)

Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request May 24, 2022
explain how to turn integers into fn ptrs

(with an intermediate raw ptr, not a direct transmute)
Direct int2ptr transmute, under the semantics I am imagining, will produce a ptr with "invalid" provenance that is invalid to deref or call. We cannot give it the same semantics as int2ptr casts since those do [something complicated](https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html).

To my great surprise, that is already what the example in the `transmute` docs does. :)  I still added a comment to say that that part is important, and I added a section explicitly talking about this to the `fn()` type docs.

With rust-lang/miri#2151, Miri will start complaining about direct int-to-fnptr transmutes (in the sense that it is UB to dereference the resulting pointer).
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request May 24, 2022
explain how to turn integers into fn ptrs

(with an intermediate raw ptr, not a direct transmute)
Direct int2ptr transmute, under the semantics I am imagining, will produce a ptr with "invalid" provenance that is invalid to deref or call. We cannot give it the same semantics as int2ptr casts since those do [something complicated](https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html).

To my great surprise, that is already what the example in the `transmute` docs does. :)  I still added a comment to say that that part is important, and I added a section explicitly talking about this to the `fn()` type docs.

With rust-lang/miri#2151, Miri will start complaining about direct int-to-fnptr transmutes (in the sense that it is UB to call the resulting pointer).
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request May 24, 2022
explain how to turn integers into fn ptrs

(with an intermediate raw ptr, not a direct transmute)
Direct int2ptr transmute, under the semantics I am imagining, will produce a ptr with "invalid" provenance that is invalid to deref or call. We cannot give it the same semantics as int2ptr casts since those do [something complicated](https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html).

To my great surprise, that is already what the example in the `transmute` docs does. :)  I still added a comment to say that that part is important, and I added a section explicitly talking about this to the `fn()` type docs.

With rust-lang/miri#2151, Miri will start complaining about direct int-to-fnptr transmutes (in the sense that it is UB to call the resulting pointer).
@bors
Copy link
Contributor

bors commented May 24, 2022

☔ The latest upstream changes (presumably #2153) made this pull request unmergeable. Please resolve the merge conflicts.

@RalfJung RalfJung marked this pull request as ready for review May 25, 2022 10:00
@RalfJung RalfJung changed the title Draft: enable number validity checking and ptr::invalid checking by default enable number validity checking and ptr::invalid checking by default May 25, 2022
@RalfJung
Copy link
Member Author

@bors r=oli-obk

@bors
Copy link
Contributor

bors commented May 25, 2022

📌 Commit 8c42ef1 has been approved by oli-obk

@RalfJung
Copy link
Member Author

@bors r=oli-obk

@bors
Copy link
Contributor

bors commented May 25, 2022

⌛ Testing commit 8c42ef1 with merge cf47776...

bors added a commit that referenced this pull request May 25, 2022
enable number validity checking and ptr::invalid checking by default

This removes the `-Zmiri-check-number-validity` flag, enabling its effects by default. (We don't error when the flag is passed, for backwards compatibility.) We also enable by default that transmuting an integer to a pointer now creates a pointer with `None` provenance, which is invalid to dereference (and, in the case of a function pointer, invalid to call). I did this together since it is all related to ptr2int/int2ptr transmutation.

Two new flags are added to optionally take back these stricter checks:
- `-Zmiri-allow-uninit-numbers` makes Miri accept uninit data in integers and floats
- `-Zmiri-allow-ptr-int-transmute` makes Miri accept pointers (provenance data) in integers and floats, *and* makes Miri treat int2ptr transmutes as equivalent to a cast.

The flag names make sense IMO, but they are somewhat inconsistent with our existing flags since we usually call things `-Zmiri-disable-$CHECK` rather than `-Zmiri-allow-$THING`. But `-Zmiri-disable-uninit-number-check` sounds silly?

(Whenever I say "transmute" this includes union and pointer based type punning.)
Cc `@saethlin` I hope this won't break everything?^^ I think the most risky part is the int2ptr transmute aspect, in particular around function pointers where no `as` casts are possible. The correct pattern is to first cast to a raw ptr and then transmute that to a fn ptr. We should probably document this better, in the `transmute` documentation and maybe in the documentation for the `fn()` type. I should run this PR against the std test suite before we land it.
r? `@oli-obk`

- [x] Ensure stdlib docs recommend "usize -> raw ptr -> fn ptr" for int-to-fnptr casts: rust-lang/rust#97321
- [x] Run the stdlib test suite
@bors
Copy link
Contributor

bors commented May 25, 2022

💡 This pull request was already approved, no need to approve it again.

  • This pull request is currently being tested. If there's no response from the continuous integration service, you may use retry to trigger a build again.

@bors
Copy link
Contributor

bors commented May 25, 2022

📌 Commit 8c42ef1 has been approved by oli-obk

@bors
Copy link
Contributor

bors commented May 25, 2022

⌛ Testing commit 8c42ef1 with merge 5832dd1...

@bors
Copy link
Contributor

bors commented May 25, 2022

☀️ Test successful - checks-actions
Approved by: oli-obk
Pushing 5832dd1 to master...

workingjubilee pushed a commit to tcdi/postgrestd that referenced this pull request Sep 15, 2022
explain how to turn integers into fn ptrs

(with an intermediate raw ptr, not a direct transmute)
Direct int2ptr transmute, under the semantics I am imagining, will produce a ptr with "invalid" provenance that is invalid to deref or call. We cannot give it the same semantics as int2ptr casts since those do [something complicated](https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html).

To my great surprise, that is already what the example in the `transmute` docs does. :)  I still added a comment to say that that part is important, and I added a section explicitly talking about this to the `fn()` type docs.

With rust-lang/miri#2151, Miri will start complaining about direct int-to-fnptr transmutes (in the sense that it is UB to call the resulting pointer).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants