From 5219414f3cde3c1037e289a6654cd722cfa75dea Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Fri, 3 May 2024 09:05:29 -0400 Subject: testsuite: fix analyzer C++ failures on Solaris [PR111475] As part of PR analyzer/96395, these patches moved testcases from gcc.dg/analyzer to c-c++-common/analyzer: - r14-3503-g55f6a7d949abc7 - r14-3823-g50b5199cff6908 - r14-6564-gae034b9106fbdd Unfortunately this led to numerous g++ testsuite failures on Solaris, tracked as PR analyzer/111475. Almost all of the failures are due to standard library differences where including a C standard library on C++ e.g. leads to the plain symbols referencing the symbols "std::" via a "using" declaration, whereas I had written the code expecting them to use symbols in the root namespace. The analyzer has special-case handling of many functions by name. This patch generalizes such handling to also match against functions in "std::" for all of the cases I found in the testsuite (via manual inspection of the preprocessed test cases against Solaris headers). This fixes cases where the analyzer was failing to "know about" the behavior of such functions. Other such failures are due to "std::" prefixes appearing in names of functions in the output, leading to mismatches against expected output. The patch adds regexes to some cases, and moves some other cases back from c-c++-common to gcc.dg where the dg-multiline syntax isn't expressive enough. Various "fd-*.c" failures relate to Solaris's socket-handling functions not being marked with "noexcept", where due to PR analyzer/97111 we mishandle the exception-handling edges in the CFG, leading to leak false positives. The patch works around this by adding -fno-exceptions to these cases, pending a proper fix for PR analyzer/97111. gcc/analyzer/ChangeLog: PR analyzer/111475 * analyzer.cc (is_special_named_call_p): Add "look_in_std" param. (is_std_function_p): Make non-static. * analyzer.h (is_special_named_call_p): Add optional "look_in_std" param. (is_std_function_p): New decl. * engine.cc (stmt_requires_new_enode_p): Look for both "signal" and "std::signal". * kf.cc (register_known_functions): Add various "std::" copies of the known functions. * known-function-manager.cc (known_function_manager::~known_function_manager): Clean up m_std_ns_map_id_to_kf. (known_function_manager::add_std_ns): New. (known_function_manager::get_match): Also look for known "std::" functions. (known_function_manager::get_by_identifier_in_std_ns): New. * known-function-manager.h (known_function_manager::add_std_ns): New decl. (known_function_manager::get_by_identifier_in_std_ns): New decl. (known_function_manager::m_std_ns_map_id_to_kf): New field. * sm-file.cc (register_known_file_functions): Add various "std::" copies of the known functions. * sm-malloc.cc (malloc_state_machine::on_stmt): Handle "std::realloc". * sm-signal.cc (signal_unsafe_p): Consider "std::" copies of the functions as also being async-signal-unsafe. (signal_state_machine::on_stmt): Consider "std::signal". gcc/testsuite/ChangeLog: PR analyzer/111475 * c-c++-common/analyzer/fd-glibc-byte-stream-socket.c: Add -fno-exceptions for now. * c-c++-common/analyzer/fd-manpage-getaddrinfo-client.c: Likewise. * c-c++-common/analyzer/fd-mappage-getaddrinfo-server.c: Rename to... * c-c++-common/analyzer/fd-manpage-getaddrinfo-server.c: ...this, and add -fno-exceptions for now. * c-c++-common/analyzer/fd-socket-meaning.c: Add -fno-exceptions for now. * c-c++-common/analyzer/fd-symbolic-socket.c: Likewise. * c-c++-common/analyzer/flexible-array-member-1.c: Use regexp to handle C vs C++ differences in spelling of function name, which could have a "std::" prefix on some targets. * c-c++-common/analyzer/pr106539.c: Likewise. * c-c++-common/analyzer/malloc-ipa-8-unchecked.c: Move back to... * gcc.dg/analyzer/malloc-ipa-8-unchecked.c: ...here, dropping attempt to generalize output for C vs C++. * c-c++-common/analyzer/signal-4a.c: Move back to... * gcc.dg/analyzer/signal-4a.c: ...here, dropping attempt to generalize output for C vs C++. * c-c++-common/analyzer/signal-4b.c: Move back to... * gcc.dg/analyzer/signal-4b.c: ...here, dropping attempt to generalize output for C vs C++. Signed-off-by: David Malcolm --- gcc/analyzer/analyzer.cc | 15 ++- gcc/analyzer/analyzer.h | 4 +- gcc/analyzer/engine.cc | 2 +- gcc/analyzer/kf.cc | 22 +++ gcc/analyzer/known-function-manager.cc | 38 +++++- gcc/analyzer/known-function-manager.h | 5 + gcc/analyzer/sm-file.cc | 8 ++ gcc/analyzer/sm-malloc.cc | 1 + gcc/analyzer/sm-signal.cc | 11 +- .../analyzer/fd-glibc-byte-stream-socket.c | 4 + .../analyzer/fd-manpage-getaddrinfo-client.c | 4 + .../analyzer/fd-manpage-getaddrinfo-server.c | 126 +++++++++++++++++ .../analyzer/fd-mappage-getaddrinfo-server.c | 122 ----------------- .../c-c++-common/analyzer/fd-socket-meaning.c | 4 + .../c-c++-common/analyzer/fd-symbolic-socket.c | 4 + .../analyzer/flexible-array-member-1.c | 6 +- .../c-c++-common/analyzer/malloc-ipa-8-unchecked.c | 108 --------------- gcc/testsuite/c-c++-common/analyzer/pr106539.c | 2 +- gcc/testsuite/c-c++-common/analyzer/signal-4a.c | 122 ----------------- gcc/testsuite/c-c++-common/analyzer/signal-4b.c | 149 --------------------- .../gcc.dg/analyzer/malloc-ipa-8-unchecked.c | 70 ++++++++++ gcc/testsuite/gcc.dg/analyzer/signal-4a.c | 79 +++++++++++ gcc/testsuite/gcc.dg/analyzer/signal-4b.c | 94 +++++++++++++ 23 files changed, 485 insertions(+), 515 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/analyzer/fd-manpage-getaddrinfo-server.c delete mode 100644 gcc/testsuite/c-c++-common/analyzer/fd-mappage-getaddrinfo-server.c delete mode 100644 gcc/testsuite/c-c++-common/analyzer/malloc-ipa-8-unchecked.c delete mode 100644 gcc/testsuite/c-c++-common/analyzer/signal-4a.c delete mode 100644 gcc/testsuite/c-c++-common/analyzer/signal-4b.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-8-unchecked.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/signal-4a.c create mode 100644 gcc/testsuite/gcc.dg/analyzer/signal-4b.c (limited to 'gcc') diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc index 7f5d3d5..2a15a3a 100644 --- a/gcc/analyzer/analyzer.cc +++ b/gcc/analyzer/analyzer.cc @@ -293,11 +293,13 @@ get_ssa_default_def (const function &fun, tree var) is_named_call_p should be used instead, using a fndecl from get_fndecl_for_call; this function should only be used for special cases where it's not practical to get at the region model, or for special - analyzer functions such as __analyzer_dump. */ + analyzer functions such as __analyzer_dump. + + If LOOK_IN_STD is true, then also look for within std:: for the name. */ bool is_special_named_call_p (const gcall *call, const char *funcname, - unsigned int num_args) + unsigned int num_args, bool look_in_std) { gcc_assert (funcname); @@ -305,7 +307,12 @@ is_special_named_call_p (const gcall *call, const char *funcname, if (!fndecl) return false; - return is_named_call_p (fndecl, funcname, call, num_args); + if (is_named_call_p (fndecl, funcname, call, num_args)) + return true; + if (look_in_std) + if (is_std_named_call_p (fndecl, funcname, call, num_args)) + return true; + return false; } /* Helper function for checkers. Is FNDECL an extern fndecl at file scope @@ -344,7 +351,7 @@ is_named_call_p (const_tree fndecl, const char *funcname) Compare with cp/typeck.cc: decl_in_std_namespace_p, but this doesn't rely on being the C++ FE (or handle inline namespaces inside of std). */ -static inline bool +bool is_std_function_p (const_tree fndecl) { tree name_decl = DECL_NAME (fndecl); diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h index d43812e3..334b0d3 100644 --- a/gcc/analyzer/analyzer.h +++ b/gcc/analyzer/analyzer.h @@ -448,10 +448,12 @@ extern tree remove_ssa_names (tree expr); } // namespace ana extern bool is_special_named_call_p (const gcall *call, const char *funcname, - unsigned int num_args); + unsigned int num_args, + bool look_in_std = false); extern bool is_named_call_p (const_tree fndecl, const char *funcname); extern bool is_named_call_p (const_tree fndecl, const char *funcname, const gcall *call, unsigned int num_args); +extern bool is_std_function_p (const_tree fndecl); extern bool is_std_named_call_p (const_tree fndecl, const char *funcname); extern bool is_std_named_call_p (const_tree fndecl, const char *funcname, const gcall *call, unsigned int num_args); diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index e0dc0e6..556e8a1 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -3768,7 +3768,7 @@ stmt_requires_new_enode_p (const gimple *stmt, regular next state, which defeats the "detect state change" logic in process_node. Work around this via special-casing, to ensure we split the enode immediately before any "signal" call. */ - if (is_special_named_call_p (call, "signal", 2)) + if (is_special_named_call_p (call, "signal", 2, true)) return true; } diff --git a/gcc/analyzer/kf.cc b/gcc/analyzer/kf.cc index 6931f07..c60e220 100644 --- a/gcc/analyzer/kf.cc +++ b/gcc/analyzer/kf.cc @@ -2344,6 +2344,28 @@ register_known_functions (known_function_manager &kfm, /* Language-specific support functions. */ register_known_functions_lang_cp (kfm); + + /* Some C++ implementations use the std:: copies of these functions + from etc for the C spellings of these headers (e.g. ), + so we must match against these too. */ + { + kfm.add_std_ns ("malloc", make_unique ()); + kfm.add_std_ns ("free", make_unique ()); + kfm.add_std_ns ("realloc", make_unique ()); + kfm.add_std_ns ("calloc", make_unique ()); + kfm.add_std_ns + ("memcpy", + make_unique (kf_memcpy_memmove::KF_MEMCPY)); + kfm.add_std_ns + ("memmove", + make_unique (kf_memcpy_memmove::KF_MEMMOVE)); + kfm.add_std_ns ("memset", make_unique (false)); + kfm.add_std_ns ("strcat", make_unique (2, false)); + kfm.add_std_ns ("strcpy", make_unique (2, false)); + kfm.add_std_ns ("strlen", make_unique ()); + kfm.add_std_ns ("strncpy", make_unique ()); + kfm.add_std_ns ("strtok", make_unique (rmm)); + } } } // namespace ana diff --git a/gcc/analyzer/known-function-manager.cc b/gcc/analyzer/known-function-manager.cc index 9f7aeb8..d24e5b8 100644 --- a/gcc/analyzer/known-function-manager.cc +++ b/gcc/analyzer/known-function-manager.cc @@ -50,6 +50,8 @@ known_function_manager::~known_function_manager () /* Delete all owned kfs. */ for (auto iter : m_map_id_to_kf) delete iter.second; + for (auto iter : m_std_ns_map_id_to_kf) + delete iter.second; for (auto iter : m_combined_fns_arr) delete iter; } @@ -64,6 +66,15 @@ known_function_manager::add (const char *name, } void +known_function_manager::add_std_ns (const char *name, + std::unique_ptr kf) +{ + LOG_FUNC_1 (get_logger (), "registering std::%s", name); + tree id = get_identifier (name); + m_std_ns_map_id_to_kf.put (id, kf.release ()); +} + +void known_function_manager::add (enum built_in_function name, std::unique_ptr kf) { @@ -104,7 +115,16 @@ known_function_manager::get_match (tree fndecl, const call_details &cd) const /* Look for a match by name. */ - /* Reject fndecls that aren't in the root namespace. */ + if (is_std_function_p (fndecl)) + { + if (tree identifier = DECL_NAME (fndecl)) + if (const known_function *candidate + = get_by_identifier_in_std_ns (identifier)) + if (candidate->matches_call_types_p (cd)) + return candidate; + return nullptr; + } + if (DECL_CONTEXT (fndecl) && TREE_CODE (DECL_CONTEXT (fndecl)) != TRANSLATION_UNIT_DECL) return NULL; @@ -158,6 +178,22 @@ known_function_manager::get_by_identifier (tree identifier) const return NULL; } +/* Get any known_function in C++ std:: namespace matching IDENTIFIER, without + type-checking. + Return nullptr if there isn't one. */ + +const known_function * +known_function_manager::get_by_identifier_in_std_ns (tree identifier) const +{ + known_function_manager *mut_this = const_cast(this); + known_function **slot = mut_this->m_std_ns_map_id_to_kf.get (identifier); + if (slot) + return *slot; + else + return nullptr; +} + + } // namespace ana #endif /* #if ENABLE_ANALYZER */ diff --git a/gcc/analyzer/known-function-manager.h b/gcc/analyzer/known-function-manager.h index 81e42e1..cf93193 100644 --- a/gcc/analyzer/known-function-manager.h +++ b/gcc/analyzer/known-function-manager.h @@ -44,6 +44,7 @@ public: ~known_function_manager (); void add (const char *name, std::unique_ptr kf); + void add_std_ns (const char *name, std::unique_ptr kf); void add (enum built_in_function name, std::unique_ptr kf); void add (enum internal_fn ifn, std::unique_ptr kf); @@ -57,11 +58,15 @@ private: const known_function * get_normal_builtin (const builtin_known_function *builtin_kf) const; const known_function *get_by_identifier (tree identifier) const; + const known_function *get_by_identifier_in_std_ns (tree identifier) const; /* Map from identifier to known_function instance. Has ownership of the latter. */ hash_map m_map_id_to_kf; + /* Likewise for C++'s std:: namespace. */ + hash_map m_std_ns_map_id_to_kf; + /* Array of known builtins. */ known_function *m_combined_fns_arr[CFN_LAST]; }; diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc index 6739c31..f85b400 100644 --- a/gcc/analyzer/sm-file.cc +++ b/gcc/analyzer/sm-file.cc @@ -648,6 +648,14 @@ register_known_file_functions (known_function_manager &kfm) kfm.add ("fread", make_unique ()); kfm.add ("getc", make_unique ()); kfm.add ("getchar", make_unique ()); + + /* Some C++ implementations use the std:: copies of these functions + from for , so we must match against these too. */ + kfm.add_std_ns ("ferror", make_unique ()); + kfm.add_std_ns ("fgets", make_unique ()); + kfm.add_std_ns ("fread", make_unique ()); + kfm.add_std_ns ("getc", make_unique ()); + kfm.add_std_ns ("getchar", make_unique ()); } #if CHECKING_P diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc index 4e11d6d..fc6718a 100644 --- a/gcc/analyzer/sm-malloc.cc +++ b/gcc/analyzer/sm-malloc.cc @@ -1983,6 +1983,7 @@ malloc_state_machine::on_stmt (sm_context *sm_ctxt, } if (is_named_call_p (callee_fndecl, "realloc", call, 2) + || is_std_named_call_p (callee_fndecl, "realloc", call, 2) || is_named_call_p (callee_fndecl, "__builtin_realloc", call, 2)) { on_realloc_call (sm_ctxt, node, call); diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc index 93269ca..84603c5 100644 --- a/gcc/analyzer/sm-signal.cc +++ b/gcc/analyzer/sm-signal.cc @@ -320,7 +320,13 @@ static bool signal_unsafe_p (tree fndecl) { function_set fs = get_async_signal_unsafe_fns (); - return fs.contains_decl_p (fndecl); + if (fs.contains_decl_p (fndecl)) + return true; + if (is_std_function_p (fndecl) + && fs.contains_name_p (IDENTIFIER_POINTER (DECL_NAME (fndecl)))) + return true; + + return false; } /* Implementation of state_machine::on_stmt vfunc for signal_state_machine. */ @@ -335,7 +341,8 @@ signal_state_machine::on_stmt (sm_context *sm_ctxt, { if (const gcall *call = dyn_cast (stmt)) if (tree callee_fndecl = sm_ctxt->get_fndecl_for_call (call)) - if (is_named_call_p (callee_fndecl, "signal", call, 2)) + if (is_named_call_p (callee_fndecl, "signal", call, 2) + || is_std_named_call_p (callee_fndecl, "signal", call, 2)) { tree handler = gimple_call_arg (call, 1); if (TREE_CODE (handler) == ADDR_EXPR diff --git a/gcc/testsuite/c-c++-common/analyzer/fd-glibc-byte-stream-socket.c b/gcc/testsuite/c-c++-common/analyzer/fd-glibc-byte-stream-socket.c index fab8426..fd57d3b 100644 --- a/gcc/testsuite/c-c++-common/analyzer/fd-glibc-byte-stream-socket.c +++ b/gcc/testsuite/c-c++-common/analyzer/fd-glibc-byte-stream-socket.c @@ -1,5 +1,9 @@ /* Example from glibc manual (16.9.6). */ /* { dg-require-effective-target sockets } */ + +/* Needed on some targets until we have exception-handling working (PR 111475). */ +/* { dg-additional-options "-fno-exceptions" } */ + /* { dg-skip-if "" { hppa*-*-hpux* powerpc*-*-aix* } } */ #include diff --git a/gcc/testsuite/c-c++-common/analyzer/fd-manpage-getaddrinfo-client.c b/gcc/testsuite/c-c++-common/analyzer/fd-manpage-getaddrinfo-client.c index 21dfe97..ee7e4b4 100644 --- a/gcc/testsuite/c-c++-common/analyzer/fd-manpage-getaddrinfo-client.c +++ b/gcc/testsuite/c-c++-common/analyzer/fd-manpage-getaddrinfo-client.c @@ -28,6 +28,10 @@ the source, must acknowledge the copyright and authors of this work. /* { dg-require-effective-target sockets } */ /* { dg-additional-options "-Wno-analyzer-too-complex" } */ + +/* Needed on some targets until we have exception-handling working (PR 111475). */ +/* { dg-additional-options "-fno-exceptions" } */ + /* { dg-skip-if "" { hppa*-*-hpux* powerpc*-*-aix* } } */ #include diff --git a/gcc/testsuite/c-c++-common/analyzer/fd-manpage-getaddrinfo-server.c b/gcc/testsuite/c-c++-common/analyzer/fd-manpage-getaddrinfo-server.c new file mode 100644 index 0000000..7bc4568 --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/fd-manpage-getaddrinfo-server.c @@ -0,0 +1,126 @@ +/* Example from getaddrinfo.3 manpage, which has this license: + +Copyright (c) 2007, 2008 Michael Kerrisk +and Copyright (c) 2006 Ulrich Drepper +A few pieces of an earlier version remain: +Copyright 2000, Sam Varshavchik + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Since the Linux kernel and libraries are constantly changing, this +manual page may be incorrect or out-of-date. The author(s) assume no +responsibility for errors or omissions, or for damages resulting from +the use of the information contained herein. The author(s) may not +have taken the same level of care in the production of this manual, +which is licensed free of charge, as they might when working +professionally. + +Formatted or processed versions of this manual, if unaccompanied by +the source, must acknowledge the copyright and authors of this work. +*/ + +/* { dg-require-effective-target sockets } */ + +/* Needed on some targets until we have exception-handling working (PR 111475). */ +/* { dg-additional-options "-fno-exceptions" } */ + +/* { dg-skip-if "" { hppa*-*-hpux* powerpc*-*-aix* } } */ + +#include +#include +#include +#include +#include +#include +#include + +#define BUF_SIZE 500 + +int +main(int argc, char *argv[]) +{ + struct addrinfo hints; + struct addrinfo *result, *rp; + int sfd, s; + struct sockaddr_storage peer_addr; + socklen_t peer_addr_len; + ssize_t nread; + char buf[BUF_SIZE]; + + if (argc != 2) { + fprintf(stderr, "Usage: %s port\n", argv[0]); + exit(EXIT_FAILURE); + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + hints.ai_protocol = 0; /* Any protocol */ + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + s = getaddrinfo(NULL, argv[1], &hints, &result); + if (s != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); + exit(EXIT_FAILURE); + } + + /* getaddrinfo() returns a list of address structures. + Try each address until we successfully bind(2). + If socket(2) (or bind(2)) fails, we (close the socket + and) try the next address. */ + + for (rp = result; rp != NULL; rp = rp->ai_next) { + sfd = socket(rp->ai_family, rp->ai_socktype, + rp->ai_protocol); + if (sfd == -1) + continue; + + if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) + break; /* Success */ + + close(sfd); + } + + freeaddrinfo(result); /* No longer needed */ + + if (rp == NULL) { /* No address succeeded */ + fprintf(stderr, "Could not bind\n"); + exit(EXIT_FAILURE); + } + + /* Read datagrams and echo them back to sender. */ + + for (;;) { + peer_addr_len = sizeof(peer_addr); + nread = recvfrom(sfd, buf, BUF_SIZE, 0, + (struct sockaddr *) &peer_addr, &peer_addr_len); + if (nread == -1) + continue; /* Ignore failed request */ + + char host[NI_MAXHOST], service[NI_MAXSERV]; + + s = getnameinfo((struct sockaddr *) &peer_addr, + peer_addr_len, host, NI_MAXHOST, + service, NI_MAXSERV, NI_NUMERICSERV); + if (s == 0) + printf("Received %zd bytes from %s:%s\n", + nread, host, service); + else + fprintf(stderr, "getnameinfo: %s\n", gai_strerror(s)); + + if (sendto(sfd, buf, nread, 0, + (struct sockaddr *) &peer_addr, + peer_addr_len) != nread) + fprintf(stderr, "Error sending response\n"); + } +} diff --git a/gcc/testsuite/c-c++-common/analyzer/fd-mappage-getaddrinfo-server.c b/gcc/testsuite/c-c++-common/analyzer/fd-mappage-getaddrinfo-server.c deleted file mode 100644 index 2e9cec4..0000000 --- a/gcc/testsuite/c-c++-common/analyzer/fd-mappage-getaddrinfo-server.c +++ /dev/null @@ -1,122 +0,0 @@ -/* Example from getaddrinfo.3 manpage, which has this license: - -Copyright (c) 2007, 2008 Michael Kerrisk -and Copyright (c) 2006 Ulrich Drepper -A few pieces of an earlier version remain: -Copyright 2000, Sam Varshavchik - -Permission is granted to make and distribute verbatim copies of this -manual provided the copyright notice and this permission notice are -preserved on all copies. - -Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided that the -entire resulting derived work is distributed under the terms of a -permission notice identical to this one. - -Since the Linux kernel and libraries are constantly changing, this -manual page may be incorrect or out-of-date. The author(s) assume no -responsibility for errors or omissions, or for damages resulting from -the use of the information contained herein. The author(s) may not -have taken the same level of care in the production of this manual, -which is licensed free of charge, as they might when working -professionally. - -Formatted or processed versions of this manual, if unaccompanied by -the source, must acknowledge the copyright and authors of this work. -*/ - -/* { dg-require-effective-target sockets } */ -/* { dg-skip-if "" { hppa*-*-hpux* powerpc*-*-aix* } } */ - -#include -#include -#include -#include -#include -#include -#include - -#define BUF_SIZE 500 - -int -main(int argc, char *argv[]) -{ - struct addrinfo hints; - struct addrinfo *result, *rp; - int sfd, s; - struct sockaddr_storage peer_addr; - socklen_t peer_addr_len; - ssize_t nread; - char buf[BUF_SIZE]; - - if (argc != 2) { - fprintf(stderr, "Usage: %s port\n", argv[0]); - exit(EXIT_FAILURE); - } - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ - hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ - hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ - hints.ai_protocol = 0; /* Any protocol */ - hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; - - s = getaddrinfo(NULL, argv[1], &hints, &result); - if (s != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); - exit(EXIT_FAILURE); - } - - /* getaddrinfo() returns a list of address structures. - Try each address until we successfully bind(2). - If socket(2) (or bind(2)) fails, we (close the socket - and) try the next address. */ - - for (rp = result; rp != NULL; rp = rp->ai_next) { - sfd = socket(rp->ai_family, rp->ai_socktype, - rp->ai_protocol); - if (sfd == -1) - continue; - - if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) - break; /* Success */ - - close(sfd); - } - - freeaddrinfo(result); /* No longer needed */ - - if (rp == NULL) { /* No address succeeded */ - fprintf(stderr, "Could not bind\n"); - exit(EXIT_FAILURE); - } - - /* Read datagrams and echo them back to sender. */ - - for (;;) { - peer_addr_len = sizeof(peer_addr); - nread = recvfrom(sfd, buf, BUF_SIZE, 0, - (struct sockaddr *) &peer_addr, &peer_addr_len); - if (nread == -1) - continue; /* Ignore failed request */ - - char host[NI_MAXHOST], service[NI_MAXSERV]; - - s = getnameinfo((struct sockaddr *) &peer_addr, - peer_addr_len, host, NI_MAXHOST, - service, NI_MAXSERV, NI_NUMERICSERV); - if (s == 0) - printf("Received %zd bytes from %s:%s\n", - nread, host, service); - else - fprintf(stderr, "getnameinfo: %s\n", gai_strerror(s)); - - if (sendto(sfd, buf, nread, 0, - (struct sockaddr *) &peer_addr, - peer_addr_len) != nread) - fprintf(stderr, "Error sending response\n"); - } -} diff --git a/gcc/testsuite/c-c++-common/analyzer/fd-socket-meaning.c b/gcc/testsuite/c-c++-common/analyzer/fd-socket-meaning.c index 82a199f..995d3a1 100644 --- a/gcc/testsuite/c-c++-common/analyzer/fd-socket-meaning.c +++ b/gcc/testsuite/c-c++-common/analyzer/fd-socket-meaning.c @@ -1,4 +1,8 @@ /* { dg-require-effective-target sockets } */ + +/* Needed on some targets until we have exception-handling working (PR 111475). */ +/* { dg-additional-options "-fno-exceptions" } */ + /* { dg-additional-options "-fanalyzer-verbose-state-changes" } */ #include diff --git a/gcc/testsuite/c-c++-common/analyzer/fd-symbolic-socket.c b/gcc/testsuite/c-c++-common/analyzer/fd-symbolic-socket.c index 32264fd..c6af0a6 100644 --- a/gcc/testsuite/c-c++-common/analyzer/fd-symbolic-socket.c +++ b/gcc/testsuite/c-c++-common/analyzer/fd-symbolic-socket.c @@ -1,4 +1,8 @@ /* { dg-require-effective-target sockets } */ + +/* Needed on some targets until we have exception-handling working (PR 111475). */ +/* { dg-additional-options "-fno-exceptions" } */ + /* { dg-skip-if "" { hppa*-*-hpux* powerpc*-*-aix* } } */ #include diff --git a/gcc/testsuite/c-c++-common/analyzer/flexible-array-member-1.c b/gcc/testsuite/c-c++-common/analyzer/flexible-array-member-1.c index 82dbcec..d794336 100644 --- a/gcc/testsuite/c-c++-common/analyzer/flexible-array-member-1.c +++ b/gcc/testsuite/c-c++-common/analyzer/flexible-array-member-1.c @@ -27,8 +27,7 @@ test_const_size_oob_1 (void) if (str) { str->len = 10; memset(str->data, 'x', 10); /* { dg-warning "heap-based buffer overflow" "Wanalyzer-out-of-bounds" } */ - /* { dg-warning "'memset' writing 10 bytes into a region of size 0 overflows the destination" "Wstringop-overflow" { target c } .-1 } */ - /* { dg-warning "'void\\* memset\\(void\\*, int, size_t\\)' writing 10 bytes into a region of size 0 overflows the destination" "Wstringop-overflow" { target c++ } .-2 } */ + /* { dg-warning "'\[^\n\r\]*memset\[^\n\r\]*' writing 10 bytes into a region of size 0 overflows the destination" "Wstringop-overflow" { target *-*-* } .-1 } */ return str; } return NULL; @@ -42,8 +41,7 @@ test_const_size_oob_2 (void) str->len = 10; /* Using the wrong size here. */ memset(str->data, 'x', 11); /* { dg-warning "heap-based buffer overflow" "Wanalyzer-out-of-bounds" } */ - /* { dg-warning "'memset' writing 11 bytes into a region of size 10 overflows the destination" "Wstringop-overflow" { target c } .-1 } */ - /* { dg-warning "'void\\* memset\\(void\\*, int, size_t\\)' writing 11 bytes into a region of size 10 overflows the destination" "Wstringop-overflow" { target c++ } .-2 } */ + /* { dg-warning "'\[^\n\r\]*memset\[^\n\r\]*' writing 11 bytes into a region of size 10 overflows the destination" "Wstringop-overflow" { target *-*-* } .-1 } */ return str; } diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-ipa-8-unchecked.c b/gcc/testsuite/c-c++-common/analyzer/malloc-ipa-8-unchecked.c deleted file mode 100644 index 5bc8e57..0000000 --- a/gcc/testsuite/c-c++-common/analyzer/malloc-ipa-8-unchecked.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Example of a multilevel wrapper around malloc, with an unchecked write. */ - -/* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fanalyzer-checker=malloc -fdiagnostics-show-caret" } */ -/* { dg-enable-nn-line-numbers "" } */ - -#include - -void *wrapped_malloc (size_t size) -{ - return malloc (size); -} - -typedef struct boxed_int -{ - int i; -} boxed_int; - -boxed_int * -make_boxed_int (int i) -{ - boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int)); - result->i = i; /* { dg-warning "dereference of possibly-NULL 'result'" } */ - return result; -} - -/* "dereference of possibly-NULL 'result' [CWE-690]". */ -/* { dg-begin-multiline-output "" } - NN | result->i = i; - | ~~~~~~~~~~^~~ - 'make_boxed_int': events 1-2 - | - | NN | make_boxed_int (int i) - | | ^~~~~~~~~~~~~~ - | | | - | | (1) entry to 'make_boxed_int' - | NN | { - | NN | boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int)); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (2) calling 'wrapped_malloc' from 'make_boxed_int' - | - +--> 'wrapped_malloc': events 3-4 - | - | NN | void *wrapped_malloc (size_t size) - | | ^~~~~~~~~~~~~~ - | | | - | | (3) entry to 'wrapped_malloc' - | NN | { - | NN | return malloc (size); - | | ~~~~~~~~~~~~~ - | | | - | | (4) this call could return NULL - | - <------+ - | - 'make_boxed_int': events 5-6 - | - | NN | boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int)); - | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (5) possible return of NULL to 'make_boxed_int' from 'wrapped_malloc' - | NN | result->i = i; - | | ~~~~~~~~~~~~~ - | | | - | | (6) 'result' could be NULL: unchecked value from (4) - | - { dg-end-multiline-output "" { target c } } */ -/* { dg-begin-multiline-output "" } - NN | result->i = i; - | ~~~~~~~~~~^~~ - 'boxed_int* make_boxed_int(int)': events 1-2 - | - | NN | make_boxed_int (int i) - | | ^~~~~~~~~~~~~~ - | | | - | | (1) entry to 'make_boxed_int' - | NN | { - | NN | boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int)); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (2) calling 'wrapped_malloc' from 'make_boxed_int' - | - +--> 'void* wrapped_malloc(size_t)': events 3-4 - | - | NN | void *wrapped_malloc (size_t size) - | | ^~~~~~~~~~~~~~ - | | | - | | (3) entry to 'wrapped_malloc' - | NN | { - | NN | return malloc (size); - | | ~~~~~~~~~~~~~ - | | | - | | (4) this call could return NULL - | - <------+ - | - 'boxed_int* make_boxed_int(int)': events 5-6 - | - | NN | boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int)); - | | ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~ - | | | - | | (5) possible return of NULL to 'make_boxed_int' from 'wrapped_malloc' - | NN | result->i = i; - | | ~~~~~~~~~~~~~ - | | | - | | (6) 'result' could be NULL: unchecked value from (4) - | - { dg-end-multiline-output "" { target c++ } } */ diff --git a/gcc/testsuite/c-c++-common/analyzer/pr106539.c b/gcc/testsuite/c-c++-common/analyzer/pr106539.c index fd27086..8745c1d 100644 --- a/gcc/testsuite/c-c++-common/analyzer/pr106539.c +++ b/gcc/testsuite/c-c++-common/analyzer/pr106539.c @@ -7,7 +7,7 @@ void *test (void) return NULL; p[0] = malloc(10); p[1] = malloc(20); /* { dg-message "allocated here" } */ - void *q = realloc (p, sizeof (void *)); /* { dg-message "when 'realloc' succeeds, moving buffer" } */ + void *q = realloc (p, sizeof (void *)); /* { dg-message "when '\[^\n\r\]*realloc\[^\n\r\]*' succeeds, moving buffer" } */ if (!q) /* { dg-warning "leak of ''" "leak of unknown" { target *-*-* } .-1 } */ return p; diff --git a/gcc/testsuite/c-c++-common/analyzer/signal-4a.c b/gcc/testsuite/c-c++-common/analyzer/signal-4a.c deleted file mode 100644 index b5c6012..0000000 --- a/gcc/testsuite/c-c++-common/analyzer/signal-4a.c +++ /dev/null @@ -1,122 +0,0 @@ -/* Verify how paths are printed for signal-handler diagnostics. */ - -/* { dg-options "-fanalyzer -fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */ -/* { dg-enable-nn-line-numbers "" } */ -/* { dg-require-effective-target signal } */ - -#include -#include -#include - -extern void body_of_program(void); - -void custom_logger(const char *msg) -{ - fprintf(stderr, "LOG: %s", msg); /* { dg-warning "call to 'fprintf' from within signal handler" "" { target c } } */ - /* { dg-warning "call to 'int fprintf\\(FILE\\*, const char\\*, ...\\)' from within signal handler" "" { target c++ } .-1 } */ -} - -static void int_handler(int signum) -{ - custom_logger("got signal"); -} - -void test (void) -{ - void *ptr = malloc (1024); - signal(SIGINT, int_handler); - body_of_program(); - free (ptr); -} - -/* "call to 'fprintf' from within signal handler [CWE-479]". */ -/* { dg-begin-multiline-output "" } - NN | fprintf(stderr, "LOG: %s", msg); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 'test': events 1-2 - | - | NN | void test (void) - | | ^~~~ - | | | - | | (1) entry to 'test' - |...... - | NN | signal(SIGINT, int_handler); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (2) registering 'int_handler' as signal handler - | - event 3 - | - |cc1: - | (3): later on, when the signal is delivered to the process - | - +--> 'int_handler': events 4-5 - | - | NN | static void int_handler(int signum) - | | ^~~~~~~~~~~ - | | | - | | (4) entry to 'int_handler' - | NN | { - | NN | custom_logger("got signal"); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (5) calling 'custom_logger' from 'int_handler' - | - +--> 'custom_logger': events 6-7 - | - | NN | void custom_logger(const char *msg) - | | ^~~~~~~~~~~~~ - | | | - | | (6) entry to 'custom_logger' - | NN | { - | NN | fprintf(stderr, "LOG: %s", msg); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (7) call to 'fprintf' from within signal handler - | - { dg-end-multiline-output "" { target c } } */ -/* { dg-begin-multiline-output "" } - NN | fprintf(stderr, "LOG: %s", msg); - | ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~ - 'void test()': events 1-2 - | - | NN | void test (void) - | | ^~~~ - | | | - | | (1) entry to 'test' - |...... - | NN | signal(SIGINT, int_handler); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (2) registering 'void int_handler(int)' as signal handler - | - event 3 - | - |cc1plus: - | (3): later on, when the signal is delivered to the process - | - +--> 'void int_handler(int)': events 4-5 - | - | NN | static void int_handler(int signum) - | | ^~~~~~~~~~~ - | | | - | | (4) entry to 'int_handler' - | NN | { - | NN | custom_logger("got signal"); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (5) calling 'custom_logger' from 'int_handler' - | - +--> 'void custom_logger(const char*)': events 6-7 - | - | NN | void custom_logger(const char *msg) - | | ^~~~~~~~~~~~~ - | | | - | | (6) entry to 'custom_logger' - | NN | { - | NN | fprintf(stderr, "LOG: %s", msg); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (7) call to 'int fprintf(FILE*, const char*, ...)' from within signal handler - | - { dg-end-multiline-output "" { target c++ } } */ diff --git a/gcc/testsuite/c-c++-common/analyzer/signal-4b.c b/gcc/testsuite/c-c++-common/analyzer/signal-4b.c deleted file mode 100644 index d2b5db7..0000000 --- a/gcc/testsuite/c-c++-common/analyzer/signal-4b.c +++ /dev/null @@ -1,149 +0,0 @@ -/* Verify how paths are printed for signal-handler diagnostics. */ - -/* { dg-options "-fanalyzer -fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */ -/* { dg-enable-nn-line-numbers "" } */ -/* { dg-require-effective-target signal } */ - -#include -#include -#include - -extern void body_of_program(void); - -void custom_logger(const char *msg) -{ - fprintf(stderr, "LOG: %s", msg); /* { dg-warning "call to 'fprintf' from within signal handler" "" { target c } } */ - /* { dg-warning "call to 'int fprintf\\(FILE\\*, const char\\*, ...\\)' from within signal handler" "" { target c++ } .-1 } */ -} - -static void int_handler(int signum) -{ - custom_logger("got signal"); -} - -static void __analyzer_register_handler () -{ - signal(SIGINT, int_handler); -} - -void test (void) -{ - __analyzer_register_handler (); - body_of_program(); -} - -/* "call to 'fprintf' from within signal handler [CWE-479]". */ -/* { dg-begin-multiline-output "" } - NN | fprintf(stderr, "LOG: %s", msg); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 'test': events 1-2 - | - | NN | void test (void) - | | ^~~~ - | | | - | | (1) entry to 'test' - | NN | { - | NN | __analyzer_register_handler (); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (2) calling '__analyzer_register_handler' from 'test' - | - +--> '__analyzer_register_handler': events 3-4 - | - | NN | static void __analyzer_register_handler () - | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (3) entry to '__analyzer_register_handler' - | NN | { - | NN | signal(SIGINT, int_handler); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (4) registering 'int_handler' as signal handler - | - event 5 - | - |cc1: - | (5): later on, when the signal is delivered to the process - | - +--> 'int_handler': events 6-7 - | - | NN | static void int_handler(int signum) - | | ^~~~~~~~~~~ - | | | - | | (6) entry to 'int_handler' - | NN | { - | NN | custom_logger("got signal"); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (7) calling 'custom_logger' from 'int_handler' - | - +--> 'custom_logger': events 8-9 - | - | NN | void custom_logger(const char *msg) - | | ^~~~~~~~~~~~~ - | | | - | | (8) entry to 'custom_logger' - | NN | { - | NN | fprintf(stderr, "LOG: %s", msg); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (9) call to 'fprintf' from within signal handler - | - { dg-end-multiline-output "" { target c } } */ -/* { dg-begin-multiline-output "" } - NN | fprintf(stderr, "LOG: %s", msg); - | ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~ - 'void test()': events 1-2 - | - | NN | void test (void) - | | ^~~~ - | | | - | | (1) entry to 'test' - | NN | { - | NN | __analyzer_register_handler (); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (2) calling '__analyzer_register_handler' from 'test' - | - +--> 'void __analyzer_register_handler()': events 3-4 - | - | NN | static void __analyzer_register_handler () - | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (3) entry to '__analyzer_register_handler' - | NN | { - | NN | signal(SIGINT, int_handler); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (4) registering 'void int_handler(int)' as signal handler - | - event 5 - | - |cc1plus: - | (5): later on, when the signal is delivered to the process - | - +--> 'void int_handler(int)': events 6-7 - | - | NN | static void int_handler(int signum) - | | ^~~~~~~~~~~ - | | | - | | (6) entry to 'int_handler' - | NN | { - | NN | custom_logger("got signal"); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (7) calling 'custom_logger' from 'int_handler' - | - +--> 'void custom_logger(const char*)': events 8-9 - | - | NN | void custom_logger(const char *msg) - | | ^~~~~~~~~~~~~ - | | | - | | (8) entry to 'custom_logger' - | NN | { - | NN | fprintf(stderr, "LOG: %s", msg); - | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | | | - | | (9) call to 'int fprintf(FILE*, const char*, ...)' from within signal handler - | - { dg-end-multiline-output "" { target c++ } } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-8-unchecked.c b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-8-unchecked.c new file mode 100644 index 0000000..f2c10dd --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-8-unchecked.c @@ -0,0 +1,70 @@ +/* Example of a multilevel wrapper around malloc, with an unchecked write. */ + +/* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fanalyzer-checker=malloc -fdiagnostics-show-caret" } */ +/* { dg-enable-nn-line-numbers "" } */ + +/* C only; attempting to generalize it for C++ leads + to an explosion of possibilities for the multiline output. */ + +#include + +void *wrapped_malloc (size_t size) +{ + return malloc (size); +} + +typedef struct boxed_int +{ + int i; +} boxed_int; + +boxed_int * +make_boxed_int (int i) +{ + boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int)); + result->i = i; /* { dg-warning "dereference of possibly-NULL 'result'" } */ + return result; +} + +/* "dereference of possibly-NULL 'result' [CWE-690]". */ +/* { dg-begin-multiline-output "" } + NN | result->i = i; + | ~~~~~~~~~~^~~ + 'make_boxed_int': events 1-2 + | + | NN | make_boxed_int (int i) + | | ^~~~~~~~~~~~~~ + | | | + | | (1) entry to 'make_boxed_int' + | NN | { + | NN | boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int)); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (2) calling 'wrapped_malloc' from 'make_boxed_int' + | + +--> 'wrapped_malloc': events 3-4 + | + | NN | void *wrapped_malloc (size_t size) + | | ^~~~~~~~~~~~~~ + | | | + | | (3) entry to 'wrapped_malloc' + | NN | { + | NN | return malloc (size); + | | ~~~~~~~~~~~~~ + | | | + | | (4) this call could return NULL + | + <------+ + | + 'make_boxed_int': events 5-6 + | + | NN | boxed_int *result = (boxed_int *)wrapped_malloc (sizeof (boxed_int)); + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (5) possible return of NULL to 'make_boxed_int' from 'wrapped_malloc' + | NN | result->i = i; + | | ~~~~~~~~~~~~~ + | | | + | | (6) 'result' could be NULL: unchecked value from (4) + | + { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/signal-4a.c b/gcc/testsuite/gcc.dg/analyzer/signal-4a.c new file mode 100644 index 0000000..538adae --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/signal-4a.c @@ -0,0 +1,79 @@ +/* Verify how paths are printed for signal-handler diagnostics. */ + +/* C only; attempting to generalize it for C++ leads + to an explosion of possibilities for the multiline output. */ + +/* { dg-options "-fanalyzer -fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */ +/* { dg-enable-nn-line-numbers "" } */ +/* { dg-require-effective-target signal } */ + +#include +#include +#include + +extern void body_of_program(void); + +void custom_logger(const char *msg) +{ + fprintf(stderr, "LOG: %s", msg); /* { dg-warning "call to 'fprintf' from within signal handler" } */ +} + +static void int_handler(int signum) +{ + custom_logger("got signal"); +} + +void test (void) +{ + void *ptr = malloc (1024); + signal(SIGINT, int_handler); + body_of_program(); + free (ptr); +} + +/* "call to 'fprintf' from within signal handler [CWE-479]". */ +/* { dg-begin-multiline-output "" } + NN | fprintf(stderr, "LOG: %s", msg); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 'test': events 1-2 + | + | NN | void test (void) + | | ^~~~ + | | | + | | (1) entry to 'test' + |...... + | NN | signal(SIGINT, int_handler); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (2) registering 'int_handler' as signal handler + | + event 3 + | + |cc1: + | (3): later on, when the signal is delivered to the process + | + +--> 'int_handler': events 4-5 + | + | NN | static void int_handler(int signum) + | | ^~~~~~~~~~~ + | | | + | | (4) entry to 'int_handler' + | NN | { + | NN | custom_logger("got signal"); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (5) calling 'custom_logger' from 'int_handler' + | + +--> 'custom_logger': events 6-7 + | + | NN | void custom_logger(const char *msg) + | | ^~~~~~~~~~~~~ + | | | + | | (6) entry to 'custom_logger' + | NN | { + | NN | fprintf(stderr, "LOG: %s", msg); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (7) call to 'fprintf' from within signal handler + | + { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/signal-4b.c b/gcc/testsuite/gcc.dg/analyzer/signal-4b.c new file mode 100644 index 0000000..5bf8c82 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/signal-4b.c @@ -0,0 +1,94 @@ +/* Verify how paths are printed for signal-handler diagnostics. */ + +/* C only; attempting to generalize it for C++ leads + to an explosion of possibilities for the multiline output. */ + +/* { dg-options "-fanalyzer -fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */ +/* { dg-enable-nn-line-numbers "" } */ +/* { dg-require-effective-target signal } */ + +#include +#include +#include + +extern void body_of_program(void); + +void custom_logger(const char *msg) +{ + fprintf(stderr, "LOG: %s", msg); /* { dg-warning "call to 'fprintf' from within signal handler" } */ +} + +static void int_handler(int signum) +{ + custom_logger("got signal"); +} + +static void __analyzer_register_handler () +{ + signal(SIGINT, int_handler); +} + +void test (void) +{ + __analyzer_register_handler (); + body_of_program(); +} + +/* "call to 'fprintf' from within signal handler [CWE-479]". */ +/* { dg-begin-multiline-output "" } + NN | fprintf(stderr, "LOG: %s", msg); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 'test': events 1-2 + | + | NN | void test (void) + | | ^~~~ + | | | + | | (1) entry to 'test' + | NN | { + | NN | __analyzer_register_handler (); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (2) calling '__analyzer_register_handler' from 'test' + | + +--> '__analyzer_register_handler': events 3-4 + | + | NN | static void __analyzer_register_handler () + | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (3) entry to '__analyzer_register_handler' + | NN | { + | NN | signal(SIGINT, int_handler); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (4) registering 'int_handler' as signal handler + | + event 5 + | + |cc1: + | (5): later on, when the signal is delivered to the process + | + +--> 'int_handler': events 6-7 + | + | NN | static void int_handler(int signum) + | | ^~~~~~~~~~~ + | | | + | | (6) entry to 'int_handler' + | NN | { + | NN | custom_logger("got signal"); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (7) calling 'custom_logger' from 'int_handler' + | + +--> 'custom_logger': events 8-9 + | + | NN | void custom_logger(const char *msg) + | | ^~~~~~~~~~~~~ + | | | + | | (8) entry to 'custom_logger' + | NN | { + | NN | fprintf(stderr, "LOG: %s", msg); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (9) call to 'fprintf' from within signal handler + | + { dg-end-multiline-output "" } */ -- cgit v1.1