analyzer: purge state for unknown function calls
authorDavid Malcolm <dmalcolm@redhat.com>
Sat, 14 Dec 2019 00:48:06 +0000 (19:48 -0500)
committerDavid Malcolm <dmalcolm@redhat.com>
Tue, 14 Jan 2020 23:47:22 +0000 (18:47 -0500)
commitef7827b0bd7cd980da625fcd12e6c56f51a166c2
tree7b501f4af72a1259ff2454de2b4569a221c6bbc4
parent14f9d7b9a708ebca57257059bda40986bb1e82a7
analyzer: purge state for unknown function calls

Whilst analyzing the reproducer for detecting CVE-2005-1689
(krb5-1.4.1's src/lib/krb5/krb/recvauth.c), the analyzer reports
a false double-free of the form:

  krb5_xfree(inbuf.data);
  krb5_read_message(..., &inbuf);
  krb5_xfree(inbuf.data); /* false diagnostic here.  */

where the call to krb5_read_message overwrites inbuf.data with
a freshly-malloced buffer.

This patch fixes the issue by purging state more thorougly when
handling a call with unknown behavior, by walking the graph of
memory regions that are reachable from the call.

gcc/analyzer/ChangeLog:
* analyzer.h (fndecl_has_gimple_body_p): New decl.
* engine.cc (impl_region_model_context::on_unknown_change): New
function.
(fndecl_has_gimple_body_p): Make non-static.
(exploded_node::on_stmt): Treat __analyzer_dump_exploded_nodes as
known.  Track whether we have a call with unknown side-effects and
pass it to on_call_post.
* exploded-graph.h (impl_region_model_context::on_unknown_change):
New decl.
* program-state.cc (sm_state_map::on_unknown_change): New function.
* program-state.h (sm_state_map::on_unknown_change): New decl.
* region-model.cc: Include "bitmap.h".
(region_model::on_call_pre): Return a bool, capturing whether the
call has unknown side effects.
(region_model::on_call_post): Add arg "bool unknown_side_effects"
and if true, call handle_unrecognized_call.
(class reachable_regions): New class.
(region_model::handle_unrecognized_call): New function.
* region-model.h (region_model::on_call_pre): Return a bool.
(region_model::on_call_post): Add arg "bool unknown_side_effects".
(region_model::handle_unrecognized_call): New decl.
(region_model_context::on_unknown_change): New vfunc.
(test_region_model_context::on_unknown_change): New function.

gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/data-model-1.c: Remove xfail.
* gcc.dg/analyzer/data-model-5b.c: Likewise.
* gcc.dg/analyzer/data-model-5c.c: Likewise.
* gcc.dg/analyzer/setjmp-3.c: Mark "foo" as pure.
* gcc.dg/analyzer/setjmp-4.c: Likewise.
* gcc.dg/analyzer/setjmp-6.c: Likewise.
* gcc.dg/analyzer/setjmp-7.c: Likewise.
* gcc.dg/analyzer/setjmp-7a.c: Likewise.
* gcc.dg/analyzer/setjmp-8.c: Likewise.
* gcc.dg/analyzer/setjmp-9.c: Likewise.
* gcc.dg/analyzer/unknown-fns.c: New test.
20 files changed:
gcc/analyzer/ChangeLog
gcc/analyzer/analyzer.h
gcc/analyzer/engine.cc
gcc/analyzer/exploded-graph.h
gcc/analyzer/program-state.cc
gcc/analyzer/program-state.h
gcc/analyzer/region-model.cc
gcc/analyzer/region-model.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/analyzer/data-model-1.c
gcc/testsuite/gcc.dg/analyzer/data-model-5b.c
gcc/testsuite/gcc.dg/analyzer/data-model-5c.c
gcc/testsuite/gcc.dg/analyzer/setjmp-3.c
gcc/testsuite/gcc.dg/analyzer/setjmp-4.c
gcc/testsuite/gcc.dg/analyzer/setjmp-6.c
gcc/testsuite/gcc.dg/analyzer/setjmp-7.c
gcc/testsuite/gcc.dg/analyzer/setjmp-7a.c
gcc/testsuite/gcc.dg/analyzer/setjmp-8.c
gcc/testsuite/gcc.dg/analyzer/setjmp-9.c
gcc/testsuite/gcc.dg/analyzer/unknown-fns.c [new file with mode: 0644]