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

Nuke slice_as{,_mut}_ptr methods of MaybeUninit #103133

Closed
wants to merge 3 commits into from

Conversation

SUPERCILEX
Copy link
Contributor

@SUPERCILEX SUPERCILEX commented Oct 17, 2022

These methods are of questionable value: they mix together removing bounds checks with converting the MaybeUninit slice into a raw pointer. These two behaviors should be explicitly invoked separately to improve code clarity and safety. There is evidence of unnecessary bounds checking removal in the stdlib uses that are updated in this PR.

In rust-lang/libs-team#122, there is discussion of a need for generalized containers. However, that's going to be a long ways off, so in the meantime this PR adds an into_inner method on MaybeUninit raw pointers to unwrap the raw pointer. These aren't strictly necessary and could be replaced by cast, but then you don't get and type system guarentees.

@rustbot rustbot added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Oct 17, 2022
@rustbot
Copy link
Collaborator

rustbot commented Oct 17, 2022

Hey! It looks like you've submitted a new PR for the library teams!

If this PR contains changes to any rust-lang/rust public library APIs then please comment with @rustbot label +T-libs-api -T-libs to tag it appropriately. If this PR contains changes to any unstable APIs please edit the PR description to add a link to the relevant API Change Proposal or create one if you haven't already. If you're unsure where your change falls no worries, just leave it as is and the reviewer will take a look and make a decision to forward on if necessary.

Examples of T-libs-api changes:

  • Stabilizing library features
  • Introducing insta-stable changes such as new implementations of existing stable traits on existing stable types
  • Introducing new or changing existing unstable library APIs (excluding permanently unstable features / features without a tracking issue)
  • Changing public documentation in ways that create new stability guarantees
  • Changing observable runtime behavior of library APIs

@rust-highfive
Copy link
Collaborator

r? @m-ou-se

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 17, 2022
@@ -480,7 +476,7 @@ impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);

/// Helper function for writing a u64 into `buf` going from last to first, with `curr`.
fn parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], curr: &mut usize) {
let buf_ptr = MaybeUninit::slice_as_mut_ptr(buf);
let buf_ptr = buf.as_mut_ptr().inner();
Copy link
Contributor Author

@SUPERCILEX SUPERCILEX Oct 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could potentially be replaced with a bunch of MaybeUninit::writes, but there are so many of them that I don't want to risk bounds checking perf or use get_unchecked a million times. Though maybe using get_unchecked a million times is actually better because it shows the unsafety?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add is already unsafe, so I guess probs not needed.

@SUPERCILEX SUPERCILEX force-pushed the kill-slice-ptr-uninit branch from cf04e53 to accf4dc Compare October 17, 2022 03:43
@SUPERCILEX
Copy link
Contributor Author

r? @RalfJung

@rust-log-analyzer

This comment has been minimized.

@SUPERCILEX SUPERCILEX force-pushed the kill-slice-ptr-uninit branch 4 times, most recently from 512e93b to 0bbb561 Compare October 17, 2022 04:49
@RalfJung
Copy link
Member

I'm not a libs API person, so I'm the wrong reviewer here.
r? libs

@SUPERCILEX
Copy link
Contributor Author

Right, keep forgetting, sorry! :)

@@ -346,7 +341,7 @@ impl FileEncoder {
// room to write the input to the buffer.
unsafe {
let src = buf.as_ptr();
let dst = MaybeUninit::slice_as_mut_ptr(&mut self.buf).add(buffered);
let dst = self.buf[buffered].as_mut_ptr();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This adds a runtime bounds check where there was none before. Same for all the other places where add became [...].

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. But the unsafety is centered around copy_nonoverlapping and presumably llvm can optimize out the bounds checking since it's done right above?

Happy to remove the bounds checking if that's what reviewers want, but either way get_unchecked is the method designed to express the desire to avoid bounds checking, not pointer addition IMO.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if the bounds checks here are a problem, I only know I took care to not introduce any new bounds checks when this code was originally ported to MaybeUninit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went back through and removed all the bounds checks that wouldn't be optimized out by the compiler. Anything remaining should be trivially removable.


// --- FIXME ---
// Stabilize these as From implementations.
// The only reason they aren't From is because that's insta-stable.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO into is way to implicit for use around unsafe code. Unsafe code needs clearly stated intent, so just saying "please convert this to something else" is not explicit enough.

So IMO we actually want dedicated methods here, and we need to bikeshed their name. I don't like inner but I also don't have better suggestions at the moment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with into_inner to be consistent with other APIs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know any API this is consistent with? into_inner is usually for methods of the form Type<T> -> T; I find it extremely surprising to see it here for a raw pointer method.

Something like as_inner_ptr or so maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I don't see *const Type<T> -> *const T as being too different from Type<T> -> T. I guess the difference is that one is a type cast whereas the other is providing a view into a type.

as_ is supposed to be for borrowed types—are we counting pointers as a kind of borrow for naming purposes? If so as_inner_ptr seems great or maybe even just as_inner.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see *const Type -> *const T as being too different from Type -> T

Why not? It makes a huge difference whether ownership is consume vs whether there is a form of "borrowing". We never use into_inner for methods like &Type<T> -> &T or &mut Type<T> -> &mut T. These functions here are very much like them, except they are borrowing via raw pointers, not references.

One similar function we have is UnsafeCell::raw_get. On MaybeUninit we already have as_(mut_)ptr that take references; now here we have the exact same methods using raw pointers so the naming should be similar. raw_as_ptr sounds odd though...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotya, I wasn't really thinking of pointers as references for naming but you're totally right that makes more sense. raw_as_ptr does seems a little weird, but it would be consistent... will rename.

@Noratrieb
Copy link
Member

If you have to add a completely new method to actually replace these methods, then maybe they aren't ready for removal imo. You should add the new method through the correct processes first, and then we can maybe remove these later.

Also I agree with Ralf that these should not be From impls at all.

@SUPERCILEX
Copy link
Contributor Author

Agreed. See rust-lang/libs-team#122 (comment). Let's let this sit until the other MaybeUninit stuff is resolved and I'll give this some more thought.

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 17, 2022
@Dylan-DPC Dylan-DPC added S-blocked Status: Blocked on something else such as an RFC or other implementation work. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Dec 13, 2022
@JohnCSimon
Copy link
Member

@SUPERCILEX
ping from triage - can you post your status on this PR? There hasn't been an update in a few months. Is thanks still blocked? Thanks!

@SUPERCILEX
Copy link
Contributor Author

Alrighty, I created rust-lang/libs-team#245 because I think creating a small, focused ACP will help move things forward.

@SUPERCILEX SUPERCILEX force-pushed the kill-slice-ptr-uninit branch from 4684c50 to 4c97cda Compare June 27, 2023 18:00
@SUPERCILEX
Copy link
Contributor Author

SUPERCILEX commented Jun 27, 2023

@rustbot ready

ACP resolution: rust-lang/libs-team#245 (comment)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 27, 2023
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
@SUPERCILEX SUPERCILEX force-pushed the kill-slice-ptr-uninit branch from 4c97cda to b602bbf Compare June 30, 2023 21:04
@workingjubilee workingjubilee added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. and removed T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jul 26, 2023
@workingjubilee
Copy link
Member

Do we need FCP or something for posterity, or should this just be r+'d? Can I even
r? libs-api

@rustbot rustbot assigned dtolnay and unassigned Mark-Simulacrum Jul 26, 2023
@RalfJung
Copy link
Member

RalfJung commented Jul 26, 2023 via email

@RalfJung
Copy link
Member

RalfJung commented Jul 26, 2023

There is evidence of unnecessary bounds checking removal in the stdlib uses that are updated in this PR.

Which ones did you think were unnecessary? As far as I am aware, most/all of these are ported from old pre-MaybeUninit code that already did not have bounds checks. So the removal was entirely deliberate, and not related to the signature of these methods.

FWIW I agree that with a raw ptr projection method (*mut MaybeUninit<T> -> *mut T) this becomes clearer, albeit more verbose. But reverting to cast strikes me as a bad intermediate step. It makes the code harder to read and it is unlikely to be ported to the raw ptr projection method once that exists (since how would we even find the places where it can be used).

@dtolnay dtolnay changed the title Nuke slice_as{,_mut}_ptr methods Nuke slice_as{,_mut}_ptr methods of MaybeUninit Jul 31, 2023
@SUPERCILEX
Copy link
Contributor Author

Which ones did you think were unnecessary?

Take a look at all the places I used slicing operators in num.rs for this commit: f2e9b40 (#103133). All of those should have probably eliminatable bounds checks.

But reverting to cast strikes me as a bad intermediate step.

Yeah, that's fair. So do those two changes need to happen together?

@RalfJung
Copy link
Member

RalfJung commented Aug 2, 2023

"should have probably" is fairly weak. This is all unsafe code because it is considered performance-sensitive. And this code is old, it used unchecked accesses already before it used MaybeUninit:

https://github.com/rust-lang/rust/blob/c11e514e9dfd44eebe435408b32de4193d87860c/src/libcore/fmt/num.rs

Notice all the offset. They were added in ebf9e1a.

So this is definitely not evidence that the current API leads to omitted bounds checks.

So do those two changes need to happen together?

I would personally prefer that. I don't have the power to block changes in this part of the compiler though.

@SUPERCILEX
Copy link
Contributor Author

"should have probably"

Typo that autocorrect keeps trying to put in, sorry. Should have provably. As in if they don't get optimized out it's an llvm bug.

I would personally prefer that.

Yeah I think that's reasonable unfortunately. I'll have time to look into this in a month or two again.

@apiraino
Copy link
Contributor

Based on the prev. comment switching to waiting on author to incorporate changes. Feel free to request a review with @rustbot ready, thanks!

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 31, 2023
@bors
Copy link
Contributor

bors commented Sep 21, 2023

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

@JohnCSimon
Copy link
Member

@SUPERCILEX
ping from triage - can you post your status on this PR? There hasn't been an update in a few months. Thanks!

FYI: when a PR is ready for review, send a message containing
@rustbot ready to switch to S-waiting-on-review so the PR is in the reviewer's backlog.

@SUPERCILEX
Copy link
Contributor Author

This PR is waiting on me to figure out what to do with *{const,mut} MaybeUninit<T> to *{const,mut} T ptr casts. Hoping to have time to think about this in December/January.

@dtolnay dtolnay added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Nov 23, 2023
@Dylan-DPC
Copy link
Member

@SUPERCILEX any updates on this?

@SUPERCILEX
Copy link
Contributor Author

I'll close for now. I still think these methods should be removed, but sadly don't have the time to see that work through right now.

@SUPERCILEX SUPERCILEX closed this Apr 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.