aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer/region-model.cc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2023-01-11 16:27:06 -0500
committerDavid Malcolm <dmalcolm@redhat.com>2023-01-11 16:27:06 -0500
commit688fc162b76dc6747a30fcfd470f4770da0f4924 (patch)
treeff0f5ea0fcfdc97d7508791b82793a27de1128f9 /gcc/analyzer/region-model.cc
parent23b4ce18379cd336d99d7c71701be28118905b57 (diff)
downloadgcc-688fc162b76dc6747a30fcfd470f4770da0f4924.zip
gcc-688fc162b76dc6747a30fcfd470f4770da0f4924.tar.gz
gcc-688fc162b76dc6747a30fcfd470f4770da0f4924.tar.bz2
analyzer: fix leak false positives on "*UNKNOWN = PTR;" [PR108252]
PR analyzer/108252 reports a false positive from -Wanalyzer-malloc-leak on code like this: *ptr_ptr = strdup(EXPR); where ptr_ptr is an UNKNOWN_VALUE. When we handle: *UNKNOWN = PTR; store::set_value normally marks *PTR as having escaped, and this means we don't report PTR as leaking when the last usage of PTR is lost. However this only works for cases where PTR is a region_svalue. In the example in the bug, it's a conjured_svalue, rather than a region_svalue. A similar problem can arise for FDs, which aren't pointers. This patch fixes the bug by updating store::set_value to mark any values stored via *UNKNOWN = VAL as not leaking. Additionally, sm-malloc.cc's known_allocator_p hardcodes strdup and strndup as allocators (and thus transitioning their result to "unchecked"), but we don't implement known_functions for these, leading to the LHS being a CONJURED_SVALUE, rather than a region_svalue to a heap-allocated region. A similar issue happens with functions marked with __attribute__((malloc)). As part of a "belt and braces" fix, the patch also updates the handling of these functions, so that they use heap-allocated regions. gcc/analyzer/ChangeLog: PR analyzer/108252 * kf.cc (class kf_strdup): New. (class kf_strndup): New. (register_known_functions): Register them. * region-model.cc (region_model::on_call_pre): Use &HEAP_ALLOCATED_REGION for the default result of an external function with the "malloc" attribute, rather than CONJURED_SVALUE. (region_model::get_or_create_region_for_heap_alloc): Allow "size_in_bytes" to be NULL. * store.cc (store::set_value): When handling *UNKNOWN = VAL, mark VAL as "maybe bound". gcc/testsuite/ChangeLog: PR analyzer/108252 * gcc.dg/analyzer/attr-malloc-pr108252.c: New test. * gcc.dg/analyzer/fd-leak-pr108252.c: New test. * gcc.dg/analyzer/flex-with-call-summaries.c: Remove xfail from warning false +ve directives. * gcc.dg/analyzer/pr103217-2.c: Add -Wno-analyzer-too-complex. * gcc.dg/analyzer/pr103217-3.c: Likewise. * gcc.dg/analyzer/strdup-pr108252.c: New test. * gcc.dg/analyzer/strndup-pr108252.c: New test. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc/analyzer/region-model.cc')
-rw-r--r--gcc/analyzer/region-model.cc32
1 files changed, 22 insertions, 10 deletions
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 5506440..2e59fba 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1441,6 +1441,8 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
if (ctxt)
check_call_args (cd);
+ tree callee_fndecl = get_fndecl_for_call (call, ctxt);
+
/* Some of the cases below update the lhs of the call based on the
return value, but not all. Provide a default value, which may
get overwritten below. */
@@ -1450,13 +1452,22 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
const svalue *sval = maybe_get_const_fn_result (cd);
if (!sval)
{
- /* For the common case of functions without __attribute__((const)),
- use a conjured value, and purge any prior state involving that
- value (in case this is in a loop). */
- sval = m_mgr->get_or_create_conjured_svalue (TREE_TYPE (lhs), call,
- lhs_region,
- conjured_purge (this,
- ctxt));
+ if (callee_fndecl
+ && lookup_attribute ("malloc", DECL_ATTRIBUTES (callee_fndecl)))
+ {
+ const region *new_reg
+ = get_or_create_region_for_heap_alloc (NULL, ctxt);
+ mark_region_as_unknown (new_reg, NULL);
+ sval = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
+ }
+ else
+ /* For the common case of functions without __attribute__((const)),
+ use a conjured value, and purge any prior state involving that
+ value (in case this is in a loop). */
+ sval = m_mgr->get_or_create_conjured_svalue (TREE_TYPE (lhs), call,
+ lhs_region,
+ conjured_purge (this,
+ ctxt));
}
set_value (lhs_region, sval, ctxt);
}
@@ -1469,7 +1480,7 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
return false;
}
- if (tree callee_fndecl = get_fndecl_for_call (call, ctxt))
+ if (callee_fndecl)
{
int callee_fndecl_flags = flags_from_decl_or_type (callee_fndecl);
@@ -4909,8 +4920,9 @@ region_model::get_or_create_region_for_heap_alloc (const svalue *size_in_bytes,
get_referenced_base_regions (base_regs_in_use);
const region *reg
= m_mgr->get_or_create_region_for_heap_alloc (base_regs_in_use);
- if (compat_types_p (size_in_bytes->get_type (), size_type_node))
- set_dynamic_extents (reg, size_in_bytes, ctxt);
+ if (size_in_bytes)
+ if (compat_types_p (size_in_bytes->get_type (), size_type_node))
+ set_dynamic_extents (reg, size_in_bytes, ctxt);
return reg;
}