Skip to content

RFC: Safety Tags #3842

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

Open
wants to merge 41 commits into
base: master
Choose a base branch
from
Open

RFC: Safety Tags #3842

wants to merge 41 commits into from

Conversation

zjp-CN
Copy link

@zjp-CN zjp-CN commented Jul 31, 2025

Summary

This RFC introduces a concise safety-comment convention for unsafe code in standard libraries:
tag every public unsafe function with #[safety::requires] and call with #[safety::checked].

Safety tags refine today’s safety-comment habits: a featherweight syntax that condenses every
requirement into a single, check-off reminder.

The following snippet compiles today if we enable enough nightly features, but we expect Clippy
and Rust-Analyzer to enforce tag checks and provide first-class IDE support.

#[safety::requires { // 💡 define safety tags on an unsafe function
    ValidPtr = "src must be [valid](https://doc.rust-lang.org/std/ptr/index.html#safety) for reads",
    Aligned = "src must be properly aligned, even if T has size 0",
    Initialized = "src must point to a properly initialized value of type T"
}]
pub unsafe fn read<T>(ptr: *const T) { }

fn main() {
    #[safety::checked { // 💡 discharge safety tags on an unsafe call
        ValidPtr, Aligned, Initialized = "optional reason"
    }]
    unsafe { read(&()) };
}

Rendered

@zjp-CN zjp-CN requested a review from ia0 August 1, 2025 06:44
Co-authored-by: kennytm <kennytm@gmail.com>
@burdges
Copy link

burdges commented Aug 3, 2025

@zjp-CN > Do you indicate tags work bad on nested unsafe calls?

I've no opinion on this RFC, or the previous one, or when one should create some static analysis plugin interface.

I'm only pointing out that an unsafe counter achieves lots, without increasing the langauge complexity much, so imho most developers would use an unsafe counter, not a claim we can make for more complex schemes. That doesn't say those schemes do not have a place.

@ia0
Copy link

ia0 commented Aug 4, 2025

I agree forcing checked clauses to be on unsafe calls might be too restrictive (in particular in comparison with current practices of having unsafe comments on unsafe blocks). However this unsafe counter seems a completely different proposal, which doesn't address most of the concerns this RFC address (like catching unsafe functions that change their requirements between 2 major versions).

Maybe a mix between a previous version of this RFC and the current one would be better, namely that checked clauses can be written anywhere between the unsafe call itself and the closest unsafe block containing it.

@zjp-CN
Copy link
Author

zjp-CN commented Aug 4, 2025

IIUC unsafe counter is a practice to alert unsafe operations are not checked against their safety requirements.

It's a piece of linter work: undocumented_unsafe_blocks, but on unsafe operations (calls, and other unsafety), so maybe name it undocumented_unsafe_operations.

Discharge of safety tags can be considered a rigorous undocumented_unsafe_operations lint as @ia0 points out, and a design on machine-readable/checkable safety requirements.

checked clauses can be written anywhere between the unsafe call itself and the closest unsafe block containing it.

checked can be attached to an unsafe block as long as the block containing single unsafe call (no restriction on how many safe calls are in it).

@ia0
Copy link

ia0 commented Aug 4, 2025

checked can be attached to an unsafe block as long as the block containing single unsafe call (no restriction on how many safe calls are in it).

Right. What I meant was to also permit this when there are multiple unsafe calls within the unsafe block (or expression) where the checked clause is present. The semantics would be that the checked clause needs to contain the union (with or without duplicates, TBD) of the unsafe call tags. That's not "clean", but it gives some amount of freedom to users that could help in such situations where multiple unsafe calls are chained. This is a trade-off essentially.

@zjp-CN
Copy link
Author

zjp-CN commented Aug 4, 2025

checked clause needs to contain the union (with or without duplicates, TBD) of the unsafe call tags. That's not "clean"

Yeah, I thought about that too. And it's basically suggesting

#[safety::checked(TagForCall1, TagForCall2)]
unsafe { call1(call2()) }

// or
#[safety::checked(TagForCall1, TagForCall2)]
unsafe { call1(); call2(); }

It's not allowed in this RFC due to exactly what you said, instead split inner results into assignments as mentioned above.

@ia0
Copy link

ia0 commented Aug 4, 2025

It's not allowed in this RFC due to exactly what you said

Ok, so there's no trade-off. That's fine for me, I'm just noticing that some may find this too strict. But then writing unsafe code is not necessarily supposed to be an enjoyable experience, so biasing towards "safety"/"precision" to the detriment of "user experience" is understandable. It just needs to be a deliberate choice and not an oversight of the consequences.

@zjp-CN
Copy link
Author

zjp-CN commented Aug 4, 2025

Not too relevant to this RFC, but I just saw an OSDI paper Paralegal: Practical Static Analysis for Privacy Bugs (repo) introduces markers as a key abstraction for mapping the policy onto the program. Basically it maps English texts to lightweight attributes in source code to find bugs.

Co-authored-by: kennytm <kennytm@gmail.com>
@alice-i-cecile
Copy link

This flavor of thing would be nice to introduce more structure (and the possibility for automated tooling) into complex unsafe code bases like bevy_ecs, which I help maintain.

@jswrenn jswrenn mentioned this pull request Aug 7, 2025
Copy link

@danjl1100 danjl1100 left a comment

Choose a reason for hiding this comment

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

I really like the direction this is moving with requires and checked since the initial version.

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.