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

Deny unsafe ops in unsafe fns in libcore #73622

Merged
merged 7 commits into from
Jul 2, 2020

Conversation

LeSeulArtichaut
Copy link
Contributor

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

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 22, 2020
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) };
Copy link
Member

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.

src/libcore/alloc/mod.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@nikomatsakis nikomatsakis left a 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 :)

@LeSeulArtichaut LeSeulArtichaut changed the title Deny unsafe ops in unsafe fns Deny unsafe ops in unsafe fns in libcore Jun 23, 2020
@LeSeulArtichaut
Copy link
Contributor Author

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.
Maybe we can cc more people from the compiler/libs teams to read and check the safety comments?

Copy link
Contributor

@nikomatsakis nikomatsakis left a 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.

src/libcore/cell.rs Outdated Show resolved Hide resolved
@LeSeulArtichaut LeSeulArtichaut force-pushed the unsafe-libcore branch 2 times, most recently from cf17082 to 991d931 Compare June 25, 2020 18:19
@bors
Copy link
Contributor

bors commented Jun 28, 2020

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

@nikomatsakis
Copy link
Contributor

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.

@nikomatsakis
Copy link
Contributor

(I think we should land it)

@LeSeulArtichaut
Copy link
Contributor Author

LeSeulArtichaut commented Jun 29, 2020

In that case shall I add the last unsafe blocks and slap some ignore-tidy-undocumented?
(I need to rebase it anyway)

@LeSeulArtichaut LeSeulArtichaut marked this pull request as ready for review June 30, 2020 17:10
@LeSeulArtichaut
Copy link
Contributor Author

@nikomatsakis This is now ready for a final review, and hopefully merging!

@nikomatsakis
Copy link
Contributor

@LeSeulArtichaut CI seems unhappy

@LeSeulArtichaut
Copy link
Contributor Author

Seems like some UI tests are failing. I really don't want to do a full compilation of the compiler for this though, tbh 😅
I'm going to try to bless the tests by hand, to further test my copy-pasting skills!

@LeSeulArtichaut
Copy link
Contributor Author

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.
Copy link
Contributor

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.

Copy link
Contributor Author

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`.
Copy link
Contributor

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. =)

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 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.

@nikomatsakis
Copy link
Contributor

@bors r+

Thought about it, I think we should move, we can always pare back comments later if we decide to do so.

@bors
Copy link
Contributor

bors commented Jul 1, 2020

📌 Commit 6a7a652 has been approved by nikomatsakis

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 1, 2020
Manishearth added a commit to Manishearth/rust that referenced this pull request Jul 1, 2020
…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
bors added a commit to rust-lang-ci/rust that referenced this pull request Jul 2, 2020
…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
@bors bors merged commit 500634b into rust-lang:master Jul 2, 2020
@LeSeulArtichaut LeSeulArtichaut deleted the unsafe-libcore branch July 2, 2020 17:40
@cuviper cuviper added this to the 1.46 milestone May 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants