]> git.ipfire.org Git - thirdparty/gcc.git/commit
analyzer: Add support of placement new and improved operator new [PR105948,PR94355]
authorbenjamin priour <priour.be@gmail.com>
Thu, 31 Aug 2023 22:01:29 +0000 (00:01 +0200)
committerbenjamin priour <vultkayn@gcc.gnu.org>
Fri, 1 Sep 2023 20:03:34 +0000 (22:03 +0200)
commite7b267444045c507654a2a3f758efee5d5b550df
tree1aa37e6cab63d98b2948bd00344fc93badc113b7
parentd3dd69706af4c086cb3385ff1f321887b91f49fb
analyzer: Add support of placement new and improved operator new [PR105948,PR94355]

Fixed spurious possibly-NULL warning always tagging along throwing
operator new despite it never returning NULL.
Now operator new is correctly recognized as possibly returning NULL
if and only if it is non-throwing or exceptions have been disabled.
Different standard signatures of operator new are now properly
recognized.

Added support of placement new, so that it is now properly recognized,
and a 'heap_allocated' region is no longer created for it.
Placement new size is also checked and a 'Wanalyzer-allocation-size'
is emitted when relevant, as well as always a 'Wanalyzer-out-of-bounds'.

'operator new' non-throwing variants are detected y checking the types
of the parameters.
Indeed, in a call to new (std::nothrow) () the chosen overload
has signature 'operator new (void*, std::nothrow_t&)', where the second
parameter is a reference. In a placement new, the second parameter will
always be a void pointer.

Prior to this patch, some buffers first allocated with 'new', then deleted
an thereafter used would result in a 'Wanalyzer-user-after-free'
warning. However the wording was "use after 'free'" instead of the
expected "use after 'delete'".
This patch fixes this by introducing a new kind of poisoned value,
namely POISON_KIND_DELETED.

Due to how the analyzer sees calls to non-throwing variants of
operator new, dereferencing a pointer freshly allocated in this fashion
caused both a 'Wanalyzer-use-of-uninitialized-value' and a
'Wanalyzer-null-dereference' to be emitted, while only the latter was
relevant. As a result, 'null-dereference' now supersedes
'use-of-uninitialized'.

Signed-off-by: benjamin priour <vultkayn@gcc.gnu.org>
gcc/analyzer/ChangeLog:

PR analyzer/105948
PR analyzer/94355
* analyzer.h (is_placement_new_p): New declaration.
* call-details.cc
(call_details::deref_ptr_arg): New function.
Dereference the argument at given index if possible.
* call-details.h: Declaration of the above function.
* kf-lang-cp.cc (is_placement_new_p): Returns true if the gcall
is recognized as a placement new.
(kf_operator_delete::impl_call_post): Unbinding a region and its
descendents now poisons with POISON_KIND_DELETED.
(register_known_functions_lang_cp): Known function "operator
delete" is now registered only once independently of its number of
arguments.
* region-model.cc (region_model::eval_condition): Now
recursively calls itself if any of the operand is wrapped in a
cast.
* sm-malloc.cc (malloc_state_machine::on_stmt):
Add placement new recognition.
* svalue.cc (poison_kind_to_str): Wording for the new PK.
* svalue.h (enum poison_kind): Add value POISON_KIND_DELETED.

gcc/testsuite/ChangeLog:

PR analyzer/105948
PR analyzer/94355
* g++.dg/analyzer/out-of-bounds-placement-new.C: Added a directive.
* g++.dg/analyzer/placement-new.C: Added tests.
* g++.dg/analyzer/new-2.C: New test.
* g++.dg/analyzer/noexcept-new.C: New test.
* g++.dg/analyzer/placement-new-size.C: New test.
13 files changed:
gcc/analyzer/analyzer.h
gcc/analyzer/call-details.cc
gcc/analyzer/call-details.h
gcc/analyzer/kf-lang-cp.cc
gcc/analyzer/region-model.cc
gcc/analyzer/sm-malloc.cc
gcc/analyzer/svalue.cc
gcc/analyzer/svalue.h
gcc/testsuite/g++.dg/analyzer/new-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/analyzer/noexcept-new.C [new file with mode: 0644]
gcc/testsuite/g++.dg/analyzer/out-of-bounds-placement-new.C
gcc/testsuite/g++.dg/analyzer/placement-new-size.C [new file with mode: 0644]
gcc/testsuite/g++.dg/analyzer/placement-new.C