https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106437

            Bug ID: 106437
           Summary: Glibc marks functions that resume a returns_twice call
                    as leaf
           Product: gcc
           Version: 13.0
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: ipa
          Assignee: unassigned at gcc dot gnu.org
          Reporter: amonakov at gcc dot gnu.org
                CC: amonakov at gcc dot gnu.org, asolokha at gmx dot com,
                    dcb314 at hotmail dot com, hubicka at gcc dot gnu.org,
                    marxin at gcc dot gnu.org, rguenth at gcc dot gnu.org,
                    unassigned at gcc dot gnu.org
  Target Milestone: ---

In tree-cfg.cc:call_can_make_abnormal_goto GCC implements an assumption that
any function with the 'leaf' attribute will not transfer control to a
returns_twice function. This behavior is from day 1 since attribute-leaf
introduction, but the documentation says:

> leaf functions are not allowed to call callback function passed to it from
> current compilation unit or directly call functions exported by the unit or
> longjmp into the unit

So the manual was talking about longjmp exclusively, even though probably it
meant resumption of returns_twice calls in general.

Today Glibc headers are marking function that can resume vfork as leaf, execve
being the biggest problem since it resumes vfork without being technically UB;
functions such as 'raise' and 'kill' can also resume vfork by terminating the
current process (but pedantically it is UB to invoke them in vfork context).

(there's also the point that 'raise' can invoke signal handlers synchronously,
and I agree with Richard that it makes it non-leaf; it's been discussed as
Glibc issue previously, the most recent instance seems to be here:
https://sourceware.org/bugzilla/show_bug.cgi?id=26802 ; ISTR there was a
discussion on GCC side also, earlier)

Presence of attribute-leaf makes GCC omit modeling of control flow transfer via
ABNORMAL_DISPATCHER, potentially causing miscompilation.

Testcase with execve, notice absence of abnormal edges on GIMPLE:

#include <unistd.h>
#include <signal.h>

int main()
{
    if (!vfork())
        for (;;) execve("/bin/false", 0, 0);
}

Reply via email to