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

--- Comment #5 from David Malcolm <dmalcolm at gcc dot gnu.org> ---
glib'c bits/error.h has:

/* If we know the function will never return make sure the compiler
   realizes that, too.  */
__extern_always_inline void
error (int __status, int __errnum, const char *__format, ...)
{
  if (__builtin_constant_p (__status) && __status != 0)
    __error_noreturn (__status, __errnum, __format, __va_arg_pack ());
  else
    __error_alias (__status, __errnum, __format, __va_arg_pack ());
}

and similar for error_at_line.

However, looking at GENERIC (via -fdump-tree-original=stderr)
  https://godbolt.org/z/dqWr1G97s
I see that this is coming out of the C front end as:

;; Function error (null)
;; enabled by -tree-original

{
  if (0)
    {
      __error_noreturn (__status, __errnum, __format, __builtin_va_arg_pack
());
    }
  else
    {
      __error_alias (__status, __errnum, __format, __builtin_va_arg_pack ());
    }
}

before any of GCC's inlining logic gets to work on it.

Hence "test" quickly gets optimized down to just:
  __error_alias (__status_2(D), __errnum_3(D), __format_4(D),
__builtin_va_arg_pack ());

and this is what is inlined into the callsite of "error".

Hence by the time the analyzer sees it we have a call to "__error_alias" which
the analyzer/kf.cc doesn't recognize, and conservatively assumes could return.

So there are arguably three issues here:
(a) should gcc keep the __builtin_constant_p around longer so that it's still
around when the inliner gets a chance to work on it?  (I don't know if this is
a good idea or not)
(b) should glibc's header be rewritten (perhaps losing the
__builtin_constant_p?)
(c) the analyzer's special-casing for error and error_at_line should also
recognize __error_alias and __error_at_line_alias (probably an easy workaround)

Reply via email to