https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94355

--- Comment #2 from CVS Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by David Malcolm <dmalc...@gcc.gnu.org>:

https://gcc.gnu.org/g:1690a839cff2e0276017a013419d81d675bbf69d

commit r11-3090-g1690a839cff2e0276017a013419d81d675bbf69d
Author: David Malcolm <dmalc...@redhat.com>
Date:   Fri Aug 28 13:43:56 2020 -0400

    analyzer: generalize sm-malloc to new/delete [PR94355]

    This patch generalizes the state machine in sm-malloc.c to support
    multiple allocator APIs, and adds just enough support for C++ new and
    delete to demonstrate the feature, allowing for detection of code
    paths where the result of new in C++ can leak - for some crude examples,
    at least (bearing in mind that the analyzer doesn't yet know about
    e.g. vfuncs, exceptions, inheritance, RTTI, etc)

    It also implements a new warning: -Wanalyzer-mismatching-deallocation.
    For example:

    demo.cc: In function 'void test()':
    demo.cc:8:8: warning: 'f' should have been deallocated with 'delete'
      but was deallocated with 'free' [CWE-762]
[-Wanalyzer-mismatching-deallocation]
        8 |   free (f);
          |   ~~~~~^~~
      'void test()': events 1-2
        |
        |    7 |   foo *f = new foo;
        |      |                ^~~
        |      |                |
        |      |                (1) allocated here (expects deallocation with
'delete')
        |    8 |   free (f);
        |      |   ~~~~~~~~
        |      |        |
        |      |        (2) deallocated with 'free' here; allocation at (1)
expects deallocation with 'delete'
        |

    The patch also adds just enough knowledge of exception-handling to
    suppress a false positive from -Wanalyzer-malloc-leak on
    g++.dg/analyzer/pr96723.C on the exception-handling CFG edge after
    operator new.  It does this by adding a constraint that the result is
    NULL if an exception was thrown from operator new, since the result from
    operator new is lost when following that exception-handling CFG edge.

    gcc/analyzer/ChangeLog:
            PR analyzer/94355
            * analyzer.opt (Wanalyzer-mismatching-deallocation): New warning.
            * region-model-impl-calls.cc
            (region_model::impl_call_operator_new): New.
            (region_model::impl_call_operator_delete): New.
            * region-model.cc (region_model::on_call_pre): Detect operator new
            and operator delete.
            (region_model::on_call_post): Likewise.
            (region_model::maybe_update_for_edge): Detect EH edges and call...
            (region_model::apply_constraints_for_exception): New function.
            * region-model.h (region_model::impl_call_operator_new): New decl.
            (region_model::impl_call_operator_delete): New decl.
            (region_model::apply_constraints_for_exception): New decl.
            * sm-malloc.cc (enum resource_state): New.
            (struct allocation_state): New state subclass.
            (enum wording): New.
            (struct api): New.
            (malloc_state_machine::custom_data_t): New typedef.
            (malloc_state_machine::add_state): New decl.
            (malloc_state_machine::m_unchecked)
            (malloc_state_machine::m_nonnull)
            (malloc_state_machine::m_freed): Delete these states in favor
            of...
            (malloc_state_machine::m_malloc)
            (malloc_state_machine::m_scalar_new)
            (malloc_state_machine::m_vector_new): ...this new api instances,
            which own their own versions of these states.
            (malloc_state_machine::on_allocator_call): New decl.
            (malloc_state_machine::on_deallocator_call): New decl.
            (api::api): New ctor.
            (dyn_cast_allocation_state): New.
            (as_a_allocation_state): New.
            (get_rs): New.
            (unchecked_p): New.
            (nonnull_p): New.
            (freed_p): New.
            (malloc_diagnostic::describe_state_change): Use unchecked_p and
            nonnull_p.
            (class mismatching_deallocation): New.
            (double_free::double_free): Add funcname param for initializing
            m_funcname.
            (double_free::emit): Use m_funcname in warning message rather
            than hardcoding "free".
            (double_free::describe_state_change): Likewise.  Use freed_p.
            (double_free::describe_call_with_state): Use freed_p.
            (double_free::describe_final_event): Use m_funcname in message
            rather than hardcoding "free".
            (double_free::m_funcname): New field.
            (possible_null::describe_state_change): Use unchecked_p.
            (possible_null::describe_return_of_state): Likewise.
            (use_after_free::use_after_free): Add param for initializing m_api.
            (use_after_free::emit): Use m_api->m_dealloc_funcname in message
            rather than hardcoding "free".
            (use_after_free::describe_state_change): Use freed_p.  Change the
            wording of the message based on the API.
            (use_after_free::describe_final_event): Use
            m_api->m_dealloc_funcname in message rather than hardcoding
            "free".  Change the wording of the message based on the API.
            (use_after_free::m_api): New field.
            (malloc_leak::describe_state_change): Use unchecked_p.  Update
            for renaming of m_malloc_event to m_alloc_event.
            (malloc_leak::describe_final_event): Update for renaming of
            m_malloc_event to m_alloc_event.
            (malloc_leak::m_malloc_event): Rename...
            (malloc_leak::m_alloc_event): ...to this.
            (free_of_non_heap::free_of_non_heap): Add param for initializing
            m_funcname.
            (free_of_non_heap::emit): Use m_funcname in message rather than
            hardcoding "free".
            (free_of_non_heap::describe_final_event): Likewise.
            (free_of_non_heap::m_funcname): New field.
            (allocation_state::dump_to_pp): New.
            (allocation_state::get_nonnull): New.
            (malloc_state_machine::malloc_state_machine): Update for changes
            to state fields and new api fields.
            (malloc_state_machine::add_state): New.
            (malloc_state_machine::on_stmt): Move malloc/calloc handling to
            on_allocator_call and call it, passing in the API pointer.
            Likewise for free, moving it to on_deallocator_call.  Handle calls
            to operator new and delete in an analogous way.  Use unchecked_p
            when testing for possibly-null-arg and possibly-null-deref, and
            transition to the non-null for the correct API.  Remove redundant
            node param from call to on_zero_assignment.  Use freed_p for
            use-after-free check, and pass in API.
            (malloc_state_machine::on_allocator_call): New, based on code in
            on_stmt.
            (malloc_state_machine::on_deallocator_call): Likewise.
            (malloc_state_machine::on_phi): Mark node param with
            ATTRIBUTE_UNUSED; don't pass it to on_zero_assignment.
            (malloc_state_machine::on_condition): Mark node param with
            ATTRIBUTE_UNUSED.  Replace on_transition calls with get_state and
            set_next_state pairs, transitioning to the non-null state for the
            appropriate API.
            (malloc_state_machine::can_purge_p): Port to new state approach.
            (malloc_state_machine::on_zero_assignment): Replace on_transition
            calls with get_state and set_next_state pairs.  Drop redundant
            node param.
            * sm.h (state_machine::add_custom_state): New.

    gcc/ChangeLog:
            PR analyzer/94355
            * doc/invoke.texi: Document -Wanalyzer-mismatching-deallocation.

    gcc/testsuite/ChangeLog:
            PR analyzer/94355
            * g++.dg/analyzer/new-1.C: New test.
            * g++.dg/analyzer/new-vs-malloc.C: New test.

Reply via email to