diff options
author | David Malcolm <dmalcolm@redhat.com> | 2024-07-04 14:44:51 -0400 |
---|---|---|
committer | David Malcolm <dmalcolm@redhat.com> | 2024-07-04 14:44:51 -0400 |
commit | a6fdb1a2a2906103afd70fa68cf7c45e896b8fbb (patch) | |
tree | 9de0f9c5c229569792b47f38999666d822d497d3 /gcc | |
parent | b611f3969249967d7f098c6adfcf5f701192a2d0 (diff) | |
download | gcc-a6fdb1a2a2906103afd70fa68cf7c45e896b8fbb.zip gcc-a6fdb1a2a2906103afd70fa68cf7c45e896b8fbb.tar.gz gcc-a6fdb1a2a2906103afd70fa68cf7c45e896b8fbb.tar.bz2 |
analyzer: handle <error.h> at -O0 [PR115724]
At -O0, glibc's:
__extern_always_inline void
error (int __status, int __errnum, const char *__format, ...)
{
if (__builtin_constant_p (__status) && __status != 0)
__error_noreturn (__status, __errnum, __format, __builtin_va_arg_pack ());
else
__error_alias (__status, __errnum, __format, __builtin_va_arg_pack ());
}
becomes just:
__extern_always_inline void
error (int __status, int __errnum, const char *__format, ...)
{
if (0)
__error_noreturn (__status, __errnum, __format, __builtin_va_arg_pack ());
else
__error_alias (__status, __errnum, __format, __builtin_va_arg_pack ());
}
and thus calls to "error" are calls to "__error_alias" by the
time -fanalyzer "sees" them.
Handle them with more special-casing in kf.cc.
gcc/analyzer/ChangeLog:
PR analyzer/115724
* kf.cc (register_known_functions): Add __error_alias and
__error_at_line_alias.
gcc/testsuite/ChangeLog:
PR analyzer/115724
* c-c++-common/analyzer/error-pr115724.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/analyzer/kf.cc | 4 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/analyzer/error-pr115724.c | 86 |
2 files changed, 90 insertions, 0 deletions
diff --git a/gcc/analyzer/kf.cc b/gcc/analyzer/kf.cc index 4213b89..5c3a71f 100644 --- a/gcc/analyzer/kf.cc +++ b/gcc/analyzer/kf.cc @@ -2325,6 +2325,10 @@ register_known_functions (known_function_manager &kfm, kfm.add ("__errno_location", make_unique<kf_errno_location> ()); kfm.add ("error", make_unique<kf_error> (3)); kfm.add ("error_at_line", make_unique<kf_error> (5)); + /* Variants of "error" and "error_at_line" seen by the + analyzer at -O0 (PR analyzer/115724). */ + kfm.add ("__error_alias", make_unique<kf_error> (3)); + kfm.add ("__error_at_line_alias", make_unique<kf_error> (5)); } /* Other implementations of C standard library. */ diff --git a/gcc/testsuite/c-c++-common/analyzer/error-pr115724.c b/gcc/testsuite/c-c++-common/analyzer/error-pr115724.c new file mode 100644 index 0000000..ae606ad --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/error-pr115724.c @@ -0,0 +1,86 @@ +/* Verify that the analyzer handles the no-optimization case in + glibc's <error.h> when error,error_at_line calls become + __error_alias and __error_at_line_alias. */ + +typedef __SIZE_TYPE__ size_t; +#define EXIT_FAILURE 1 +#define __extern_always_inline extern inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) + +int errno; + +/* Adapted from glibc's bits/error.h. */ + +extern void __error_alias (int __status, int __errnum, + const char *__format, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); +extern void __error_noreturn (int __status, int __errnum, + const char *__format, ...) + __attribute__ ((__noreturn__, __format__ (__printf__, 3, 4))); + +/* 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, __builtin_va_arg_pack ()); + else + __error_alias (__status, __errnum, __format, __builtin_va_arg_pack ()); +} + +extern void __error_at_line_alias (int __status, int __errnum, + const char *__fname, + unsigned int __line, + const char *__format, ...) + __attribute__ ((__format__ (__printf__, 5, 6))); +extern void __error_at_line_noreturn (int __status, int __errnum, + const char *__fname, + unsigned int __line, + const char *__format, + ...) + __attribute__ ((__noreturn__, __format__ (__printf__, 5, 6))); + +/* If we know the function will never return make sure the compiler + realizes that, too. */ +__extern_always_inline void +error_at_line (int __status, int __errnum, const char *__fname, + unsigned int __line, const char *__format, ...) +{ + if (__builtin_constant_p (__status) && __status != 0) + __error_at_line_noreturn (__status, __errnum, __fname, __line, __format, + __builtin_va_arg_pack ()); + else + __error_at_line_alias (__status, __errnum, __fname, __line, + __format, __builtin_va_arg_pack ()); +} + + +struct list { + size_t size; + void (*destroy)(void *data); + struct list_node *head; + struct list_node *tail; +}; + +struct list *list_create(void (*destroy)(void *data)) +{ + struct list *result = (struct list *)__builtin_calloc(1, sizeof(*result)); + if (!result) + error(EXIT_FAILURE,errno,"%s:%d %s()",__FILE__,__LINE__,__func__); + + result->destroy = destroy; /* { dg-bogus "dereference of NULL 'result'" } */ + + return result; +} + +struct list *list_create_using_at_line(void (*destroy)(void *data)) +{ + struct list *result = (struct list *)__builtin_calloc(1, sizeof(*result)); + if (!result) + error_at_line(EXIT_FAILURE,errno,__FILE__,__LINE__, + "%s()", __func__); + + result->destroy = destroy; /* { dg-bogus "dereference of NULL 'result'" } */ + + return result; +} |