analyzer: handle __attribute__((const)) [PR104434]
authorDavid Malcolm <dmalcolm@redhat.com>
Wed, 23 Feb 2022 14:14:58 +0000 (09:14 -0500)
committerDavid Malcolm <dmalcolm@redhat.com>
Wed, 23 Feb 2022 23:51:26 +0000 (18:51 -0500)
commitaee1adf2cdc1cf4e116e5c05b6e7c92b0fbb264b
treeaecbdc03e6faa33ed77e493db72d474f8b58c7e0
parentcdcea7c1ef6586bb1eb0144b741969748cbd780b
analyzer: handle __attribute__((const)) [PR104434]

When testing -fanalyzer on openblas-0.3, I noticed slightly over 2000
false positives from -Wanalyzer-malloc-leak on code like this:

        if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'p' ) ) {
            pt_t = (lapack_complex_float*)
                LAPACKE_malloc( sizeof(lapack_complex_float) *
                                ldpt_t * MAX(1,n) );
            [...snip...]
        }

        [...snip lots of code...]

        if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'q' ) ) {
            LAPACKE_free( pt_t );
        }

where LAPACKE_lsame is a char-comparison function implemented in a
different TU.
The analyzer naively considers the execution path where:
  LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'p' )
is true at the malloc guard, but then false at the free guard, which
is thus a memory leak.

This patch makes -fanalyer respect __attribute__((const)), so that the
analyzer treats such functions as returning the same value when given
the same inputs.

I've filed https://github.com/xianyi/OpenBLAS/issues/3543 suggesting that
LAPACKE_lsame be annotated with __attribute__((const)); with that, and
with this patch, the false positives seem to be fixed.

gcc/analyzer/ChangeLog:
PR analyzer/104434
* analyzer.h (class const_fn_result_svalue): New decl.
* region-model-impl-calls.cc (call_details::get_manager): New.
* region-model-manager.cc
(region_model_manager::get_or_create_const_fn_result_svalue): New.
(region_model_manager::log_stats): Log
m_const_fn_result_values_map.
* region-model.cc (const_fn_p): New.
(maybe_get_const_fn_result): New.
(region_model::on_call_pre): Handle fndecls with
__attribute__((const)) by calling the above rather than making
a conjured_svalue.
* region-model.h (visitor::visit_const_fn_result_svalue): New.
(region_model_manager::get_or_create_const_fn_result_svalue): New
decl.
(region_model_manager::const_fn_result_values_map_t): New typedef.
(region_model_manager::m_const_fn_result_values_map): New field.
(call_details::get_manager): New decl.
* svalue.cc (svalue::cmp_ptr): Handle SK_CONST_FN_RESULT.
(const_fn_result_svalue::dump_to_pp): New.
(const_fn_result_svalue::dump_input): New.
(const_fn_result_svalue::accept): New.
* svalue.h (enum svalue_kind): Add SK_CONST_FN_RESULT.
(svalue::dyn_cast_const_fn_result_svalue): New.
(class const_fn_result_svalue): New.
(is_a_helper <const const_fn_result_svalue *>::test): New.
(template <> struct default_hash_traits<const_fn_result_svalue::key_t>):
New.

gcc/testsuite/ChangeLog:
PR analyzer/104434
* gcc.dg/analyzer/attr-const-1.c: New test.
* gcc.dg/analyzer/attr-const-2.c: New test.
* gcc.dg/analyzer/attr-const-3.c: New test.
* gcc.dg/analyzer/pr104434-const.c: New test.
* gcc.dg/analyzer/pr104434-nonconst.c: New test.
* gcc.dg/analyzer/pr104434.h: New test.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
13 files changed:
gcc/analyzer/analyzer.h
gcc/analyzer/region-model-impl-calls.cc
gcc/analyzer/region-model-manager.cc
gcc/analyzer/region-model.cc
gcc/analyzer/region-model.h
gcc/analyzer/svalue.cc
gcc/analyzer/svalue.h
gcc/testsuite/gcc.dg/analyzer/attr-const-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/attr-const-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/attr-const-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/pr104434-const.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/pr104434-nonconst.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/pr104434.h [new file with mode: 0644]