Line data Source code
1 : /* Support for plugin-supplied behaviors of known functions.
2 : Copyright (C) 2022-2026 Free Software Foundation, Inc.
3 : Contributed by David Malcolm <dmalcolm@redhat.com>.
4 :
5 : This file is part of GCC.
6 :
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.
11 :
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.
16 :
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/>. */
20 :
21 : #include "analyzer/common.h"
22 :
23 : #include "diagnostic-core.h"
24 : #include "stringpool.h"
25 :
26 : #include "analyzer/analyzer-logging.h"
27 : #include "analyzer/known-function-manager.h"
28 : #include "analyzer/region-model.h"
29 : #include "analyzer/call-details.h"
30 :
31 : #if ENABLE_ANALYZER
32 :
33 : namespace ana {
34 :
35 : /* class known_function_manager : public log_user. */
36 :
37 4061 : known_function_manager::known_function_manager (logger *logger)
38 4061 : : log_user (logger)
39 : {
40 4061 : memset (m_combined_fns_arr, 0, sizeof (m_combined_fns_arr));
41 4061 : }
42 :
43 4061 : known_function_manager::~known_function_manager ()
44 : {
45 : /* Delete all owned kfs. */
46 385777 : for (auto iter : m_map_id_to_kf)
47 381716 : delete iter.second;
48 74081 : for (auto iter : m_std_ns_map_id_to_kf)
49 70020 : delete iter.second;
50 9502740 : for (auto iter : m_combined_fns_arr)
51 9498679 : delete iter;
52 4061 : }
53 :
54 : void
55 381716 : known_function_manager::add (const char *name,
56 : std::unique_ptr<known_function> kf)
57 : {
58 381716 : LOG_FUNC_1 (get_logger (), "registering %s", name);
59 381716 : tree id = get_identifier (name);
60 381716 : m_map_id_to_kf.put (id, kf.release ());
61 381716 : }
62 :
63 : void
64 70020 : known_function_manager::add_std_ns (const char *name,
65 : std::unique_ptr<known_function> kf)
66 : {
67 70020 : LOG_FUNC_1 (get_logger (), "registering std::%s", name);
68 70020 : tree id = get_identifier (name);
69 70020 : m_std_ns_map_id_to_kf.put (id, kf.release ());
70 70020 : }
71 :
72 : void
73 350100 : known_function_manager::add (enum built_in_function name,
74 : std::unique_ptr<known_function> kf)
75 : {
76 350100 : gcc_assert (name < END_BUILTINS);
77 350100 : delete m_combined_fns_arr[name];
78 350100 : m_combined_fns_arr[name] = kf.release ();
79 350100 : }
80 :
81 : void
82 17505 : known_function_manager::add (enum internal_fn ifn,
83 : std::unique_ptr<known_function> kf)
84 : {
85 17505 : gcc_assert (ifn < IFN_LAST);
86 17505 : delete m_combined_fns_arr[ifn + int (END_BUILTINS)];
87 17505 : m_combined_fns_arr[ifn + int (END_BUILTINS)] = kf.release ();
88 17505 : }
89 :
90 : /* Get any known_function for FNDECL for call CD.
91 :
92 : The call must match all assumptions made by the known_function (such as
93 : e.g. "argument 1's type must be a pointer type").
94 :
95 : Return nullptr if no known_function is found, or it does not match the
96 : assumption(s). */
97 :
98 : const known_function *
99 370778 : known_function_manager::get_match (tree fndecl, const call_details &cd) const
100 : {
101 : /* Look for a matching built-in. */
102 370778 : if (fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
103 : {
104 337798 : if (const known_function *candidate
105 168899 : = get_normal_builtin (DECL_FUNCTION_CODE (fndecl)))
106 23907 : if (gimple_builtin_call_types_compatible_p (&cd.get_call_stmt (),
107 : fndecl))
108 : return candidate;
109 : }
110 :
111 : /* Look for a match by name. */
112 :
113 346871 : if (is_std_function_p (fndecl))
114 : {
115 1198 : if (tree identifier = DECL_NAME (fndecl))
116 2396 : if (const known_function *candidate
117 1198 : = get_by_identifier_in_std_ns (identifier))
118 120 : if (candidate->matches_call_types_p (cd))
119 : return candidate;
120 1078 : return nullptr;
121 : }
122 :
123 : /* Only match functions declared at global scope, or within namespace
124 : __cxxabiv1 (e.g. __dynamic_cast). */
125 345673 : if (!is_cxxabi_function_p (fndecl))
126 345010 : if (DECL_CONTEXT (fndecl)
127 345010 : && TREE_CODE (DECL_CONTEXT (fndecl)) != TRANSLATION_UNIT_DECL)
128 : return nullptr;
129 :
130 340107 : if (tree identifier = DECL_NAME (fndecl))
131 340107 : if (const known_function *candidate = get_by_identifier (identifier))
132 229740 : if (candidate->matches_call_types_p (cd))
133 229172 : return candidate;
134 :
135 : return nullptr;
136 : }
137 :
138 : /* Get any known_function for IFN, or nullptr. */
139 :
140 : const known_function *
141 4923 : known_function_manager::get_internal_fn (enum internal_fn ifn) const
142 : {
143 4923 : gcc_assert (ifn < IFN_LAST);
144 4923 : return m_combined_fns_arr[ifn + int (END_BUILTINS)];
145 : }
146 :
147 : /* Get any known_function for NAME, without type-checking.
148 : Return nullptr if there isn't one. */
149 :
150 : const known_function *
151 168899 : known_function_manager::get_normal_builtin (enum built_in_function name) const
152 : {
153 : /* The numbers for built-in functions in enum combined_fn are the same as
154 : for the built_in_function enum. */
155 168899 : gcc_assert (name < END_BUILTINS);
156 168899 : return m_combined_fns_arr[name];
157 : }
158 :
159 : const known_function *
160 0 : known_function_manager::
161 : get_normal_builtin (const builtin_known_function *builtin_kf) const
162 : {
163 0 : return get_normal_builtin (builtin_kf->builtin_code ());
164 : }
165 :
166 : /* Get any known_function matching IDENTIFIER, without type-checking.
167 : Return nullptr if there isn't one. */
168 :
169 : const known_function *
170 340107 : known_function_manager::get_by_identifier (tree identifier) const
171 : {
172 340107 : known_function_manager *mut_this = const_cast<known_function_manager *>(this);
173 340107 : known_function **slot = mut_this->m_map_id_to_kf.get (identifier);
174 340107 : if (slot)
175 229740 : return *slot;
176 : else
177 : return nullptr;
178 : }
179 :
180 : /* Get any known_function in C++ std:: namespace matching IDENTIFIER, without
181 : type-checking.
182 : Return nullptr if there isn't one. */
183 :
184 : const known_function *
185 1198 : known_function_manager::get_by_identifier_in_std_ns (tree identifier) const
186 : {
187 1198 : known_function_manager *mut_this = const_cast<known_function_manager *>(this);
188 1198 : known_function **slot = mut_this->m_std_ns_map_id_to_kf.get (identifier);
189 1198 : if (slot)
190 120 : return *slot;
191 : else
192 : return nullptr;
193 : }
194 :
195 :
196 : } // namespace ana
197 :
198 : #endif /* #if ENABLE_ANALYZER */
|