libgccjit: Add ability to get the alignment of a type
[official-gcc.git] / gcc / analyzer / kf-lang-cp.cc
blob8d1c566c54510baf6f2ae223711e990d9331dd84
1 /* Handling for the known behavior of various functions specific to C++.
2 Copyright (C) 2020-2024 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #define INCLUDE_MEMORY
23 #define INCLUDE_VECTOR
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tree.h"
27 #include "function.h"
28 #include "basic-block.h"
29 #include "gimple.h"
30 #include "analyzer/analyzer.h"
31 #include "analyzer/analyzer-logging.h"
32 #include "diagnostic.h"
33 #include "analyzer/region-model.h"
34 #include "analyzer/call-details.h"
35 #include "make-unique.h"
37 #if ENABLE_ANALYZER
39 /* Return true if CALL is a non-allocating operator new or operator new []
40 that contains no user-defined args, i.e. having any signature of:
42 - void* operator new (std::size_t count, void* ptr);
43 - void* operator new[] (std::size_t count, void* ptr);
45 See https://en.cppreference.com/w/cpp/memory/new/operator_new. */
47 bool is_placement_new_p (const gcall *call)
49 gcc_assert (call);
50 tree fndecl = gimple_call_fndecl (call);
52 if (!fndecl || TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
53 /* Give up on overloaded operator new. */
54 return false;
56 if (!is_named_call_p (fndecl, "operator new", call, 2)
57 && !is_named_call_p (fndecl, "operator new []", call, 2))
58 return false;
60 /* We must distinguish between an allocating non-throwing new
61 and a non-allocating new.
63 The former might have one of the following signatures :
64 void* operator new (std::size_t count, const std::nothrow_t& tag);
65 void* operator new[] (std::size_t count, const std::nothrow_t& tag);
66 Whereas a placement new would take a pointer. */
67 tree arg1_type = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
68 return TREE_CODE (TREE_VALUE (arg1_type)) == POINTER_TYPE;
71 namespace ana {
73 /* Implementations of specific functions. */
75 /* Handler for "operator new" and "operator new []". */
77 class kf_operator_new : public known_function
79 public:
80 bool matches_call_types_p (const call_details &cd) const final override
82 return (cd.num_args () == 1
83 && cd.arg_is_size_p (0))
84 || (cd.num_args () == 2
85 && cd.arg_is_size_p (0)
86 && POINTER_TYPE_P (cd.get_arg_type (1)));
89 void impl_call_pre (const call_details &cd) const final override
91 region_model *model = cd.get_model ();
92 region_model_manager *mgr = cd.get_manager ();
93 const svalue *size_sval = cd.get_arg_svalue (0);
94 region_model_context *ctxt = cd.get_ctxt ();
95 const gcall *call = cd.get_call_stmt ();
97 /* If the call was actually a placement new, check that accessing
98 the buffer lhs is placed into does not result in out-of-bounds. */
99 if (is_placement_new_p (call))
101 const region *ptr_reg = cd.deref_ptr_arg (1);
102 if (ptr_reg && cd.get_lhs_type ())
104 const svalue *num_bytes_sval = cd.get_arg_svalue (0);
105 const region *sized_new_reg
106 = mgr->get_sized_region (ptr_reg,
107 cd.get_lhs_type (),
108 num_bytes_sval);
109 model->check_region_for_write (sized_new_reg,
110 nullptr,
111 ctxt);
112 const svalue *ptr_sval
113 = mgr->get_ptr_svalue (cd.get_lhs_type (), sized_new_reg);
114 cd.maybe_set_lhs (ptr_sval);
117 /* If the call is an allocating new, then create a heap allocated
118 region. */
119 else
121 const region *new_reg
122 = model->get_or_create_region_for_heap_alloc (size_sval, ctxt);
123 if (cd.get_lhs_type ())
125 const svalue *ptr_sval
126 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
127 cd.maybe_set_lhs (ptr_sval);
132 void impl_call_post (const call_details &cd) const final override
134 region_model *model = cd.get_model ();
135 region_model_manager *mgr = cd.get_manager ();
136 tree callee_fndecl = cd.get_fndecl_for_call ();
137 region_model_context *ctxt = cd.get_ctxt ();
139 /* If the call is guaranteed to return nonnull
140 then add a nonnull constraint to the allocated region. */
141 if (!TREE_NOTHROW (callee_fndecl) && flag_exceptions)
143 const svalue *null_sval
144 = mgr->get_or_create_null_ptr (cd.get_lhs_type ());
145 const svalue *result
146 = model->get_store_value (cd.get_lhs_region (), ctxt);
147 model->add_constraint (result, NE_EXPR, null_sval, ctxt);
152 /* Handler for "operator delete" and for "operator delete []",
153 both the sized and unsized variants
154 (2 arguments and 1 argument respectively). */
156 class kf_operator_delete : public known_function
158 public:
159 bool matches_call_types_p (const call_details &cd) const final override
161 return cd.num_args () == 1 or cd.num_args () == 2;
164 void impl_call_post (const call_details &cd) const final override
166 region_model *model = cd.get_model ();
167 const svalue *ptr_sval = cd.get_arg_svalue (0);
168 if (const region *freed_reg = ptr_sval->maybe_get_region ())
170 /* If the ptr points to an underlying heap region, delete it,
171 poisoning pointers. */
172 model->unbind_region_and_descendents (freed_reg,
173 POISON_KIND_DELETED);
179 /* Populate KFM with instances of known functions relating to C++. */
181 void
182 register_known_functions_lang_cp (known_function_manager &kfm)
184 kfm.add ("operator new", make_unique<kf_operator_new> ());
185 kfm.add ("operator new []", make_unique<kf_operator_new> ());
186 kfm.add ("operator delete", make_unique<kf_operator_delete> ());
187 kfm.add ("operator delete []", make_unique<kf_operator_delete> ());
190 } // namespace ana
192 #endif /* #if ENABLE_ANALYZER */