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

Lint: enable empty_loop for no_std crates #6161

Closed
josephlr opened this issue Oct 11, 2020 · 10 comments · Fixed by #6205
Closed

Lint: enable empty_loop for no_std crates #6161

josephlr opened this issue Oct 11, 2020 · 10 comments · Fixed by #6205
Labels
C-bug Category: Clippy is not doing the correct thing C-enhancement Category: Enhancement of lints, like adding more cases or adding help messages S-needs-discussion Status: Needs further discussion before merging or work can be started

Comments

@josephlr
Copy link
Contributor

josephlr commented Oct 11, 2020

Right now, we have a style lint against the following code:

loop {}

Note that this is no longer undefined behavior (since rust-lang/rust#77972).

Currently, there is no way to have a no_std binary or library use the empty_loop lint.
Even adding #![deny(clippy::empty_loop)] to a crate does nothing. This is because #5086 (fixing #3746), made the lint essentially not exist for no_std crates.

Furthermore, even in no_std crates, using a "hot" deadloop is almost always not what you want (as it burns a bunch of CPU, and can cause crashes). Even on a no_std target, a user should either:

  • Panic
  • Call a platform-specific halt or pause intrinsic.

Note, core::sync::atomic::spin_loop_hint is not a good recommendation here, as pause isn't meant for dead-loops (it's designed for spin-locks). See rust-lang/rust#77924

In my opinion, we should:

  • Reenable the empty_loop lint for no_std crates.
  • Have a no_std specific help message.
  • Disable this lint automatically in #[panic_handler]s
    • As an alternative, we could just disable this lint for no_std binaries (while keeping it on for no_std libraries).
    • The only uses of deadloops in the Rustonomicon are inside of #[panic_handler].

Our documentation for fixing this (on std and no_std) is part of #6162

CC (people involved with this change last time): @therealprof, @oli-obk, @eddyp, @Areredify, @phansch

@josephlr josephlr added the C-bug Category: Clippy is not doing the correct thing label Oct 11, 2020
@flip1995 flip1995 added S-needs-discussion Status: Needs further discussion before merging or work can be started C-enhancement Category: Enhancement of lints, like adding more cases or adding help messages labels Oct 12, 2020
@jonas-schievink
Copy link
Contributor

core::sync::atomic::spin_loop_hint does not help here, it is a no-op on most embedded platforms and never causes side-effects

@josephlr
Copy link
Contributor Author

core::sync::atomic::spin_loop_hint does not help here, it is a no-op on most embedded platforms and never causes side-effects

Agreed that this doesn't completely fix the issue. That hint currently only does something on:

  • x86/x86_64 with SSE2
  • ARM V6 and later (including Aarch64)

It would be nice if that hint did fix the issue. I'll see about filing an issue upstream to make it so core::sync::atomic::spin_loop_hint always does some sort of side-effect.

@jonas-schievink
Copy link
Contributor

IMO we should just fix the LLVM bugs instead. spin_loop_hint is not meant to do anything here, it's not meant to have a side-effect, it's just a hint to schedule another hyperthread.

@josephlr
Copy link
Contributor Author

@jonas-schievink I talk a bit in rust-lang/rust#77924 about why we might want spin_loop_hint to have a side-effect on all platforms. Basically, it makes our recommendations to users better, and makes the behavior more consistent across targets (as spin_loop_hint is a side-effect on x86 and (most) ARM targets).

@jonas-schievink
Copy link
Contributor

It does not have side effects on any target. LLVM might treat it as such, but really it doesn't.

@josephlr
Copy link
Contributor Author

josephlr commented Oct 14, 2020

It does not have side effects on any target. LLVM might treat it as such, but really it doesn't.

I guess I'm confused, for the current implementation on x86, the hint alls the pause instruction, which is a side-effect for the purposes of optimization and the like.

bors added a commit that referenced this issue Oct 16, 2020
Enable empty_loop for no_std crates.

Fixes #6161

This change:
  - Makes it so the `empty_loop` lint will fire for `no_std` crates, but with a `no_std`-specific message (mentioning [`spin_loop_hint`](https://doc.rust-lang.org/core/sync/atomic/fn..html)).
  - Updates the `std` message to also mention [`std::thread::yield_now`](https://doc.rust-lang.org/std/thread/fn.yield_now.html).
  - Updates the docs to also mention the [LLVM infinite loop bug](rust-lang/rust#28728)
  - Updates the tests/stderr files to test this change.

changelog: Update `empty_loop` lint to work with `no_std` crates
bors added a commit that referenced this issue Oct 16, 2020
Enable empty_loop for no_std crates.

Fixes #6161

This change:
  - Makes it so the `empty_loop` lint will fire for `no_std` crates, but with a `no_std`-specific message (mentioning [`spin_loop_hint`](https://doc.rust-lang.org/core/sync/atomic/fn..html)).
  - Updates the `std` message to also mention [`std::thread::yield_now`](https://doc.rust-lang.org/std/thread/fn.yield_now.html).
  - Updates the docs to also mention the [LLVM infinite loop bug](rust-lang/rust#28728)
  - Updates the tests/stderr files to test this change.

changelog: Update `empty_loop` lint to work with `no_std` crates
bors added a commit that referenced this issue Oct 17, 2020
Enable empty_loop for no_std crates.

Fixes #6161

This change:
  - Makes it so the `empty_loop` lint will fire for `no_std` crates, but with a `no_std`-specific message (mentioning [`spin_loop_hint`](https://doc.rust-lang.org/core/sync/atomic/fn..html)).
  - Updates the `std` message to also mention [`std::thread::yield_now`](https://doc.rust-lang.org/std/thread/fn.yield_now.html).
  - Updates the docs to also mention the [LLVM infinite loop bug](rust-lang/rust#28728)
  - Updates the tests/stderr files to test this change.

changelog: Update `empty_loop` lint to work with `no_std` crates
bors added a commit that referenced this issue Oct 19, 2020
Enable empty_loop for no_std crates.

Fixes #6161

This change:
  - Makes it so the `empty_loop` lint will fire for `no_std` crates, but with a `no_std`-specific message (mentioning [`spin_loop_hint`](https://doc.rust-lang.org/core/sync/atomic/fn..html)).
  - Updates the `std` message to also mention [`std::thread::yield_now`](https://doc.rust-lang.org/std/thread/fn.yield_now.html).
  - Updates the docs to also mention the [LLVM infinite loop bug](rust-lang/rust#28728)
  - Updates the tests/stderr files to test this change.

changelog: Update `empty_loop` lint to work with `no_std` crates
@josephlr
Copy link
Contributor Author

josephlr commented Oct 23, 2020

I've updated the description for this issue to make it clear this is no longer about undefined behavior. Now, this issue just tracks re-enabling the style lint for no_std libraries. Even for no_std libraries, it's probably a good idea to for use to have a lint that says "hey, you should panic instead of deadlooping".

I think we should either:

  1. Enable this lint for no_std libraries, disabling it in no_std binaries
  2. Enable this lint for no_std libraries and binaries, but disable it inside #[panic_handler]

EDIT: Implementation of (2) is up in #6205

bors added a commit that referenced this issue Oct 25, 2020
Update empty_loop documentation/message.

Originally part of #6161, but now this PR only deals with `std` crates

This change:
  - Updates the `std` message .
  - Updates the docs to mention how the busy loops should be fixed
    - Gives examples of how to do this for `no_std` targets
  - Updates the tests/stderr files to test this change.

changelog: Update `empty_loop` lint documentation
@eddyp
Copy link

eddyp commented Nov 4, 2020

I think we should either:

1. Enable this lint for `no_std` libraries, disabling it in `no_std` binaries

2. Enable this lint for `no_std` libraries and binaries, but disable it inside `#[panic_handler]`

In my view the second is the correct approach as on no_std you can customary use an empty loop {} only on unrecoverable errors. Main loops, even in an interrupt driven application, is expected to have a non-empty loop as it should contain at least some code to save power (e.g. WFI on ARMv7-M ISA).

@therealprof
Copy link

(e.g. WFI on ARMv7-M ISA).

WFI interacts badly with a debugger. At the moment there're legitimate reasons to want a truly empty loop, maybe there should be a libcore function providing such a functionality in a problem free manner?

@bors bors closed this as completed in abfa331 Nov 8, 2020
@eddyp
Copy link

eddyp commented Nov 17, 2020

(e.g. WFI on ARMv7-M ISA).

WFI interacts badly with a debugger.

Is that something specific to Rust code? Or some specific boards/SoCs? Can you provide more details?

I am yet to encounter such issues with JTAG debuggers in C code I worked with, and have limited experience with non-play embedded Rust code that would contain the main loop (making power saving instructions needed).

At the moment there're legitimate reasons to want a truly empty loop, maybe there should be a libcore function providing such a functionality in a problem free manner?

BTW, the issue is closed now, so if you have issues, you might want to follow up, as option 2 was implemented:

abfa331#diff-43e58dc26b162ad6f137224e22f25d0a652e9c319ed6a7b7d74061110e5dea77

jannic added a commit to jannic/rp-hal that referenced this issue Aug 1, 2022
- Clippy warns about empty loops, rust-lang/rust-clippy#6161
- wfi allows to CPU to save some power

WFI was avoided in examples for fear of ill interactions with debuggers.
However the rp2040 debug port does continue to work, as long as the
relevant clocks are not disabled in SLEEP_EN0/SLEEP_EN1. (By default,
all clocks stay enabled in sleep mode.)

This patch replaces several different workarounds with just calling wfi.
ExplodingWaffle pushed a commit to ExplodingWaffle/rp-hal that referenced this issue Aug 14, 2022
- Clippy warns about empty loops, rust-lang/rust-clippy#6161
- wfi allows to CPU to save some power

WFI was avoided in examples for fear of ill interactions with debuggers.
However the rp2040 debug port does continue to work, as long as the
relevant clocks are not disabled in SLEEP_EN0/SLEEP_EN1. (By default,
all clocks stay enabled in sleep mode.)

This patch replaces several different workarounds with just calling wfi.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: Clippy is not doing the correct thing C-enhancement Category: Enhancement of lints, like adding more cases or adding help messages S-needs-discussion Status: Needs further discussion before merging or work can be started
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants