Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are noreturn attributes on exiting functions necessary?

Are noreturn attributes on never-returning functions necessary, or is this just an (arguably premature? -- at least for exits, I can't imagine why optimize there) optimization?

It was explained to me that in a context such as

void myexit(int s) _Noreturn {
   exit(s);
}
// ...
if (!p) { myexit(1); } 
f(*p);
/// ...

noreturn prevents the !p branch from being optimized out. But is it really permissible for a compiler to optimize out that branch? I realize the rationale for optimizing it out would be: "Undefined behavior can't happen. If p == NULL, dereferencing it is UB, therefore p can never be NULL in this context, therefore the !p branch does not trigger". But can't the compiler resolve the problem just as well by assuming that myexit could be a function that doesn't return (even if it's not explicitly marked as such)?

like image 485
PSkocik Avatar asked Jul 18 '16 07:07

PSkocik


2 Answers

This allows for several optimizations to take place. First, for the call itself this may to allow for a simplified setup, not all registers have to be saved, a jmp instruction can be used instead of call or similar. Then the code after the call can also be optimized because there is no branching back to the normal flow.

So yes, usually _Noreturn is a valuable information to the compiler.

But as a direct answer to your question, no, this is a property for optimization, so it is not necessary.

like image 129
Jens Gustedt Avatar answered Oct 20 '22 08:10

Jens Gustedt


Axiom: The standard is the definite resource on what's well-defined in C.

  • The standard specifies assert, therefore using assert is well-defined.
  • assert conditionally calls abort, a _Noreturn function, therefore that's allowed.
  • Every usage of assert is inside a function. Therefore functions may or may not return.
  • The standard has this example:

    _Noreturn void g (int i) { // causes undefined behavior if i <= 0
        if (i > 0) abort();
    }
    

    Therefore functions conditionally returning must not be _Noreturn. This means:

    • For externally defined functions, the compiler has to assume the function might not return and isn't free to optimize out the if-branch
    • For "internally" defined functions, the compiler can check whether the function indeed always returns and optimize out the branch.

In both cases, compiled program behavior aligns with what a non-optimizing abstract C machine would do and the 'as-if' rule is observed.

like image 42
a3f Avatar answered Oct 20 '22 07:10

a3f