Skip to content

Lint at deny-by-default against references to static mut #128794

Closed
@traviscross

Description

@traviscross

We had earlier decided to disallow references to static mut in:

Later, we decided to disallow hidden references to mutable statics also:

Since then, some interesting cases have come up in:

These interesting cases revolve around how we desugar syntax for equality, comparison, compound assignment, and indexing. There are two aspects.

One, though PartialEq::eq, PartialOrd::lt, AddAssign::add_assign, Index::index, and IndexMut::index_mut all take references, for primitive types, as implemented today in lowering to MIR, these operations don't generate references at all. E.g., no references at all are created here:

fn f(x: u8) {
    static mut S: u8 = 1;
    static mut T: [u8; 1] = [0; 1];
    unsafe {
        _ = S == S;
        _ = S < S;
        S += x;
        S += T[0];
        T[0] = x;
    }
}

This behavior is documented for compound assignment expressions, but not otherwise (as far as I can tell).

Two, even if acting on wrapper types where a reference would be generated, the signatures of these methods guarantee that the reference is not leaked and is short-lived. That is, there's no possible sound implementation of AddAssign::add_assign, for any type, that would cause this:

static mut S: W<u8> = W(1);
unsafe { S += W(x); };

...to have any additional UB as compared with:

static mut S: W<u8> = W(1);
unsafe { S = S + W(x); }

...which raises the question of why we would want to treat these differently, and why we would want to encourage people to write the latter rather than the former.


In the 2024-08-07 triage meeting, we discussed whether making references to mutable statics a hard error actually met our bar for hard errors. In other cases, we've chosen that only when doing so would make the language definition in a future edition simpler. Otherwise, we've stopped at a deny-by-default lint.

We discussed how, if we made this a lint rather than a hard error, we might have more room to maneuver.

This is what the comment by @scottmcm below is in reply to. However, we did not reach an actual consensus in the meeting.

Also, we did not discuss in the meeting the second aspect described above about how short-lived references are UB-equivalent to accesses.


Proposal

On the table in this issue is the following proposal:

  1. Upgrade the static_mut_ref lint to deny-by-default in Rust 2024.
    • That would replace and remove the current hard error for references to mutable statics in Rust 2024.
    • Doing this as a lint would give us more room to maneuver.
    • This case does not meet our bar for doing a hard error since it does not make the language definition any simpler in the new edition, and we've stopped at deny-by-default in other cases like this.
  2. Extend, in all editions, static_mut_ref to lint against "hidden references" (that is, references created by virtue of autoref).
    • This follows the decision in #123060 except that a deny-by-default lint rather than a hard error would be used in Rust 2024.
    • This extension is justified because a reference that is created by autoref and then leaked is just as dangerous as any other reference to a static mut.
  3. As feasible, do not lint in cases (whether explicit or due to autoref) where the compiler can prove that the reference is not created or does not leak.
    • This resolves how to handle the open questions in #124895.
    • An operation that does not create a reference, or a use where we can prove that the reference does not leak, has no additional UB as compared with any other access to the static mut. There's no reason for us to push people away from these patterns and into other patterns that have no more or less potential for UB.
    • We'd start by not linting in the cases where we can tell from the MIR that no reference is created, then later work could do more to avoid linting against other cases where such a proof is feasible. This later work would not be required to ship this lint or the edition.

cc @obeis @RalfJung @rust-lang/lang

Tracking:

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.C-discussionCategory: Discussion or questions that doesn't represent real issues.T-langRelevant to the language teamdisposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.finished-final-comment-periodThe final comment period is finished for this PR / Issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions