Search code examples
cassemblyc11function-callnoreturn

Why does "noreturn" function return?


I read this question about noreturn attribute, which is used for functions that don't return to the caller.

Then I have made a program in C.

#include <stdio.h>
#include <stdnoreturn.h>

noreturn void func()
{
        printf("noreturn func\n");
}

int main()
{
        func();
}

And generated assembly of the code using this:

.LC0:
        .string "func"
func:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $.LC0, %edi
        call    puts
        nop
        popq    %rbp
        ret   // ==> Here function return value.
main:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $0, %eax
        call    func

Why does function func() return after providing noreturn attribute?


Solution

  • The function specifiers in C are a hint to the compiler, the degree of acceptance is implementation defined.

    First of all, _Noreturn function specifier (or, noreturn, using <stdnoreturn.h>) is a hint to the compiler about a theoretical promise made by the programmer that this function will never return. Based on this promise, compiler can make certain decisions, perform some optimizations for the code generation.

    IIRC, if a function specified with noreturn function specifier eventually returns to its caller, either

    • by using and explicit return statement
    • by reaching end of function body

    the behaviour is undefined. You MUST NOT return from the function.

    To make it clear, using noreturn function specifier does not stop a function form returning to its caller. It is a promise made by the programmer to the compiler to allow it some more degree of freedom to generate optimized code.

    Now, in case, you made a promise earlier and later, choose to violate this, the result is UB. Compilers are encouraged, but not required, to produce warnings when a _Noreturn function appears to be capable of returning to its caller.

    According to chapter §6.7.4, C11, Paragraph 8

    A function declared with a _Noreturn function specifier shall not return to its caller.

    and, the paragraph 12, (Note the comments!!)

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

    For C++, the behaviour is quite similar. Quoting from chapter §7.6.4, C++14, paragraph 2 (emphasis mine)

    If a function f is called where f was previously declared with the noreturn attribute and f eventually returns, the behavior is undefined. [ Note: The function may terminate by throwing an exception. —end note ]

    [ Note: Implementations are encouraged to issue a warning if a function marked [[noreturn]] might return. —end note ]

    3 [ Example:

    [[ noreturn ]] void f() {
    throw "error"; // OK
    }
    [[ noreturn ]] void q(int i) { // behavior is undefined if called with an argument <= 0
    if (i > 0)
    throw "positive";
    }
    

    —end example ]