aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2020-02-27 14:19:33 -0500
committerDavid Malcolm <dmalcolm@redhat.com>2020-03-02 16:40:23 -0500
commit9f00b22f98ec0688fcd9816a03aa3f7eea58bcf7 (patch)
treee3ee554f9d502225feb1db5f03b3ba60ad26c356 /gcc/analyzer
parentcd14f288ddf246d40f109aa7999b99a44739cd99 (diff)
downloadgcc-9f00b22f98ec0688fcd9816a03aa3f7eea58bcf7.zip
gcc-9f00b22f98ec0688fcd9816a03aa3f7eea58bcf7.tar.gz
gcc-9f00b22f98ec0688fcd9816a03aa3f7eea58bcf7.tar.bz2
analyzer: detect malloc, free, calloc within "std" [PR93959]
PR analyzer/93959 reported that g++.dg/analyzer/malloc.C was failing with no output on Solaris. The issue is that <stdlib.h> there has "using std::free;", converting all the "free" calls to std::free, which fails the name-matching via is_named_call_p. This patch implements an is_std_named_call_p variant of is_named_call_p to check for the name within "std", and uses it in sm-malloc.c to check for std::malloc, std::calloc, and std::free. gcc/analyzer/ChangeLog: PR analyzer/93959 * analyzer.cc (is_std_function_p): New function. (is_std_named_call_p): New functions. * analyzer.h (is_std_named_call_p): New decl. * sm-malloc.cc (malloc_state_machine::on_stmt): Check for "std::" variants when checking for malloc, calloc and free. gcc/testsuite/ChangeLog: PR analyzer/93959 * g++.dg/analyzer/cstdlib-2.C: New test. * g++.dg/analyzer/cstdlib.C: New test.
Diffstat (limited to 'gcc/analyzer')
-rw-r--r--gcc/analyzer/ChangeLog9
-rw-r--r--gcc/analyzer/analyzer.cc61
-rw-r--r--gcc/analyzer/analyzer.h2
-rw-r--r--gcc/analyzer/sm-malloc.cc3
4 files changed, 75 insertions, 0 deletions
diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog
index 5fbaec3..e5d7bdb 100644
--- a/gcc/analyzer/ChangeLog
+++ b/gcc/analyzer/ChangeLog
@@ -1,3 +1,12 @@
+2020-03-02 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/93959
+ * analyzer.cc (is_std_function_p): New function.
+ (is_std_named_call_p): New functions.
+ * analyzer.h (is_std_named_call_p): New decl.
+ * sm-malloc.cc (malloc_state_machine::on_stmt): Check for "std::"
+ variants when checking for malloc, calloc and free.
+
2020-02-26 David Malcolm <dmalcolm@redhat.com>
PR analyzer/93950
diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
index 5cf745e..8bc3ce4 100644
--- a/gcc/analyzer/analyzer.cc
+++ b/gcc/analyzer/analyzer.cc
@@ -86,6 +86,49 @@ is_named_call_p (tree fndecl, const char *funcname)
return 0 == strcmp (tname, funcname);
}
+/* Return true if FNDECL is within the namespace "std".
+ Compare with cp/typeck.c: 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
+is_std_function_p (const_tree fndecl)
+{
+ tree name_decl = DECL_NAME (fndecl);
+ if (!name_decl)
+ return false;
+ if (!DECL_CONTEXT (fndecl))
+ return false;
+ if (TREE_CODE (DECL_CONTEXT (fndecl)) != NAMESPACE_DECL)
+ return false;
+ tree ns = DECL_CONTEXT (fndecl);
+ if (!(DECL_CONTEXT (ns) == NULL_TREE
+ || TREE_CODE (DECL_CONTEXT (ns)) == TRANSLATION_UNIT_DECL))
+ return false;
+ if (!DECL_NAME (ns))
+ return false;
+ return id_equal ("std", DECL_NAME (ns));
+}
+
+/* Like is_named_call_p, but look for std::FUNCNAME. */
+
+bool
+is_std_named_call_p (tree fndecl, const char *funcname)
+{
+ gcc_assert (fndecl);
+ gcc_assert (funcname);
+
+ if (!is_std_function_p (fndecl))
+ return false;
+
+ tree identifier = DECL_NAME (fndecl);
+ const char *name = IDENTIFIER_POINTER (identifier);
+ const char *tname = name;
+
+ /* Don't disregard prefix _ or __ in FNDECL's name. */
+
+ return 0 == strcmp (tname, funcname);
+}
+
/* Helper function for checkers. Is FNDECL an extern fndecl at file scope
that has the given FUNCNAME, and does CALL have the given number of
arguments? */
@@ -106,6 +149,24 @@ is_named_call_p (tree fndecl, const char *funcname,
return true;
}
+/* Like is_named_call_p, but check for std::FUNCNAME. */
+
+bool
+is_std_named_call_p (tree fndecl, const char *funcname,
+ const gcall *call, unsigned int num_args)
+{
+ gcc_assert (fndecl);
+ gcc_assert (funcname);
+
+ if (!is_std_named_call_p (fndecl, funcname))
+ return false;
+
+ if (gimple_call_num_args (call) != num_args)
+ return false;
+
+ return true;
+}
+
/* Return true if stmt is a setjmp or sigsetjmp call. */
bool
diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index 1ae76cc..5364edb 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -78,6 +78,8 @@ extern bool is_special_named_call_p (const gcall *call, const char *funcname,
extern bool is_named_call_p (tree fndecl, const char *funcname);
extern bool is_named_call_p (tree fndecl, const char *funcname,
const gcall *call, unsigned int num_args);
+extern bool is_std_named_call_p (tree fndecl, const char *funcname,
+ const gcall *call, unsigned int num_args);
extern bool is_setjmp_call_p (const gcall *call);
extern bool is_longjmp_call_p (const gcall *call);
diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc
index 46225b6..aaef695 100644
--- a/gcc/analyzer/sm-malloc.cc
+++ b/gcc/analyzer/sm-malloc.cc
@@ -611,6 +611,8 @@ malloc_state_machine::on_stmt (sm_context *sm_ctxt,
{
if (is_named_call_p (callee_fndecl, "malloc", call, 1)
|| is_named_call_p (callee_fndecl, "calloc", call, 2)
+ || is_std_named_call_p (callee_fndecl, "malloc", call, 1)
+ || is_std_named_call_p (callee_fndecl, "calloc", call, 2)
|| is_named_call_p (callee_fndecl, "__builtin_malloc", call, 1)
|| is_named_call_p (callee_fndecl, "__builtin_calloc", call, 2))
{
@@ -640,6 +642,7 @@ malloc_state_machine::on_stmt (sm_context *sm_ctxt,
}
if (is_named_call_p (callee_fndecl, "free", call, 1)
+ || is_std_named_call_p (callee_fndecl, "free", call, 1)
|| is_named_call_p (callee_fndecl, "__builtin_free", call, 1))
{
tree arg = gimple_call_arg (call, 0);