-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Deny unsafe ops in unsafe fns in libcore #73622
Conversation
ptr::write_bytes(ptr, 0, size); | ||
// SAFETY: as allocation succeeded, the region from `ptr` | ||
// of size `size` is guaranteed to be valid for writes. | ||
unsafe { ptr::write_bytes(ptr, 0, size) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually a great example where we do still do local unsafety reasoning inside an unsafe fn
, instead of just forwarding requirements to the caller.
01c0283
to
59e7888
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Holy detailed-unsafety-comments, Batman! This is good work, though to properly review is going to take some time and detailed reading :)
Which is why I wanted to do it bit by bit 😄 . Please take your time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I read over as best I could, admittedly somewhat skimming. I have one nit but also some meta-thoughts (that don't mean we shouldn't take the PR). Basically, what I found myself really wanting was a clearer way to say "this is a requirement we pass onto the caller" versus "this is an unsafe requirement we locally prove". I sort of wish we had distinct keywords for that or something like this.
cf17082
to
991d931
Compare
☔ The latest upstream changes (presumably #73838) made this pull request unmergeable. Please resolve the merge conflicts. |
If we're going to land this, I'm inclined to land it and then land successive improvements to the comments as people notice them. |
(I think we should land it) |
In that case shall I add the last unsafe blocks and slap some |
991d931
to
b365233
Compare
@nikomatsakis This is now ready for a final review, and hopefully merging! |
1b7bc93
to
5ba33d1
Compare
And final part!!!
5ba33d1
to
a1623ff
Compare
@LeSeulArtichaut CI seems unhappy |
Seems like some UI tests are failing. I really don't want to do a full compilation of the compiler for this though, tbh 😅 |
713c3ae
to
800906d
Compare
800906d
to
6a7a652
Compare
CI should pass now. |
@@ -189,12 +189,14 @@ macro_rules! step_identical_methods { | |||
() => { | |||
#[inline] | |||
unsafe fn forward_unchecked(start: Self, n: usize) -> Self { | |||
start.unchecked_add(n as Self) | |||
// SAFETY: the caller has to guarantee that `start + n` doesn't overflow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: the vast majority of comments in these diffs take this form (i.e., "Caller must guarantee X"). Interestingly, usually in functions that have no associated comments, presumably because they are trait impls or in some other context where the comment is elsewhere.
Anyway, the question is -- do we think these comments make sense / add-value? Should we have some shorthand?
I think this comment is a good example where I feel there is added value -- i.e., this doesn't just say "some unsafe thing" but it is rather specific about what we are assuming.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion, a detailed safety comment is useful:
- when the conditions that the caller must guarantee are only a subset of all the conditions required to call do the unsafe operation, because there are other invariants that we prove through other means. I think it is absolutely useful to have a detailed safety comments in these cases.
- when only a part of what the caller must guarantee is used, because the other guarantees are used elsewhere in the function. In this case, I think safety comments are useful because they help readers understand where the safety contract comes from, which I think is useful for contributors, or even for any consumer of the standard library who wants to understand where constraints come from.
I'm not an experienced rustacean used to writing unsafe stuff though, and I probably have too few experience to have a good opinion about all of this.
@@ -699,7 +707,8 @@ impl<T: ?Sized> *const T { | |||
where | |||
T: Sized, | |||
{ | |||
read_unaligned(self) | |||
// SAFETY: the caller must uphold the safety contract for `read_unaligned`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an example of a comment that doesn't add a lot of information, but I don't know that I would change it. =)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this kinds of comments mostly in functions where the call is actually delegated to another function, without any additional elements coming from the content of this function. Like:
unsafe fn do_x() {
unsafe { actually_do_x() }
}
In most of these cases, either the safety conditions are written in the doc comments for do_x
because it is a "public interface" function, or there are no comments anywhere because it's an entirely internal function and that makes it really difficult to reason about safety contracts and I was unable to write more detailed comments.
@bors r+ Thought about it, I think we should move, we can always pare back comments later if we decide to do so. |
📌 Commit 6a7a652 has been approved by |
…ikomatsakis Deny unsafe ops in unsafe fns in libcore After `liballoc`, It's time for `libcore` :D I planned to do this bit by bit to avoid having a big chunk of diffs, so to make reviews easier, and to make the unsafe blocks narrower and take the time to document them properly. r? @nikomatsakis cc @RalfJung
…arth Rollup of 10 pull requests Successful merges: - rust-lang#73414 (Implement `slice_strip` feature) - rust-lang#73564 (linker: Create GNU_EH_FRAME header by default when producing ELFs) - rust-lang#73622 (Deny unsafe ops in unsafe fns in libcore) - rust-lang#73684 (add spans to injected coverage counters, extract with CoverageData query) - rust-lang#73812 (ast_pretty: Pass some token streams and trees by reference) - rust-lang#73853 (Add newline to rustc MultiSpan docs) - rust-lang#73883 (Compile rustdoc less often.) - rust-lang#73885 (Fix wasm32 being broken due to a NodeJS version bump) - rust-lang#73903 (Changes required for rustc/cargo to build for iOS targets) - rust-lang#73938 (Optimise fast path of checked_ops with `unlikely`) Failed merges: r? @ghost
After
liballoc
, It's time forlibcore
:DI planned to do this bit by bit to avoid having a big chunk of diffs, so to make reviews easier, and to make the unsafe blocks narrower and take the time to document them properly.
r? @nikomatsakis cc @RalfJung