analyzer: fix false positive on realloc [PR99193]
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 25 Feb 2021 00:55:40 +0000 (19:55 -0500)
committerDavid Malcolm <dmalcolm@redhat.com>
Thu, 25 Feb 2021 00:55:40 +0000 (19:55 -0500)
commita6baafcac5308be1a5d92c0b2a179495b7a24b52
tree8aeb92daee4014e212555e84a55af310f2de4c00
parent4028d01a050b478f245aab08702000976b7add2d
analyzer: fix false positive on realloc [PR99193]

PR analyzer/99193 describes various false positives from
-Wanalyzer-mismatching-deallocation on realloc(3) calls
of the form:

    |   31 |   void *p = malloc (1024);
    |      |             ^~~~~~~~~~~~~
    |      |             |
    |      |             (1) allocated here (expects deallocation with ‘free’)
    |   32 |   void *q = realloc (p, 4096);
    |      |             ~~~~~~~~~~~~~~~~~
    |      |             |
    |      |             (2) deallocated with ‘realloc’ here; allocation at (1) expects deallocation with ‘free’
    |

The underlying issue is that the analyzer has no knowledge of
realloc(3), and realloc has awkward semantics.

Unfortunately, the analyzer is currently structured so that each call
statement can only have at most one successor state; there is no
way to "bifurcate" the state, or have N-way splits into multiple
outcomes.  The existing "on_stmt" code works on a copy of the next
state, updating it in place, rather than copying it and making any
necessary changes.  I did this as an optimization to avoid unnecessary
copying of state objects, but it makes it hard to support multiple
outcomes.  (ideally our state objects would be immutable and thus
support trivial copying, alternatively, C++11 move semantics may
help here)

I attempted a few approaches to implementing bifurcation within the
existing state-update framework, but they were messy and thus likely
buggy; a proper implementation would rework state-updating to
generate copies, but this would be a major change, and seems too
late for GCC 11.

As a workaround, this patch implements enough of realloc(3) to
suppress the false positives.

This fixes the false positives in PR analyzer/99193.
I've filed PR analyzer/99260 to track "properly" implementing realloc(3).

gcc/analyzer/ChangeLog:
PR analyzer/99193
* region-model-impl-calls.cc (region_model::impl_call_realloc): New.
* region-model.cc (region_model::on_call_pre): Call it.
* region-model.h (region_model::impl_call_realloc): New decl.
* sm-malloc.cc (enum wording): Add WORDING_REALLOCATED.
(malloc_state_machine::m_realloc): New field.
(use_after_free::describe_state_change): Add case for
WORDING_REALLOCATED.
(use_after_free::describe_final_event): Likewise.
(malloc_state_machine::malloc_state_machine): Initialize
m_realloc.
(malloc_state_machine::on_stmt): Handle realloc by calling...
(malloc_state_machine::on_realloc_call): New.

gcc/testsuite/ChangeLog:
PR analyzer/99193
* gcc.dg/analyzer/pr99193-1.c: New test.
* gcc.dg/analyzer/pr99193-2.c: New test.
* gcc.dg/analyzer/pr99193-3.c: New test.
* gcc.dg/analyzer/realloc-1.c: New test.
gcc/analyzer/region-model-impl-calls.cc
gcc/analyzer/region-model.cc
gcc/analyzer/region-model.h
gcc/analyzer/sm-malloc.cc
gcc/testsuite/gcc.dg/analyzer/pr99193-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/pr99193-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/pr99193-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/realloc-1.c [new file with mode: 0644]