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

Disallow *references* to static mut [Edition Idea] #114447

Closed
Tracked by #172
scottmcm opened this issue Aug 4, 2023 · 45 comments · Fixed by #117556
Closed
Tracked by #172

Disallow *references* to static mut [Edition Idea] #114447

scottmcm opened this issue Aug 4, 2023 · 45 comments · Fixed by #117556
Assignees
Labels
A-edition-2024 Area: The 2024 edition A-maybe-future-edition Something we may consider for a future edition. E-help-wanted Call for participation: Help is requested to fix this issue. E-medium Call for participation: Medium difficulty. Experience needed to fix: Intermediate. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@scottmcm
Copy link
Member

scottmcm commented Aug 4, 2023

Now that we have ptr::addr_of_mut!, the 2024 edition would be a great time to do @RalfJung's idea from #53639 (comment):

Disallow &MY_STATIC_MUT and &mut MY_STATIC_MUT entirely.

ptr::addr_of_mut!(MY_STATIC_MUT) could even be safe -- unlike taking a reference which is unsafe and often insta-UB -- and helps encourage avoiding races in the accesses, which is more practical than trying to avoid the UB from concurrent existence of references.

(Maybe people will end up just doing &mut *ptr::addr_of_mut!(MY_STATIC_MUT) without thinking through all the safety requirements -- in particular, making sure that the reference stops being used before a second reference is created -- but we can't force them to drink.)

@scottmcm scottmcm added T-lang Relevant to the language team, which will review and decide on the PR/issue. A-maybe-future-edition Something we may consider for a future edition. I-lang-nominated Nominated for discussion during a lang team meeting. labels Aug 4, 2023
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Aug 4, 2023
@Noratrieb Noratrieb removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Aug 4, 2023
@scottmcm scottmcm added E-help-wanted Call for participation: Help is requested to fix this issue. A-edition-2024 Area: The 2024 edition labels Sep 5, 2023
@Lokathor
Copy link
Contributor

Lokathor commented Sep 5, 2023

I think that this would be much better if methods on a type could take *mut self, instead of only allowing &mut self, but that's not a hard blocker.

@scottmcm scottmcm added the E-medium Call for participation: Medium difficulty. Experience needed to fix: Intermediate. label Sep 5, 2023
@scottmcm
Copy link
Member Author

scottmcm commented Sep 5, 2023

We discussed this in the lang team meeting today, and the consensus was in favour of going in this direction.

(With https://doc.rust-lang.org/std/cell/struct.SyncUnsafeCell.html and https://doc.rust-lang.org/std/ptr/macro.addr_of_mut.html we have options that we didn't back in 2018.)

Steps needed, I think:

  • Add a lint that warns on using a & or &mut to a static mut, with some help suggesting other options.
  • Make doing so a hard error in 2024 (in addition to the lint that affects the other editions)

@obeis
Copy link
Contributor

obeis commented Sep 14, 2023

@rustbot claim

@traviscross
Copy link
Contributor

@rustbot labels -I-lang-nominated

I'm going to unnominate this, since there's nothing more to discuss until there is a PR to review. Please nominate such a PR as soon as it is posted.

(This is correctly labeled so we can track it with other ideas for the next edition without the nomination.)

@rustbot rustbot removed the I-lang-nominated Nominated for discussion during a lang team meeting. label Oct 24, 2023
@scottmcm
Copy link
Member Author

scottmcm commented Nov 1, 2023

@obeis Any updates? Have you managed to make progress here?

@obeis
Copy link
Contributor

obeis commented Nov 1, 2023

@scottmcm almost done. I will submit my pull request within the next two days at the latest. I apologize for the delay.

@RalfJung
Copy link
Member

RalfJung commented Dec 2, 2023

While implementing the lint in #117556, the question came up whether various cases of implicitly taking a reference should be linted against:

static mut STATIC = &[0, 1, 2];

let _ = STATIC.len();
let _ = STATIC[0];
let _ = format!("{}", STATIC);

The three listed cases are (fairly) harmless. However, let val = z.get() might not be harmless if get returns a 'static reference.

@scottmcm (and t-lang in general), what is your opinion on that?

@est31
Copy link
Member

est31 commented Dec 2, 2023

Personally I lean towards deprecating these cases, too, if the idea is that we want to mostly deprecate static mut anyways. As pointed out above, dot syntax can be used to create references without involving any &, so the creation of the potentially dangerous reference is quite hidden. By extension [] syntax and even field access syntax is in similar positions as well, when the type that they give access to is a static reference: but there you don't create a new reference but only access an existing one (example: static mut ST = (&[&0, &1, &2], &3); let _ = ST.0[0]; let _ = ST.1;).

@scottmcm
Copy link
Member Author

scottmcm commented Dec 4, 2023

I think this should be linting about anything that's created enough of a reference to trigger the reference rules -- if it can trigger UB when someone else holds a &mut to the static, that's worth linting about here.

@ravenexp
Copy link

ravenexp commented Dec 5, 2023

Are Vec::leak() and the like still OK under the new rules?

@Lokathor
Copy link
Contributor

Lokathor commented Dec 5, 2023

This discussion is only about static mut variables (which can easily cause UB), not &mut T references with a 'static lifetime (which are 100% and UB free).

So Vec::leak and Box::leak and similar are unaffected.

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jan 3, 2024
…twco

Disallow reference to `static mut` and adding `static_mut_ref` lint

Closes rust-lang#114447

r? `@scottmcm`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jan 5, 2024
…twco

Disallow reference to `static mut` and adding `static_mut_ref` lint

Closes rust-lang#114447

r? `@scottmcm`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jan 5, 2024
…twco

Disallow reference to `static mut` and adding `static_mut_ref` lint

Closes rust-lang#114447

r? ``@scottmcm``
bors added a commit to rust-lang-ci/rust that referenced this issue Jan 7, 2024
Disallow reference to `static mut` and adding `static_mut_ref` lint

Closes rust-lang#114447

r? `@scottmcm`
@uazu
Copy link

uazu commented May 29, 2024

Note that I don't find this particularly persuasive, since as far as the linker sees, static mut FOO: i32 and static FOO: SyncUnsafeCell<i32> are exactly the same. They're just as efficient.

Is there something you're seeing that actually needs static mut specifically, as opposed to static-with-UnsafeCell-internally?

Okay, I thought you were thinking of getting rid of mutable statics entirely. The 1.78 compiler warning which brought me to this page only mentioned addr_of_mut! and didn't say anything about static with UnsafeCell. So that is what we're supposed to use now instead of static mut? I really don't mind. I will switch if that is now the approved way. (Since you can get a *mut either way does it make any difference to safety? The coder still needs to know what they're doing.)

@RalfJung
Copy link
Member

RalfJung commented May 29, 2024

(Since you can get a *mut either way does it make any difference to safety? The coder still needs to know what they're doing.)

That's exactly why we are only deprecating references to static mut for now and encourage moving to raw pointers instead. Some people are arguing we should ban static mut entirely but so far those people have not managed to convince the team(s) that that step would be worth it.

My personal opinion is that switching from static mut with only raw pointers to static SyncUnsafeCell mostly feels like needless extra paperwork. So as far as I am concerned, if you're using static mut and raw pointers throughout, you're good. The moment you create references from those raw pointers you need to be extremely careful, and you should make them as short-lived as possible.

@scottmcm
Copy link
Member Author

Well, the simplest transition is to https://doc.rust-lang.org/std/cell/struct.SyncUnsafeCell.html, but unfortunately that's not yet stable :( You can always also make your own types with appropriate unsafe impls that use UnsafeCell internally -- that's all SyncUnsafeCell is.

Since you can get a *mut either way does it make any difference to safety?

The differences are in whether you get a reference directly. *muts are allowed to alias, so you can make new ones all day long and keep them around -- the only problems are when you actually read or write through them. Whereas multiple independent live &muts at the same time is UB even without a data race. So that's the difference in footgun-ness.

@uazu
Copy link

uazu commented May 30, 2024

This is clearer now, thanks. I can see the justification for some kind of static ... UnsafeCell approach instead of static mut because it does express the problems with mutable globals better in Rust terms, and the coder might be persuaded to read the UnsafeCell docs. It's not any safer for someone who is just copy/pasting incantations, though.

However, I couldn't use SyncUnsafeCell because I'm storing non-Sync types protected by a thread-ID check. So I needed to do what @eddyb explains at the top of #53639, i.e. create my own wrapper type that has an unsafe impl Sync and then justify the safety in comments. So telling everyone to use SyncUnsafeCell isn't going to work, unless the docs for SyncUnsafeCell explain that it doesn't cover all cases.

I don't think my new code is any better or worse without static mut, because I was already careful. It has 40% more LOC and has two more unsafe keywords. There's not much in it.

@yanchith
Copy link
Contributor

yanchith commented May 31, 2024

My personal opinion is that switching from static mut with only raw pointers to static SyncUnsafeCell mostly feels like needless extra paperwork.

I feel this way too, and am glad that you do, too!

Still, if there's some busywork to discourage misuse, I can live with that, just please let me have (the equivalent of) my:

let p = ptr::addr_of_mut!(STATIC_MUT);

There's programs I can't express without. For instance, we have a low-overhead profiler in our company that is just two rdtscs, and a couple of adds, loads and stores per profiling zone. The profiler is very careful to not create references, and it can only be ran in isolated single-threaded scenarios when we are tuning algorithms.

ac000 added a commit to nginx/unit-wasm that referenced this issue Jul 2, 2024
With at least

  rustc 1.79.0 (129f3b996 2024-06-10) (Fedora 1.79.0-3.fc40)

We were getting warnings when building the rust examples like

warning: creating a mutable reference to mutable static is discouraged
  --> src/lib.rs:75:40
   |
75 |     let ctx: *mut luw_ctx_t = unsafe { &mut CTX };
   |                                        ^^^^^^^^ mutable reference to mutable static
   |
   = note: for more information, see issue #114447 <rust-lang/rust#114447>
   = note: this will be a hard error in the 2024 edition
   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
   = note: `#[warn(static_mut_refs)]` on by default
help: use `addr_of_mut!` instead to create a raw pointer
   |
75 |     let ctx: *mut luw_ctx_t = unsafe { addr_of_mut!(CTX) };
   |                                        ~~~~~~~~~~~~~~~~~

So do like it says and use the addr_of_mut!() macro.

Signed-off-by: Andrew Clayton <[email protected]>
@ronhombre

This comment was marked as off-topic.

@ChayimFriedman2

This comment was marked as off-topic.

@ronhombre

This comment was marked as off-topic.

@workingjubilee
Copy link
Member

As a reminder, the Rust issue tracker is for filing bugs or issues with the language, it is not for use as a helpdesk. This includes creating code of dubious quality via passing a random number generator through a filter (or vector of weights) and asking us to not lint on it: When lints trigger correctly, they are supposed to trigger on code of dubious quality, to discourage reusing it.

pazmank pushed a commit to pazmank/nucleo-h7xx that referenced this issue Aug 22, 2024
antoinevg added a commit to antoinevg/nucleo-h7xx that referenced this issue Aug 22, 2024
ogoffart added a commit to slint-ui/slint-mcu-rust-template that referenced this issue Sep 16, 2024
```
warning: creating a mutable reference to mutable static is discouraged
  --> src/main.rs:40:29
   |
40 |     unsafe { ALLOCATOR.init(&mut HEAP as *const u8 as usize, core::mem::size_of_val(&HEAP)) };
   |                             ^^^^^^^^^ mutable reference to mutable static
   |
   = note: for more information, see issue #114447 <rust-lang/rust#114447>
   = note: this will be a hard error in the 2024 edition
   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
   = note: `#[warn(static_mut_refs)]` on by default
help: use `addr_of_mut!` instead to create a raw pointer
   |
40 |     unsafe { ALLOCATOR.init(addr_of_mut!(HEAP) as *const u8 as usize, core::mem::size_of_val(&HEAP)) };
   |                             ~~~~~~~~~~~~~    +
```
ogoffart added a commit to slint-ui/slint-mcu-rust-template that referenced this issue Sep 16, 2024
```
warning: creating a mutable reference to mutable static is discouraged
  --> src/main.rs:40:29
   |
40 |     unsafe { ALLOCATOR.init(&mut HEAP as *const u8 as usize, core::mem::size_of_val(&HEAP)) };
   |                             ^^^^^^^^^ mutable reference to mutable static
   |
   = note: for more information, see issue #114447 <rust-lang/rust#114447>
   = note: this will be a hard error in the 2024 edition
   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
   = note: `#[warn(static_mut_refs)]` on by default
help: use `addr_of_mut!` instead to create a raw pointer
   |
40 |     unsafe { ALLOCATOR.init(addr_of_mut!(HEAP) as *const u8 as usize, core::mem::size_of_val(&HEAP)) };
   |                             ~~~~~~~~~~~~~    +
```
facebook-github-bot pushed a commit to facebook/sapling that referenced this issue Oct 30, 2024
Summary:
Fixes the following warning by following the advice given:

```
warning: creating a mutable reference to mutable static is discouraged
  --> fbcode/eden/scm/lib/cpython-ext/src/bytesobject.rs:37:13
   |
37 |             &mut PyBytes_Type as *mut PyTypeObject,
   |             ^^^^^^^^^^^^^^^^^ mutable reference to mutable static
   |
   = note: for more information, see issue #114447 <rust-lang/rust#114447>
   = note: this will be a hard error in the 2024 edition
   = note: this mutable reference has lifetime `'static`, but if the static gets accessed (read or written) by any other means, or any other reference is created, then any further use of this mutable reference is Undefined Behavior
   = note: `#[warn(static_mut_refs)]` on by default
help: use `addr_of_mut!` instead to create a raw pointer
   |
37 |             addr_of_mut!(PyBytes_Type) as *mut PyTypeObject,
   |             ~~~~~~~~~~~~~            +

```

Reviewed By: quark-zju

Differential Revision: D65218834

fbshipit-source-id: 8298cdf8089b6d8516e0cb59a811b30465eb1f8c
pthierry-ledger added a commit to outpost-os/sentry-kernel that referenced this issue Nov 13, 2024
MarSik pushed a commit to MarSik/stm32l0xx-hal that referenced this issue Mar 17, 2025
This fixes this warning:

warning: shared reference of mutable static is discouraged
  --> stm32l0xx-hal/src/signature.rs:45:40
   |
45 |         core::str::from_utf8_unchecked(&DEVICE_ID_STR)
   |                                        ^^^^^^^^^^^^^^ shared reference of mutable static
   |
   = note: for more information, see issue #114447 <rust-lang/rust#114447>
   = note: reference of mutable static is a hard error from 2024 edition
   = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior
   = note: `#[warn(static_mut_ref)]` on by default
help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer

Co-authored-by: Javier Cardona <[email protected]>
tgross35 pushed a commit to tgross35/ctest2 that referenced this issue Apr 2, 2025
tgross35 pushed a commit to tgross35/rust-libc that referenced this issue Apr 2, 2025
tgross35 pushed a commit to tgross35/ctest2 that referenced this issue Apr 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-edition-2024 Area: The 2024 edition A-maybe-future-edition Something we may consider for a future edition. E-help-wanted Call for participation: Help is requested to fix this issue. E-medium Call for participation: Medium difficulty. Experience needed to fix: Intermediate. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.