-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
feat: split unsafe_code
lint into lint group
#108975
Conversation
(rustbot has picked a reviewer for you, use r? to override) |
Thanks for the PR, @Ezrashaw! I'd be grateful for some input from @rust-lang/lang, since this is changing the behavior of the |
I don't think we should do this right now, because making promises to other unsafe code is possible even if there's nothing unsafe in the body of a function. The standard example being that I think what the situation in the issue actually wants is https://rust-lang.github.io/rfcs/2316-safe-unsafe-trait-methods.html, so that it's then not an The other thing that might make this more reasonable would be some kind of |
@scottmcm Right, so there are a few points here that I'll address but I'm just the implementer so cc @chbaker0:
Yes it does, and it gets that by also requiring
I don't quite understand? That sounds like a whole new language feature? I'm not quite sure what |
Modules are the boundary between safety and unsafety. I think this is generally true for an So, an Also like @Ezrashaw said,
I'm not sure I understand what problem this solves. If a module internally has I could only possibly see this as a way of pushing the safety assertion to a different place. Like, instead of struct FooData {...}
unsafe fn foo(data: FooData) {...}
unsafe { foo(FooData {...}) } you could do unsafe struct FooData {...}
fn foo(data: FooData) {...}
foo(unsafe { FooData {...} }) So that constructing struct FooData {...}
impl FooData {
unsafe fn new(...) -> FooData {...}
}
fn foo(data: FooData) |
By the way, the |
Exactly, well put. To summarize: not all use of the |
Note that @rcvalle began a very long quest to implement compiler-based CFI and has made many negotiations with us about this based, in part, on someone else's paper about mere exposed interfaces. That paper had the premise that Rust-defined code that would be caught by the if mixed_codebase.contains(["C", "Rust"]) {
assert_eq!(mixed_codebase.security, Security::Unsound);
} I have... several disagreements with that paper's premise and conclusions, but I think the essential complaint about the In particular, it doesn't make sense to change the |
What about having an |
☔ The latest upstream changes (presumably #108682) made this pull request unmergeable. Please resolve the merge conflicts. |
Yeah, I can't speak for lang much less all of T-lang but I have no objection to promoting |
Could that be done in this PR? Does it need a FCP or anything? I'm happy to implement this. |
40a87fc
to
dad074f
Compare
unsafe_code
lint tweakingunsafe_code
lint into lint group
@workingjubilee @chbaker0 I've implemented the new lint group. Could you review please? |
r? lang |
☔ The latest upstream changes (presumably #109503) made this pull request unmergeable. Please resolve the merge conflicts. |
@nikomatsakis I've just seen a issue with this PR. It stops |
Hello, visiting this PR, checking for progress cc @nikomatsakis :) (In case, feel free to re-roll the review T-lang assignment) |
That would not be acceptable. |
@workingjubilee Of course. I looked a bit closer and the tracking issue is #81670. TLDR is that it's a future compatibility lint because For this PR, we can probably just made an exception (which will be removed when forbidding lint groups is fully fixed). I'm happy to implement this if it's wanted (the original point of this PR remains). |
Lang team needs to weigh in on whether this should be done. (Not yet sure if it needs an FCP from T-lang, or just a champion) @rustbot label: I-lang-nominated |
@rustbot label: +T-lang -T-compiler +S-waiting-on-team |
Also @jyn514 notes that:
|
Agreed that we cannot make this change until |
This issue was discussed in the lang-team meeting today. There was some sympathy for the idea that creating and discharging With respect to #108926 (which seems to have motivated this PR), the feeling was that use-case may be better addressed by an implementation of the safe impls for @Ezrashaw: What do you think? |
@traviscross Well, firstly I'd just say that I don't have a really strong view on this. With that in mind, I think that this issue extends to more than just trait functions; free functions have the same problem. There is still a difference between upholding and defining safety invariants (there might be better terms for this that I'm not aware of). For example, consider the following definition: (1) // SAFETY: The wrapped `String` must consist only of uppercase ASCII characters.
struct OnlyUppercase(String);
impl OnlyUppercase {
// SAFETY: `OnlyUppercase`'s invariants must be upheld.
pub unsafe fn new_unchecked(value: String) -> Self {
Self(value)
}
} And the following function: (2) fn create_only_uppercase() -> OnlyUppercase {
// SAFETY: The provided string literal only has uppercase ASCII characters.
unsafe { OnlyUppercase::new_unchecked("RUST".to_owned()) }
} (note that this example will become better with unsafe fields; they might be another use-case for this change) While both of these code snippets use the At first glance, this point may seem to be minor. However, we should note that in the first code example there is no possibility of Undefined Behavior. Period. To be clear, 1 could rely on this invariant for safety reasons, however if Undefined Behavior were to occur, the code which failed to uphold the invariant would be at fault, not the example. In other words, use of the This becomes important when we consider that the first example is (could be) library code and the second user code. Libraries may not want to uphold complex invariants which could cause UB (in my experience, "no unsafety" is often in Github READMEs, etc). They expect to be able to "prove" this with Again, I'm not anywhere near as experienced as anyone on the library team, so take this with a grain of salt. (please note that I'm not really contributing right now, so I might take a while to respond) |
@Ezrashaw: Thanks for that. However, in the meeting people were struggling to come up with an example of why a library would export unsafety without also using unsafety internally. In your example 1, for example, why does the library need the caller to uphold that invariant unless it's internally going to do something unsafe with it? (Because if it does something unsafe internally with it, then If you could extend that example to show how exporting that invariant might be useful (without the library using unsafety internally), that would answer the question that people had about this. |
@traviscross Well, I think that generally it is possible to have "higher-level" invariants which aren't UB-related. For example, a lexer I wrote recently (in Rust) required input to be ASCII. It was like this because Unicode characters could muck up Also, I'd still say that it isn't a big, big change (i.e. |
I would be against any lints that implicitly encourage " A type can have correctness invariants, and even both // Correctness invariant only; do not rely on in unsafe code.
pub struct Even(u32);
impl Even {
fn new(val: u32) -> Option<Self>;
fn new_unchecked(val: u32) -> Self;
}
// Safety: unsafe code is allowed to rely on the field being odd
pub struct Odd(u32);
impl Odd {
fn new(val: u32) -> Option<Self>;
unsafe fn new_unchecked(val: u32) -> Self;
}
Totally unrelated to this PR, but |
Based on Scott's analysis: @rfcbot close |
Team member @joshtriplett has proposed to close this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
The declaration of an I have to admit I am quite surprised that |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
The final comment period, with a disposition to close, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. |
Closing this per FCP. @RalfJung You're not wrong about |
Is "just stop denying |
I would prefer we not to relax the lint on definitions until we have a clearer story about linting here, partly because such an exception seems like it would be very prone to accidentally allowing other unsafe definitions I may want to catch using linting. |
Fixes #108926
See discussion in linked issue. This PR allows some use of theunsafe
keyword where no actual unsafety (as in tangible memory issues) could occur, under theunsafe_code
lint.EDIT: This PR introduces a new lint group:
unsafe_code
which contains two new lints which replaceunsafe_code
:unsafe_obligation_discharge
andunsafe_obligation_define
. These splitunsafe_code
into code that can cause Undefined Behaviour and code which has theunsafe
token but, importantly, cannot introduce Undefined Behaviour. See discussion here and on the linked issue.