10

I have a following embedded system optimization case (simplified).

int main() { while (1) { // Do something if (unrecoverable_error) { __breakpoint(); while(1); } } } 

If the while (1); statement is replaced by return 0, the compiler invokes all the destructors due upon exit from main, (and for that matter generates the destructor code bloat) - both for main-local and global, even if the crt0 ultimately traps the CPU in a while(1); loop after all.

Thus, there is an advantage to judiciously use while(1); if one wants the system to intentionally hang.

Statically analyzing the code with -fanalyzer leads to (obvious) infinite loop error/warning.

How does one annotate that a specific instance of the infinite loop is indeed intentional?

I don't want to disable the infinite loop detection entirely (as it is possible that other parts of the code may contain bugs that lead to non-trivial infinite loops).

19
  • 3
    Does the same way as with any other diagnostic work? As in #pragma GCC diagnostic ignored "-Wanalyzer-infinite-loop" ? You might want to surround it with #pragma GCC diagnostic push .... #pragma GCC diagnostic pop Commented Apr 29 at 13:35
  • 3
    In C++ infinitive loops are treated as undefined behavior. As result when optimizer will see infinitive loop optimizer can remove it. Commented Apr 29 at 13:47
  • 5
    @MarekR Infinite loops without observable behavior are per the spec undefined behavior. Commented Apr 29 at 13:50
  • 2
    According to the latest draft this type of trivial loop is not undefined, and even specifies "The statement of a trivial infinite loop is replaced with a call to the function std​::​this_thread​::​yield". Commented Apr 29 at 13:57
  • 1
    @EugeneSh. intro.abstract defines what constitutes observable behaviour, and "it seems to be stuck" isn't one of them. Commented Apr 29 at 14:03

3 Answers 3

8

Infinite loops without side effects are generally considered as undefined behavior in C++ (Some exceptions in the newest draft are given in the comments of the question).

According to the latest draft, reading from a volatile object is considered a side effect.

Therefore you might replace the while(1); statement with

volatile int dummy = 1; while (1) { // I do not know if side effect in control statement counts if (!dummy) break; } 
Sign up to request clarification or add additional context in comments.

6 Comments

Question was about annotating code to silence static code analyzer warning. The UB of infinitive loop without side-effect was just side topic.
Fixing the problem might be one way to silence the analyzer. It might even be the better way to silence it, compared to just hiding the problem.
Ok you are right, here is repro: godbolt.org/z/Ka51zj8er
Interesting! Curious - in practice, not in pure language theory (I'm not a great fan of having 4 pointless opcodes today.. yes, I'm fighting to squeeze sth in 8k of .text code) - can we find a compiler that actually elides while(1); (since it can change the runtime behavior)?
@qdot clang for example is really zealous when it comes to eliminating loops without side effects - see for example godbolt - note that the assembly for foo does not contain any loop at all (and no ret instruction either, so it will just continue to execute whatever bytes happen to be located after foo) - note that clang version 19+ and gcc version 14+ both implement P2809R3 so these will never optimize out trivial infinite loops. If your compiler is older than that you can use asm volatile(""); as a special side effect to prevent the optimization.
|
6

You can typically add the noreturn attribute to main to indicate that you intentionally put in an infinite loop.

Most static analyzers also understand the noreturn attribute, and will not flag a problem here.

__attribute__((noreturn)) int main() { while (1) { // Do something if (unrecoverable_error) { __breakpoint(); while(1); } } } 

2 Comments

Depending on how complex // Do something turns out to be, I would be tempted to add a separate noreturn function that calls __breakpoint and hangs.
This has no effect on -fanalyzer. How did this get 7 upvotes?
0

According to GCC documentation for -Wanalyzer-infinite-loop:

This diagnostics warns for paths through the code which appear to lead to an infinite loop.

Specifically, the analyzer will issue this warning when it "sees" a loop in which:

  • no externally-visible work could be being done within the loop
  • there is no way to escape from the loop
  • the analyzer is sufficiently confident about the program state throughout the loop to know that the above are true

So one way to silence the warning is to insert some “externally-visible work” into the body of the loop: an __asm__ (""); statement suffices for that purpose (see Godbolt sample), as inline assembly is opaque to GCC (and will likely remain that way), so the compiler has to assume that it may have any effect whatsoever. Other solutions, like a dummy volatile variable or dummy extern call carry the risk that the compiler may eventually see through them and show the warning anyway – while an empty __asm__ statement has been endorsed as the “dummy side effect” idiom in at least one other place in GCC documentation, so it should be relatively safe.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.