Line data Source code
1 : /* Operations within the code being analyzed.
2 : Copyright (C) 2019-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 "gimple-pretty-print.h"
24 : #include "gimple-iterator.h"
25 : #include "tree-cfg.h"
26 : #include "tree-dfa.h"
27 : #include "fold-const.h"
28 : #include "cgraph.h"
29 : #include "text-art/dump.h"
30 : #include "text-art/tree-widget.h"
31 :
32 : #include "analyzer/ops.h"
33 : #include "analyzer/call-details.h"
34 : #include "analyzer/exploded-graph.h"
35 : #include "analyzer/checker-path.h"
36 : #include "analyzer/impl-sm-context.h"
37 : #include "analyzer/constraint-manager.h"
38 : #include "analyzer/call-summary.h"
39 : #include "analyzer/call-info.h"
40 : #include "analyzer/analysis-plan.h"
41 : #include "analyzer/callsite-expr.h"
42 : #include "analyzer/state-transition.h"
43 :
44 : #if ENABLE_ANALYZER
45 :
46 : namespace ana {
47 :
48 20979 : event_loc_info::event_loc_info (const exploded_node *enode)
49 : {
50 20979 : if (enode)
51 : {
52 20979 : m_loc = enode->get_location ();
53 20979 : m_fndecl = enode->get_point ().get_fndecl ();
54 41913 : m_depth = enode->get_stack_depth ();
55 : }
56 : else
57 : {
58 0 : m_loc = UNKNOWN_LOCATION;
59 0 : m_fndecl = NULL_TREE;
60 0 : m_depth = 0;
61 : }
62 20979 : }
63 :
64 5797 : event_loc_info::event_loc_info (const program_point &point)
65 : {
66 5797 : m_loc = point.get_location ();
67 5797 : m_fndecl = point.get_fndecl ();
68 5797 : m_depth = point.get_stack_depth ();
69 5797 : }
70 :
71 : /* Make an event_loc_info suitable for a function_entry_event at POINT.
72 : If STATE_TRANS is non-null, then try to extract the pertinent parameter
73 : from it and use the location of that parameter, rather than that of the
74 : function name. */
75 :
76 : event_loc_info
77 5028 : event_loc_info_for_function_entry (const program_point &point,
78 : const state_transition_at_call *state_trans)
79 : {
80 5028 : event_loc_info result (point);
81 5028 : if (state_trans)
82 : {
83 23 : callsite_expr expr = state_trans->get_callsite_expr ();
84 46 : expr.maybe_get_param_location (point.get_fndecl (),
85 : &result.m_loc);
86 : }
87 5028 : return result;
88 : }
89 :
90 : // struct operation_context
91 :
92 : void
93 0 : operation_context::dump () const
94 : {
95 0 : fprintf (stderr, "src enode: EN: %i\n", m_src_enode.m_index);
96 0 : m_src_enode.dump (m_eg.get_ext_state ());
97 :
98 0 : fprintf (stderr, "superedge\n");
99 0 : pretty_printer pp;
100 0 : pp.set_output_stream (stderr);
101 0 : m_sedge.dump (&pp);
102 0 : }
103 :
104 : logger *
105 456732 : operation_context::get_logger () const
106 : {
107 456732 : return m_eg.get_logger ();
108 : }
109 :
110 : const extrinsic_state &
111 298857 : operation_context::get_ext_state () const
112 : {
113 298857 : return m_eg.get_ext_state ();
114 : }
115 :
116 : const program_point &
117 24965 : operation_context::get_initial_point () const
118 : {
119 24965 : return m_src_enode.get_point ();
120 : }
121 :
122 : const program_state &
123 1212146 : operation_context::get_initial_state () const
124 : {
125 1212146 : return m_src_enode.get_state ();
126 : }
127 :
128 : const supergraph &
129 6830 : operation_context::get_supergraph () const
130 : {
131 6830 : return m_eg.get_supergraph ();
132 : }
133 :
134 : program_point
135 348619 : operation_context::get_next_intraprocedural_point () const
136 : {
137 : /* All edges are intraprocedural. */
138 348619 : gcc_assert (m_sedge.m_src->get_function ()
139 : == m_sedge.m_dest->get_function ());
140 348619 : return program_point (m_sedge.m_dest,
141 348619 : m_src_enode.get_point ().get_call_string ());
142 : }
143 :
144 : void
145 296965 : operation_context::add_outcome (const program_point &dst_point,
146 : program_state dst_state,
147 : bool could_do_work,
148 : uncertainty_t *uncertainty,
149 : std::unique_ptr<custom_edge_info> info)
150 : {
151 296965 : const program_state &src_state = get_initial_state ();
152 296965 : impl_region_model_context ctxt (m_eg, &m_src_enode,
153 : &src_state, &dst_state,
154 296965 : uncertainty, nullptr);
155 296965 : program_state::detect_leaks (src_state, dst_state, nullptr,
156 : get_ext_state (), &ctxt);
157 :
158 593930 : if (exploded_node *dst_enode
159 296965 : = m_eg.get_or_create_node (dst_point, dst_state, &m_src_enode))
160 : {
161 295926 : m_eg.add_edge (&m_src_enode, dst_enode, &m_sedge, could_do_work,
162 : std::move (info));
163 295926 : m_eg.detect_infinite_recursion (dst_enode);
164 : }
165 296965 : }
166 :
167 221396 : class op_region_model_context : public impl_region_model_context
168 : {
169 : public:
170 110698 : op_region_model_context (operation_context &op_ctxt,
171 : program_state &dst_state)
172 110698 : : impl_region_model_context (op_ctxt.m_eg,
173 110698 : &op_ctxt.m_src_enode,
174 110698 : &op_ctxt.get_initial_state (),
175 : &dst_state,
176 : nullptr,
177 110698 : &m_path_context)
178 : {
179 110698 : }
180 :
181 45112 : bool terminate_path_p () const
182 : {
183 45112 : return m_path_context.terminate_path_p ();
184 : }
185 :
186 : private:
187 60169 : class op_path_context : public path_context
188 : {
189 : public:
190 110698 : op_path_context ()
191 110698 : : m_terminate_path (false)
192 : {
193 : }
194 :
195 0 : void bifurcate (std::unique_ptr<custom_edge_info>) final override
196 : {
197 0 : gcc_unreachable ();
198 : }
199 :
200 42 : void terminate_path () final override
201 : {
202 42 : m_terminate_path = true;
203 42 : }
204 :
205 45112 : bool terminate_path_p () const final override
206 : {
207 45112 : return m_terminate_path;
208 : }
209 : private:
210 : bool m_terminate_path;
211 : } m_path_context;
212 : };
213 :
214 : // struct rewind_context
215 :
216 : void
217 67 : rewind_context::on_data_origin (tree dst_tree)
218 : {
219 67 : gcc_assert (dst_tree);
220 67 : const region_model &dst_enode_model = get_dst_region_model ();
221 67 : const region *dst_reg_in_dst_enode
222 67 : = dst_enode_model.get_lvalue (dst_tree, nullptr);
223 67 : if (m_input.m_region_holding_value == dst_reg_in_dst_enode)
224 : {
225 30 : if (m_logger)
226 0 : m_logger->log ("data origin, into %qE", dst_tree);
227 30 : m_output.m_region_holding_value = nullptr;
228 30 : add_state_transition
229 30 : (std::make_unique<state_transition_origin> (dst_tree));
230 : }
231 67 : }
232 :
233 : void
234 2711 : rewind_context::on_data_flow (tree src_tree, tree dst_tree)
235 : {
236 2711 : gcc_assert (src_tree);
237 2711 : gcc_assert (dst_tree);
238 2711 : const region_model &dst_enode_model = get_dst_region_model ();
239 2711 : const region *dst_reg_in_dst_enode
240 2711 : = dst_enode_model.get_lvalue (dst_tree, nullptr);
241 2711 : if (m_input.m_region_holding_value == dst_reg_in_dst_enode)
242 : {
243 65 : if (m_logger)
244 0 : m_logger->log ("rewinding from %qE to %qE", dst_tree, src_tree);
245 65 : const region_model &src_enode_model = get_src_region_model ();
246 65 : const region *src_reg_in_src_enode
247 65 : = src_enode_model.get_lvalue (src_tree, nullptr);
248 65 : m_output.m_region_holding_value = src_reg_in_src_enode;
249 :
250 65 : if (TREE_CODE (src_tree) == RESULT_DECL)
251 12 : add_state_transition (std::make_unique<state_transition_at_return> ());
252 53 : else if (auto state_trans
253 : = state_transition::make (m_output.m_region_holding_value,
254 : src_tree,
255 : m_input.m_region_holding_value,
256 53 : dst_tree))
257 53 : add_state_transition (std::move (state_trans));
258 : }
259 2711 : }
260 :
261 : // class gimple_stmt_op : public operation
262 :
263 : void
264 1120 : gimple_stmt_op::print_as_edge_label (pretty_printer *pp,
265 : bool /*user_facing*/) const
266 : {
267 1120 : pp_gimple_stmt_1 (pp, &m_stmt, 0, (dump_flags_t)0);
268 1120 : }
269 :
270 : bool
271 182207 : gimple_stmt_op::defines_ssa_name_p (const_tree ssa_name) const
272 : {
273 182207 : return &m_stmt == SSA_NAME_DEF_STMT (ssa_name);
274 : }
275 :
276 : bool
277 35465 : gimple_stmt_op::supports_bulk_merge_p () const
278 : {
279 35465 : return false;
280 : }
281 :
282 : /* Subclass of path_context for use within operation::execute implementations
283 : so that we can split states e.g. at "realloc" calls. */
284 :
285 : class impl_path_context : public path_context
286 : {
287 : public:
288 245280 : impl_path_context (const program_state *cur_state,
289 : logger *logger)
290 245280 : : m_cur_state (cur_state),
291 245280 : m_logger (logger),
292 245280 : m_terminate_path (false)
293 : {
294 : }
295 :
296 : bool bifurcation_p () const
297 : {
298 : return m_custom_eedge_infos.length () > 0;
299 : }
300 :
301 16906 : const program_state &get_state_at_bifurcation () const
302 : {
303 16906 : gcc_assert (m_state_at_bifurcation);
304 16906 : return *m_state_at_bifurcation;
305 : }
306 :
307 : void
308 8489 : bifurcate (std::unique_ptr<custom_edge_info> info) final override
309 : {
310 8489 : if (m_logger)
311 0 : m_logger->log ("bifurcating path");
312 :
313 8489 : if (m_state_at_bifurcation)
314 : /* Verify that the state at bifurcation is consistent when we
315 : split into multiple out-edges. */
316 1743 : gcc_assert (*m_state_at_bifurcation == *m_cur_state);
317 : else
318 : /* Take a copy of the cur_state at the moment when bifurcation
319 : happens. */
320 6746 : m_state_at_bifurcation
321 6746 : = std::unique_ptr<program_state> (new program_state (*m_cur_state));
322 :
323 : /* Take ownership of INFO. */
324 8489 : m_custom_eedge_infos.safe_push (info.release ());
325 8489 : }
326 :
327 2106 : void terminate_path () final override
328 : {
329 2106 : if (m_logger)
330 2 : m_logger->log ("terminating path");
331 2106 : m_terminate_path = true;
332 2106 : }
333 :
334 429572 : bool terminate_path_p () const final override
335 : {
336 429572 : return m_terminate_path;
337 : }
338 :
339 : const vec<custom_edge_info *> & get_custom_eedge_infos ()
340 : {
341 : return m_custom_eedge_infos;
342 : }
343 :
344 : private:
345 : const program_state *m_cur_state;
346 :
347 : logger *m_logger;
348 :
349 : /* Lazily-created copy of the state before the split. */
350 : std::unique_ptr<program_state> m_state_at_bifurcation;
351 :
352 : auto_vec <custom_edge_info *> m_custom_eedge_infos;
353 :
354 : bool m_terminate_path;
355 : };
356 :
357 : DEBUG_FUNCTION void
358 0 : operation::dump () const
359 : {
360 0 : tree_dump_pretty_printer pp (stderr);
361 0 : print_as_edge_label (&pp, false);
362 0 : pp_newline (&pp);
363 0 : }
364 :
365 : void
366 251575 : operation::handle_on_stmt_for_state_machines (operation_context &op_ctxt,
367 : program_state &dst_state,
368 : path_context *path_ctxt,
369 : bool &unknown_side_effects,
370 : const gimple &stmt)
371 : {
372 251575 : const program_state &old_state = op_ctxt.get_initial_state ();
373 251575 : int sm_idx;
374 251575 : sm_state_map *smap;
375 2011662 : FOR_EACH_VEC_ELT (old_state.m_checker_states, sm_idx, smap)
376 : {
377 1760087 : const state_machine &sm = op_ctxt.m_eg.get_ext_state ().get_sm (sm_idx);
378 1760087 : const sm_state_map *old_smap
379 1760087 : = old_state.m_checker_states[sm_idx];
380 1760087 : sm_state_map *new_smap = dst_state.m_checker_states[sm_idx];
381 1760087 : impl_sm_context sm_ctxt (op_ctxt.m_eg, sm_idx, sm,
382 1760087 : &op_ctxt.m_src_enode,
383 : &old_state,
384 : &dst_state,
385 : old_smap, new_smap, path_ctxt,
386 1760087 : unknown_side_effects);
387 :
388 : /* Allow the state_machine to handle the stmt. */
389 1760087 : if (sm.on_stmt (sm_ctxt, &stmt))
390 22109 : unknown_side_effects = false;
391 1760087 : }
392 251575 : }
393 :
394 : void
395 109672 : gimple_stmt_op::
396 : walk_load_store_addr_ops (void *data,
397 : walk_stmt_load_store_addr_fn load_cb,
398 : walk_stmt_load_store_addr_fn store_cb,
399 : walk_stmt_load_store_addr_fn addr_cb) const
400 : {
401 109672 : walk_stmt_load_store_addr_ops (const_cast<gimple *>(&m_stmt), data,
402 : load_cb, store_cb, addr_cb);
403 109672 : }
404 :
405 : void
406 156578 : gimple_stmt_op::execute (operation_context &op_ctxt) const
407 : {
408 156578 : auto logger = op_ctxt.get_logger ();
409 156578 : LOG_SCOPE (logger);
410 156578 : if (logger)
411 : {
412 94 : logger->start_log_line ();
413 94 : pp_gimple_stmt_1 (logger->get_printer (), &get_stmt (), 0,
414 : (dump_flags_t)0);
415 94 : logger->end_log_line ();
416 : }
417 156578 : execute_on_state (op_ctxt,
418 : /* Pass in a copy. */
419 : op_ctxt.get_initial_state ());
420 156578 : }
421 :
422 : void
423 206463 : gimple_stmt_op::execute_on_state (operation_context &op_ctxt,
424 : program_state dst_state) const
425 : {
426 206463 : auto logger = op_ctxt.get_logger ();
427 206463 : LOG_SCOPE (logger);
428 :
429 206463 : auto dst_point (op_ctxt.get_next_intraprocedural_point ());
430 206463 : const program_state &old_state = op_ctxt.get_initial_state ();
431 :
432 206463 : bool unknown_side_effects = false;
433 206463 : bool could_have_done_work = false;
434 :
435 206463 : impl_path_context path_ctxt (&dst_state, logger);
436 206463 : uncertainty_t uncertainty;
437 206463 : impl_region_model_context ctxt (op_ctxt.m_eg,
438 206463 : &op_ctxt.m_src_enode,
439 : &old_state,
440 : &dst_state,
441 : &uncertainty,
442 : &path_ctxt,
443 206463 : &m_stmt,
444 206463 : &could_have_done_work);
445 :
446 206463 : dst_state.m_region_model->on_stmt_pre (&get_stmt (),
447 : &unknown_side_effects,
448 : &ctxt);
449 :
450 206463 : handle_on_stmt_for_state_machines (op_ctxt,
451 : dst_state,
452 : &path_ctxt,
453 : unknown_side_effects,
454 : m_stmt);
455 :
456 206463 : if (path_ctxt.terminate_path_p ())
457 740 : return;
458 :
459 205723 : if (const gcall *call = dyn_cast <const gcall *> (&m_stmt))
460 49619 : dst_state.m_region_model->on_call_post (*call, unknown_side_effects, &ctxt);
461 :
462 205723 : if (!path_ctxt.terminate_path_p ())
463 204444 : op_ctxt.add_outcome (dst_point, dst_state, could_have_done_work,
464 : &uncertainty);
465 :
466 : /* If we have custom edge infos, "bifurcate" the state
467 : accordingly, potentially creating a new state/enode/eedge
468 : instances. For example, to handle a "realloc" call, we
469 : might split into 3 states, for the "failure",
470 : "resizing in place", and "moving to a new buffer" cases. */
471 227596 : for (auto edge_info_iter : path_ctxt.get_custom_eedge_infos ())
472 : {
473 : /* Take ownership of the edge infos from the path_ctxt. */
474 8453 : std::unique_ptr<custom_edge_info> edge_info (edge_info_iter);
475 8453 : if (logger)
476 : {
477 0 : logger->start_log_line ();
478 0 : logger->log_partial ("bifurcating for edge: ");
479 0 : edge_info->print (logger->get_printer ());
480 0 : logger->end_log_line ();
481 : }
482 8453 : program_state bifurcated_new_state
483 8453 : (path_ctxt.get_state_at_bifurcation ());
484 :
485 : /* Apply edge_info to state. */
486 8453 : impl_region_model_context
487 : bifurcation_ctxt (op_ctxt.m_eg,
488 8453 : &op_ctxt.m_src_enode,
489 8453 : &path_ctxt.get_state_at_bifurcation (),
490 : &bifurcated_new_state,
491 : nullptr, // uncertainty_t *uncertainty
492 : nullptr, // path_context *path_ctxt
493 8453 : &m_stmt);
494 8453 : if (edge_info->update_state (&bifurcated_new_state,
495 : nullptr, /* no exploded_edge yet. */
496 : &bifurcation_ctxt))
497 : {
498 8104 : if (exploded_node *next2
499 8104 : = edge_info->create_enode
500 8104 : (op_ctxt.m_eg,
501 : dst_point,
502 : std::move (bifurcated_new_state),
503 8104 : &op_ctxt.m_src_enode,
504 : &bifurcation_ctxt))
505 : {
506 7675 : op_ctxt.m_eg.add_edge (&op_ctxt.m_src_enode, next2, nullptr,
507 : true /* assume that work could be done */,
508 : std::move (edge_info));
509 : }
510 : }
511 8453 : }
512 412926 : }
513 :
514 : bool
515 127238 : gimple_stmt_op::
516 : execute_for_feasibility (const exploded_edge &,
517 : feasibility_state &fstate,
518 : region_model_context *ctxt,
519 : std::unique_ptr<rejected_constraint> */*out_rc*/) const
520 : {
521 127238 : region_model &model = fstate.get_model ();
522 127238 : bool unknown_side_effects;
523 127238 : model.on_stmt_pre (&m_stmt, &unknown_side_effects, ctxt);
524 :
525 127238 : if (const gcall *call = dyn_cast <const gcall *> (&m_stmt))
526 27131 : model.on_call_post (*call, unknown_side_effects, ctxt);
527 :
528 127238 : return true;
529 : }
530 :
531 : /* An sm_context for adding state_change_event on assignments to NULL,
532 : where the default state isn't m_start. Storing such state in the
533 : sm_state_map would lead to bloat of the exploded_graph, so we want
534 : to leave it as a default state, and inject state change events here
535 : when we have a diagnostic.
536 : Find transitions of constants, for handling on_zero_assignment. */
537 :
538 96357 : struct null_assignment_sm_context : public sm_context
539 : {
540 96357 : null_assignment_sm_context (int sm_idx,
541 : const state_machine &sm,
542 : const program_state *old_state,
543 : const program_state *new_state,
544 : const gimple *stmt,
545 : const program_point *point,
546 : checker_path *emission_path,
547 : const extrinsic_state &ext_state)
548 96357 : : sm_context (sm_idx, sm), m_old_state (old_state), m_new_state (new_state),
549 96357 : m_stmt (stmt), m_point (point), m_emission_path (emission_path),
550 96357 : m_ext_state (ext_state)
551 : {
552 : }
553 :
554 0 : tree get_fndecl_for_call (const gcall &/*call*/) final override
555 : {
556 0 : return NULL_TREE;
557 : }
558 :
559 4468 : state_machine::state_t get_state (tree var) final override
560 : {
561 4468 : const svalue *var_old_sval
562 4468 : = m_old_state->m_region_model->get_rvalue (var, nullptr);
563 4468 : const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx];
564 :
565 4468 : state_machine::state_t current
566 4468 : = old_smap->get_state (var_old_sval, m_ext_state);
567 :
568 4468 : return current;
569 : }
570 :
571 5 : state_machine::state_t get_state (const svalue *sval) final override
572 : {
573 5 : const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx];
574 5 : state_machine::state_t current = old_smap->get_state (sval, m_ext_state);
575 5 : return current;
576 : }
577 :
578 1331 : void set_next_state (tree var,
579 : state_machine::state_t to,
580 : tree origin ATTRIBUTE_UNUSED) final override
581 : {
582 1331 : state_machine::state_t from = get_state (var);
583 1331 : if (from != m_sm.get_start_state ())
584 906 : return;
585 1216 : if (!is_transition_to_null (to))
586 : return;
587 :
588 425 : const svalue *var_new_sval
589 425 : = m_new_state->m_region_model->get_rvalue (var, nullptr);
590 :
591 425 : m_emission_path->add_event
592 425 : (std::make_unique<state_change_event> (event_loc_info (*m_point),
593 425 : m_stmt,
594 : m_sm,
595 : var_new_sval,
596 : from, to,
597 850 : nullptr,
598 425 : *m_new_state,
599 850 : nullptr));
600 : }
601 :
602 0 : void set_next_state (const svalue *sval,
603 : state_machine::state_t to,
604 : tree origin ATTRIBUTE_UNUSED) final override
605 : {
606 0 : state_machine::state_t from = get_state (sval);
607 0 : if (from != m_sm.get_start_state ())
608 0 : return;
609 0 : if (!is_transition_to_null (to))
610 : return;
611 :
612 0 : m_emission_path->add_event
613 0 : (std::make_unique<state_change_event> (event_loc_info (*m_point),
614 0 : m_stmt,
615 : m_sm,
616 : sval,
617 : from, to,
618 0 : nullptr,
619 0 : *m_new_state,
620 0 : nullptr));
621 : }
622 :
623 115 : void warn (tree, std::unique_ptr<pending_diagnostic>) final override
624 : {
625 115 : }
626 0 : void warn (const svalue *, std::unique_ptr<pending_diagnostic>) final override
627 : {
628 0 : }
629 :
630 115 : tree get_diagnostic_tree (tree expr) final override
631 : {
632 115 : return expr;
633 : }
634 :
635 0 : tree get_diagnostic_tree (const svalue *sval) final override
636 : {
637 0 : return m_new_state->m_region_model->get_representative_tree (sval);
638 : }
639 :
640 13756 : state_machine::state_t get_global_state () const final override
641 : {
642 13756 : return 0;
643 : }
644 :
645 0 : void set_global_state (state_machine::state_t) final override
646 : {
647 : /* No-op. */
648 0 : }
649 :
650 0 : void clear_all_per_svalue_state () final override
651 : {
652 : /* No-op. */
653 0 : }
654 :
655 0 : void on_custom_transition (custom_transition *) final override
656 : {
657 0 : }
658 :
659 13803 : tree is_zero_assignment (const gimple *stmt) final override
660 : {
661 26277 : const gassign *assign_stmt = dyn_cast <const gassign *> (stmt);
662 13803 : if (!assign_stmt)
663 : return NULL_TREE;
664 27606 : if (const svalue *sval
665 13803 : = m_new_state->m_region_model->get_gassign_result (assign_stmt, nullptr))
666 13315 : if (tree cst = sval->maybe_get_constant ())
667 2524 : if (::zerop(cst))
668 1329 : return gimple_assign_lhs (assign_stmt);
669 : return NULL_TREE;
670 : }
671 :
672 1276 : const program_state *get_old_program_state () const final override
673 : {
674 1276 : return m_old_state;
675 : }
676 0 : const program_state *get_new_program_state () const final override
677 : {
678 0 : return m_new_state;
679 : }
680 :
681 0 : location_t get_emission_location () const final override
682 : {
683 0 : return UNKNOWN_LOCATION;
684 : }
685 :
686 : /* We only care about transitions to the "null" state
687 : within sm-malloc. Special-case this. */
688 1216 : static bool is_transition_to_null (state_machine::state_t s)
689 : {
690 1216 : return !strcmp (s->get_name (), "null");
691 : }
692 :
693 : const program_state *m_old_state;
694 : const program_state *m_new_state;
695 : const gimple *m_stmt;
696 : const program_point *m_point;
697 : checker_path *m_emission_path;
698 : const extrinsic_state &m_ext_state;
699 : };
700 :
701 : void
702 13944 : gimple_stmt_op::add_any_events_for_eedge (const exploded_edge &eedge,
703 : checker_path &out_path) const
704 : {
705 13944 : out_path.add_event
706 13944 : (std::make_unique<statement_event> (&get_stmt (),
707 13944 : eedge.m_dest->get_function ()->decl,
708 27888 : eedge.m_dest->get_stack_depth (),
709 13944 : eedge.m_dest->get_state ()));
710 :
711 : /* Create state change events for assignment to NULL.
712 : Iterate through the stmts in dst_enode, adding state change
713 : events for them. */
714 13944 : if (const gassign *assign = dyn_cast<const gassign *> (&m_stmt))
715 : {
716 13821 : const program_point &src_point = eedge.m_src->get_point ();
717 13821 : const extrinsic_state &ext_state = out_path.get_ext_state ();
718 110178 : for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
719 : {
720 96357 : const state_machine &sm = ext_state.get_sm (i);
721 96357 : null_assignment_sm_context sm_ctxt (i, sm,
722 96357 : &eedge.m_src->get_state (),
723 96357 : &eedge.m_dest->get_state (),
724 : assign,
725 : &src_point,
726 : &out_path,
727 96357 : ext_state);
728 96357 : sm.on_stmt (sm_ctxt, assign);
729 : // TODO: what about phi nodes?
730 96357 : }
731 : }
732 13944 : }
733 :
734 : // class gasm_op : public gimple_stmt_op
735 :
736 : // class gassign_op : public gimple_stmt_op
737 :
738 : bool
739 10987 : gassign_op::try_to_rewind_data_flow (rewind_context &ctxt) const
740 : {
741 10987 : auto logger = ctxt.m_logger;
742 10987 : LOG_SCOPE (logger);
743 10987 : if (logger)
744 : {
745 5 : logger->start_log_line ();
746 5 : pp_gimple_stmt_1 (logger->get_printer (), &get_stmt (), 0,
747 : (dump_flags_t)0);
748 5 : logger->end_log_line ();
749 : }
750 :
751 10987 : const gassign &assign = get_gassign ();
752 10987 : tree lhs = gimple_assign_lhs (&assign);
753 :
754 10987 : if (!ctxt.could_be_affected_by_write_p (lhs))
755 : return true;
756 :
757 270 : tree rhs1 = gimple_assign_rhs1 (&assign);
758 270 : enum tree_code op = gimple_assign_rhs_code (&assign);
759 :
760 270 : switch (op)
761 : {
762 : default:
763 : return false;
764 :
765 105 : case NOP_EXPR:
766 105 : case SSA_NAME:
767 105 : case VAR_DECL:
768 105 : case PARM_DECL:
769 105 : case COMPONENT_REF:
770 105 : ctxt.on_data_flow (rhs1, lhs);
771 105 : break;
772 :
773 67 : case INTEGER_CST:
774 67 : case REAL_CST:
775 67 : if (logger)
776 1 : logger->log ("value comes from here");
777 67 : ctxt.on_data_origin (lhs);
778 67 : break;
779 : }
780 :
781 : return true;
782 10987 : }
783 :
784 : // class predict_op : public gimple_stmt_op
785 :
786 : // class greturn_op : public gimple_stmt_op
787 :
788 : void
789 17386 : greturn_op::execute (operation_context &op_ctxt) const
790 : {
791 17386 : auto logger = op_ctxt.get_logger ();
792 :
793 17386 : auto dst_point (op_ctxt.get_next_intraprocedural_point ());
794 17386 : const program_state &old_state = op_ctxt.get_initial_state ();
795 17386 : program_state dst_state (old_state);
796 :
797 17386 : impl_path_context path_ctxt (&dst_state, logger);
798 17386 : uncertainty_t uncertainty;
799 17386 : impl_region_model_context ctxt (op_ctxt.m_eg,
800 17386 : &op_ctxt.m_src_enode,
801 :
802 : /* TODO: should we be getting the ECs from the
803 : old state, rather than the new? */
804 17386 : &op_ctxt.get_initial_state (),
805 : &dst_state,
806 : &uncertainty,
807 : &path_ctxt,
808 : nullptr,
809 17386 : nullptr);
810 :
811 17386 : tree callee = op_ctxt.get_initial_point ().get_function ()->decl;
812 17386 : tree lhs = DECL_RESULT (callee);
813 :
814 34772 : if (lhs && get_retval ())
815 : {
816 8770 : region_model *dst_region_model = dst_state.m_region_model;
817 8770 : const svalue *sval
818 8770 : = dst_region_model->get_rvalue (get_retval (), &ctxt);
819 8770 : const region *ret_reg = dst_region_model->get_lvalue (lhs, &ctxt);
820 8770 : dst_region_model->set_value (ret_reg, sval, &ctxt);
821 : }
822 :
823 17386 : if (!path_ctxt.terminate_path_p ())
824 17371 : op_ctxt.add_outcome (dst_point, dst_state, false, &uncertainty);
825 34772 : }
826 :
827 : bool
828 4737 : greturn_op::
829 : execute_for_feasibility (const exploded_edge &eedge,
830 : feasibility_state &fstate,
831 : region_model_context *ctxt,
832 : std::unique_ptr<rejected_constraint> *) const
833 : {
834 4737 : tree callee = eedge.m_src->get_function ()->decl;
835 4737 : tree lhs = DECL_RESULT (callee);
836 :
837 9474 : if (lhs && get_retval ())
838 : {
839 1946 : region_model &model = fstate.get_model ();
840 1946 : const svalue *sval = model.get_rvalue (get_retval (), ctxt);
841 1946 : const region *ret_reg = model.get_lvalue (lhs, ctxt);
842 1946 : model.set_value (ret_reg, sval, ctxt);
843 : }
844 :
845 4737 : return true;
846 : }
847 :
848 : void
849 1008 : greturn_op::add_any_events_for_eedge (const exploded_edge &,
850 : checker_path &) const
851 : {
852 : // No-op.
853 1008 : }
854 :
855 :
856 : bool
857 942 : greturn_op::try_to_rewind_data_flow (rewind_context &ctxt) const
858 : {
859 942 : auto logger = ctxt.m_logger;
860 942 : LOG_SCOPE (logger);
861 :
862 942 : if (get_retval ())
863 : {
864 436 : const region_model &src_enode_model = ctxt.get_src_region_model ();
865 436 : tree fndecl = src_enode_model.get_current_function ()->decl;
866 436 : ctxt.on_data_flow (get_retval (), DECL_RESULT (fndecl));
867 : }
868 :
869 1884 : return true;
870 942 : }
871 :
872 : // class call_and_return_op : public gimple_stmt_op
873 :
874 : std::unique_ptr<operation>
875 42136 : call_and_return_op::make (const gcall &call_stmt)
876 : {
877 42136 : if (is_special_named_call_p (call_stmt, "__analyzer_dump", 0))
878 0 : return std::make_unique<dump_op> (call_stmt, dump_op::dump_kind::state);
879 42136 : else if (is_special_named_call_p (call_stmt, "__analyzer_dump_sarif", 0))
880 0 : return std::make_unique<dump_op> (call_stmt, dump_op::dump_kind::sarif);
881 42136 : else if (is_special_named_call_p (call_stmt, "__analyzer_dump_dot", 0))
882 0 : return std::make_unique<dump_op> (call_stmt, dump_op::dump_kind::dot);
883 42136 : else if (is_special_named_call_p (call_stmt, "__analyzer_dump_state", 2))
884 309 : return std::make_unique<dump_op> (call_stmt, dump_op::dump_kind::state_2);
885 41827 : else if (is_setjmp_call_p (call_stmt))
886 29 : return std::make_unique<setjmp_op> (call_stmt);
887 41798 : else if (is_longjmp_call_p (call_stmt))
888 41 : return std::make_unique<longjmp_op> (call_stmt);
889 41757 : else if (is_cxa_throw_p (call_stmt))
890 73 : return std::make_unique<cxa_throw_op> (call_stmt, false);
891 41684 : else if (is_cxa_rethrow_p (call_stmt))
892 39 : return std::make_unique<cxa_throw_op> (call_stmt, true);
893 :
894 41645 : return std::make_unique<call_and_return_op> (call_stmt);
895 : }
896 :
897 : /* Resolve a function call by one of:
898 :
899 : (a) using a call summary to add eedges to new enodes capturing
900 : the states after summarized outcomes of the call
901 :
902 : (b) adding an interprocedural_call edge, effectively "stepping into"
903 : the called function, for detailed analysis of that path
904 :
905 : (c) simulating the effect of the call, adding an eedge to a new
906 : enode for the outcome of the call. */
907 :
908 : void
909 57464 : call_and_return_op::execute (operation_context &op_ctxt) const
910 : {
911 : /* Can we turn this into an interprocedural call, and execute within
912 : the called fuction? */
913 57464 : const program_state &old_state = op_ctxt.get_initial_state ();
914 57464 : program_state dst_state (old_state);
915 57464 : op_region_model_context ctxt (op_ctxt, dst_state);
916 57464 : ctxt.m_stmt = &get_gcall ();
917 57464 : call_details cd (get_gcall (), old_state.m_region_model, &ctxt);
918 :
919 : /* Regardless of how we handle the call, check any known
920 : preconditions. */
921 57464 : {
922 : /* Check for any preconditions if it's a known_function. */
923 57464 : if (auto kf = maybe_get_known_function (cd))
924 33590 : kf->check_any_preconditions (cd);
925 :
926 : /* Check for any preconditions using sm-state. */
927 : {
928 : int sm_idx;
929 : sm_state_map *smap;
930 459349 : FOR_EACH_VEC_ELT (old_state.m_checker_states, sm_idx, smap)
931 : {
932 401885 : const state_machine &sm
933 401885 : = op_ctxt.m_eg.get_ext_state ().get_sm (sm_idx);
934 401885 : const sm_state_map *old_smap
935 401885 : = old_state.m_checker_states[sm_idx];
936 401885 : sm_state_map *new_smap = dst_state.m_checker_states[sm_idx];
937 401885 : impl_sm_context sm_ctxt (op_ctxt.m_eg, sm_idx, sm,
938 401885 : &op_ctxt.m_src_enode,
939 : &old_state, &dst_state,
940 401885 : old_smap, new_smap, nullptr);
941 401885 : sm.check_call_preconditions (sm_ctxt, cd);
942 401885 : }
943 : }
944 : }
945 :
946 57464 : if (tree callee_fndecl = cd.get_fndecl_for_call ())
947 : {
948 : // Consider using a call summary
949 53663 : if (function *called_fn = DECL_STRUCT_FUNCTION (callee_fndecl))
950 7579 : if (cgraph_edge *edge = get_any_cgraph_edge (op_ctxt))
951 7579 : if (op_ctxt.m_eg.get_analysis_plan ().use_summary_p (edge))
952 : {
953 787 : per_function_data *called_fn_data
954 787 : = op_ctxt.m_eg.get_per_function_data (called_fn);
955 787 : if (called_fn_data)
956 : {
957 749 : replay_call_summaries (op_ctxt, *called_fn,
958 : *called_fn_data, &ctxt);
959 749 : return;
960 : }
961 : }
962 :
963 : // Do we have an entry snode for this fndecl?
964 52914 : if (auto callee_fun = DECL_STRUCT_FUNCTION (callee_fndecl))
965 13660 : if (supernode *callee_entry_snode
966 6830 : = (op_ctxt.get_supergraph ()
967 6830 : .get_node_for_function_entry (*callee_fun)))
968 : {
969 6830 : const call_string *dst_call_string
970 6830 : (op_ctxt.m_src_enode
971 6830 : .get_point ()
972 6830 : .get_call_string ()
973 6830 : .push_call (op_ctxt.m_sedge, *this, *callee_fun));
974 6830 : const program_point dst_point
975 6830 : (callee_entry_snode, *dst_call_string);
976 6830 : auto edge_info
977 : = std::make_unique<interprocedural_call> (*this,
978 6830 : *callee_fun);
979 6830 : edge_info->update_state (&dst_state, nullptr, &ctxt);
980 6830 : op_ctxt.add_outcome (dst_point, dst_state, false, nullptr,
981 13660 : std::move (edge_info));
982 6830 : return;
983 6830 : }
984 : }
985 :
986 : /* Resolve intraprocedurally: execute the gcall, but using the
987 : dst_state from above so that any preconditions have been applied. */
988 49885 : gimple_stmt_op::execute_on_state (op_ctxt, std::move (dst_state));
989 57464 : }
990 :
991 : cgraph_edge *
992 7579 : call_and_return_op::get_any_cgraph_edge (operation_context &op_ctxt) const
993 : {
994 7579 : tree caller_fndecl = op_ctxt.get_initial_point ().get_fndecl ();
995 7579 : gcc_assert (caller_fndecl);
996 :
997 7579 : auto caller_cgnode = cgraph_node::get (caller_fndecl);
998 7579 : gcc_assert (caller_cgnode);
999 7579 : return caller_cgnode->get_edge (const_cast<gcall *> (&get_gcall ()));
1000 : }
1001 :
1002 : void
1003 7376 : call_and_return_op::
1004 : add_any_events_for_eedge (const exploded_edge &,
1005 : checker_path &) const
1006 : {
1007 7376 : }
1008 :
1009 : /* Given PARM_TO_FIND, a PARM_DECL, identify its index (writing it
1010 : to *OUT if OUT is non-NULL), and return the corresponding argument
1011 : at the callsite. */
1012 :
1013 : tree
1014 278 : call_and_return_op::get_arg_for_parm (tree callee_fndecl,
1015 : tree parm_to_find,
1016 : callsite_expr *out) const
1017 : {
1018 278 : gcc_assert (TREE_CODE (parm_to_find) == PARM_DECL);
1019 :
1020 278 : const gcall &call_stmt = get_gcall ();
1021 :
1022 278 : unsigned i = 0;
1023 319 : for (tree iter_parm = DECL_ARGUMENTS (callee_fndecl); iter_parm;
1024 41 : iter_parm = DECL_CHAIN (iter_parm), ++i)
1025 : {
1026 281 : if (i >= gimple_call_num_args (&call_stmt))
1027 : return NULL_TREE;
1028 281 : if (iter_parm == parm_to_find)
1029 : {
1030 240 : if (out)
1031 240 : *out = callsite_expr::from_zero_based_param (i);
1032 240 : return gimple_call_arg (&call_stmt, i);
1033 : }
1034 : }
1035 :
1036 : /* Not found. */
1037 : return NULL_TREE;
1038 : }
1039 :
1040 : /* Look for a use of ARG_TO_FIND as an argument at this callsite.
1041 : If found, return the default SSA def of the corresponding parm within
1042 : the callee, and if OUT is non-NULL, write the index to *OUT.
1043 : Only the first match is handled. */
1044 :
1045 : tree
1046 443 : call_and_return_op::get_parm_for_arg (tree callee_fndecl,
1047 : tree arg_to_find,
1048 : callsite_expr *out) const
1049 : {
1050 443 : const gcall &call_stmt = get_gcall ();
1051 :
1052 443 : unsigned i = 0;
1053 735 : for (tree iter_parm = DECL_ARGUMENTS (callee_fndecl); iter_parm;
1054 292 : iter_parm = DECL_CHAIN (iter_parm), ++i)
1055 : {
1056 388 : if (i >= gimple_call_num_args (&call_stmt))
1057 : return NULL_TREE;
1058 387 : tree param = gimple_call_arg (&call_stmt, i);
1059 387 : if (arg_to_find == param)
1060 : {
1061 95 : if (out)
1062 95 : *out = callsite_expr::from_zero_based_param (i);
1063 95 : return ssa_default_def (DECL_STRUCT_FUNCTION (callee_fndecl),
1064 95 : iter_parm);
1065 : }
1066 : }
1067 :
1068 : /* Not found. */
1069 : return NULL_TREE;
1070 : }
1071 :
1072 : /* Map caller_expr back to an expr within the callee, or return NULL_TREE.
1073 : If non-NULL is returned, populate OUT. */
1074 :
1075 : tree
1076 443 : call_and_return_op::map_expr_from_caller_to_callee (tree callee_fndecl,
1077 : tree caller_expr,
1078 : callsite_expr *out) const
1079 : {
1080 : /* Is it an argument (actual param)? If so, convert to
1081 : parameter (formal param). */
1082 443 : tree parm = get_parm_for_arg (callee_fndecl, caller_expr, out);
1083 443 : if (parm)
1084 : return parm;
1085 : /* Otherwise try return value. */
1086 352 : if (caller_expr == gimple_call_lhs (&get_gcall ()))
1087 : {
1088 94 : if (out)
1089 94 : *out = callsite_expr::from_return_value ();
1090 94 : return DECL_RESULT (callee_fndecl);
1091 : }
1092 :
1093 : return NULL_TREE;
1094 : }
1095 :
1096 : /* Map callee_expr back to an expr within the caller, or return NULL_TREE.
1097 : If non-NULL is returned, populate OUT. */
1098 :
1099 : tree
1100 1293 : call_and_return_op::map_expr_from_callee_to_caller (tree callee_fndecl,
1101 : tree callee_expr,
1102 : callsite_expr *out) const
1103 : {
1104 1293 : if (callee_expr == NULL_TREE)
1105 : return NULL_TREE;
1106 :
1107 : /* If it's a parameter (formal param), get the argument (actual param). */
1108 448 : if (TREE_CODE (callee_expr) == PARM_DECL)
1109 7 : return get_arg_for_parm (callee_fndecl, callee_expr, out);
1110 :
1111 : /* Similar for the default SSA name of the PARM_DECL. */
1112 441 : if (TREE_CODE (callee_expr) == SSA_NAME
1113 306 : && SSA_NAME_IS_DEFAULT_DEF (callee_expr)
1114 712 : && TREE_CODE (SSA_NAME_VAR (callee_expr)) == PARM_DECL)
1115 271 : return get_arg_for_parm (callee_fndecl, SSA_NAME_VAR (callee_expr), out);
1116 :
1117 : /* Otherwise try return value. */
1118 170 : if (callee_expr == DECL_RESULT (callee_fndecl))
1119 : {
1120 1 : if (out)
1121 1 : *out = callsite_expr::from_return_value ();
1122 1 : return gimple_call_lhs (&get_gcall ());
1123 : }
1124 :
1125 : return NULL_TREE;
1126 : }
1127 :
1128 : const known_function *
1129 57464 : call_and_return_op::maybe_get_known_function (const call_details &cd) const
1130 : {
1131 57464 : region_model_manager *mgr = cd.get_manager ();
1132 57464 : known_function_manager *known_fn_mgr = mgr->get_known_function_manager ();
1133 :
1134 57464 : if (gimple_call_internal_p (&get_gcall ()))
1135 3431 : return known_fn_mgr->get_internal_fn
1136 3431 : (gimple_call_internal_fn (&get_gcall ()));
1137 :
1138 54033 : if (tree callee_fndecl = cd.get_fndecl_for_call ())
1139 53663 : return known_fn_mgr->get_match (callee_fndecl, cd);
1140 :
1141 : return nullptr;
1142 : }
1143 :
1144 : void
1145 749 : call_and_return_op::
1146 : replay_call_summaries (operation_context &op_ctxt,
1147 : function &called_fn,
1148 : per_function_data &called_fn_data,
1149 : region_model_context *ctxt) const
1150 : {
1151 749 : logger *logger = op_ctxt.get_logger ();
1152 749 : LOG_SCOPE (logger);
1153 :
1154 3782 : for (auto summary : called_fn_data.m_summaries)
1155 : {
1156 1535 : gcc_assert (summary);
1157 1535 : replay_call_summary (op_ctxt, called_fn, *summary, ctxt);
1158 : }
1159 749 : }
1160 :
1161 : bool
1162 5109 : call_and_return_op::try_to_rewind_data_flow (rewind_context &ctxt) const
1163 : {
1164 5109 : LOG_SCOPE (ctxt.m_logger);
1165 10218 : return true;
1166 5109 : }
1167 :
1168 : /* A concrete call_info subclass representing a replay of a call summary. */
1169 :
1170 : class call_summary_edge_info : public call_info
1171 : {
1172 : public:
1173 1414 : call_summary_edge_info (const call_details &cd,
1174 : const function &called_fn,
1175 : call_summary &summary,
1176 : const extrinsic_state &ext_state)
1177 1414 : : call_info (cd, called_fn),
1178 1414 : m_called_fn (called_fn),
1179 1414 : m_summary (summary),
1180 1414 : m_ext_state (ext_state)
1181 : {}
1182 :
1183 0 : bool update_state (program_state *state,
1184 : const exploded_edge *,
1185 : region_model_context *ctxt) const final override
1186 : {
1187 : /* Update STATE based on summary_end_state. */
1188 0 : call_details cd (get_call_details (state->m_region_model, ctxt));
1189 0 : call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state);
1190 0 : const program_state &summary_end_state = m_summary.get_state ();
1191 0 : return state->replay_call_summary (r, summary_end_state);
1192 0 : }
1193 :
1194 123 : bool update_model (region_model *model,
1195 : const exploded_edge *,
1196 : region_model_context *ctxt) const final override
1197 : {
1198 : /* Update STATE based on summary_end_state. */
1199 123 : call_details cd (get_call_details (model, ctxt));
1200 123 : call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state);
1201 123 : const program_state &summary_end_state = m_summary.get_state ();
1202 123 : model->replay_call_summary (r, *summary_end_state.m_region_model);
1203 123 : return true;
1204 123 : }
1205 :
1206 62 : void print_desc (pretty_printer &pp) const final override
1207 : {
1208 62 : pp_string (&pp, m_summary.get_desc ().get ());
1209 62 : }
1210 :
1211 : private:
1212 : const function &m_called_fn;
1213 : call_summary &m_summary;
1214 : const extrinsic_state &m_ext_state;
1215 : };
1216 :
1217 : void
1218 1535 : call_and_return_op::
1219 : replay_call_summary (operation_context &op_ctxt,
1220 : function &called_fn,
1221 : call_summary &summary,
1222 : region_model_context *ctxt) const
1223 : {
1224 1535 : logger *logger = op_ctxt.get_logger ();
1225 1535 : LOG_SCOPE (logger);
1226 1535 : if (logger)
1227 0 : logger->log ("using %s as summary for call to %qE from %qE",
1228 0 : summary.get_desc ().get (),
1229 : called_fn.decl,
1230 0 : op_ctxt.get_initial_point ().get_function ()->decl);
1231 1535 : const extrinsic_state &ext_state = op_ctxt.get_ext_state ();
1232 1535 : const program_state &old_state = op_ctxt.get_initial_state ();
1233 1535 : const program_state &summary_end_state = summary.get_state ();
1234 1535 : if (logger)
1235 : {
1236 0 : pretty_printer *pp = logger->get_printer ();
1237 :
1238 0 : logger->start_log_line ();
1239 0 : pp_string (pp, "callsite state: ");
1240 0 : old_state.dump_to_pp (ext_state, true, false, pp);
1241 0 : logger->end_log_line ();
1242 :
1243 0 : logger->start_log_line ();
1244 0 : pp_string (pp, "summary end state: ");
1245 0 : summary_end_state.dump_to_pp (ext_state, true, false, pp);
1246 0 : logger->end_log_line ();
1247 : }
1248 :
1249 1535 : program_state new_state (old_state);
1250 :
1251 1535 : call_details cd (get_gcall (), new_state.m_region_model, ctxt);
1252 1535 : call_summary_replay r (cd, called_fn, summary, ext_state);
1253 :
1254 1535 : if (new_state.replay_call_summary (r, summary_end_state))
1255 1414 : op_ctxt.add_outcome
1256 1414 : (op_ctxt.get_next_intraprocedural_point (),
1257 : new_state,
1258 : true,
1259 : nullptr,
1260 2828 : std::make_unique<call_summary_edge_info> (cd,
1261 : called_fn,
1262 : summary,
1263 : ext_state));
1264 1535 : }
1265 :
1266 : // class dump_op : public call_and_return_op
1267 :
1268 : void
1269 357 : dump_op::execute (operation_context &op_ctxt) const
1270 : {
1271 357 : const program_state &state = op_ctxt.get_initial_state ();
1272 357 : switch (m_dump_kind)
1273 : {
1274 0 : default:
1275 0 : gcc_unreachable ();
1276 0 : case dump_kind::state:
1277 : /* Handle the builtin "__analyzer_dump" by dumping state
1278 : to stderr. */
1279 0 : state.dump (op_ctxt.get_ext_state (), true);
1280 0 : break;
1281 0 : case dump_kind::sarif:
1282 0 : state.dump_sarif (op_ctxt.get_ext_state ());
1283 0 : break;
1284 0 : case dump_kind::dot:
1285 0 : state.dump_dot (op_ctxt.get_ext_state ());
1286 0 : break;
1287 357 : case dump_kind::state_2:
1288 357 : {
1289 357 : program_state dst_state (state);
1290 357 : op_region_model_context ctxt (op_ctxt, dst_state);
1291 357 : dst_state.impl_call_analyzer_dump_state (get_gcall (),
1292 : op_ctxt.get_ext_state (),
1293 : &ctxt);
1294 357 : }
1295 357 : break;
1296 : }
1297 :
1298 357 : op_ctxt.add_outcome (op_ctxt.get_next_intraprocedural_point (),
1299 : state, false, nullptr);
1300 357 : }
1301 :
1302 : // class setjmp_op : public call_and_return_op
1303 :
1304 : void
1305 34 : setjmp_op::execute (operation_context &op_ctxt) const
1306 : {
1307 34 : program_state dst_state (op_ctxt.get_initial_state ());
1308 34 : op_region_model_context ctxt (op_ctxt, dst_state);
1309 34 : dst_state.m_region_model->on_setjmp (get_gcall (),
1310 34 : op_ctxt.m_src_enode,
1311 : op_ctxt.m_sedge,
1312 : &ctxt);
1313 34 : op_ctxt.add_outcome (op_ctxt.get_next_intraprocedural_point (),
1314 : dst_state, true, nullptr);
1315 34 : }
1316 :
1317 : void
1318 20 : setjmp_op::add_any_events_for_eedge (const exploded_edge &eedge,
1319 : checker_path &out_path) const
1320 : {
1321 20 : out_path.add_event
1322 20 : (std::make_unique<setjmp_event>
1323 40 : (event_loc_info (eedge.m_src),
1324 20 : eedge.m_src,
1325 : get_gcall ()));
1326 20 : }
1327 :
1328 : // class longjmp_op : public call_and_return_op
1329 :
1330 : void
1331 63 : longjmp_op::execute (operation_context &op_ctxt) const
1332 : {
1333 63 : program_state dst_state (op_ctxt.get_initial_state ());
1334 63 : op_region_model_context ctxt (op_ctxt, dst_state);
1335 63 : op_ctxt.m_src_enode.on_longjmp (op_ctxt.m_eg, get_gcall (), &dst_state,
1336 : &ctxt);
1337 63 : }
1338 :
1339 : // class cxa_throw_op : public call_and_return_op
1340 :
1341 : void
1342 190 : cxa_throw_op::execute (operation_context &op_ctxt) const
1343 : {
1344 190 : program_state dst_state (op_ctxt.get_initial_state ());
1345 190 : op_region_model_context ctxt (op_ctxt, dst_state);
1346 190 : program_point after_throw_point (op_ctxt.get_next_intraprocedural_point ());
1347 190 : op_ctxt.m_src_enode.on_throw (op_ctxt.m_eg,
1348 : get_gcall (),
1349 : after_throw_point,
1350 : &dst_state,
1351 190 : m_is_rethrow,
1352 : &ctxt);
1353 : // We don't continue along op_ctxt's superedge
1354 190 : }
1355 :
1356 : // class control_flow_op : public operation
1357 :
1358 : void
1359 18180 : control_flow_op::
1360 : walk_load_store_addr_ops (void *data,
1361 : walk_stmt_load_store_addr_fn load_cb,
1362 : walk_stmt_load_store_addr_fn store_cb,
1363 : walk_stmt_load_store_addr_fn addr_cb) const
1364 : {
1365 18180 : walk_stmt_load_store_addr_ops (const_cast <gimple *> (&m_ctrlflow_stmt),
1366 : data,
1367 : load_cb, store_cb, addr_cb);
1368 18180 : }
1369 :
1370 : void
1371 2690 : control_flow_op::add_any_events_for_eedge (const exploded_edge &eedge,
1372 : checker_path &out_path) const
1373 : {
1374 2690 : out_path.add_event
1375 2690 : (std::make_unique<start_cfg_edge_event> (eedge,
1376 5380 : event_loc_info (eedge.m_src),
1377 2690 : this));
1378 2690 : out_path.add_event
1379 2690 : (std::make_unique<end_cfg_edge_event> (eedge,
1380 5380 : event_loc_info (eedge.m_dest),
1381 2690 : this));
1382 2690 : }
1383 :
1384 : /* Attempt to generate a description of any condition that holds at this edge.
1385 :
1386 : The intent is to make the user-facing messages more clear, especially for
1387 : cases where there's a single or double-negative, such as
1388 : when describing the false branch of an inverted condition.
1389 :
1390 : For example, rather than printing just:
1391 :
1392 : | if (!ptr)
1393 : | ~
1394 : | |
1395 : | (1) following 'false' branch...
1396 :
1397 : it's clearer to spell out the condition that holds:
1398 :
1399 : | if (!ptr)
1400 : | ~
1401 : | |
1402 : | (1) following 'false' branch (when 'ptr' is non-NULL)...
1403 : ^^^^^^^^^^^^^^^^^^^^^^
1404 :
1405 : In the above example, this function would generate the highlighted
1406 : string: "when 'ptr' is non-NULL".
1407 :
1408 : If the edge is not a condition, or it's not clear that a description of
1409 : the condition would be helpful to the user, return NULL. */
1410 :
1411 : label_text
1412 450 : control_flow_op::maybe_describe_condition (bool ) const
1413 : {
1414 450 : return label_text::borrow (nullptr);
1415 : }
1416 :
1417 : void
1418 51985 : control_flow_op::execute (operation_context &op_ctxt) const
1419 : {
1420 51985 : auto logger = op_ctxt.get_logger ();
1421 51985 : LOG_SCOPE (logger);
1422 :
1423 51985 : program_state dst_state (op_ctxt.get_initial_state ());
1424 51985 : op_region_model_context ctxt (op_ctxt, dst_state);
1425 51985 : if (apply_constraints (&op_ctxt.m_sedge,
1426 51985 : *dst_state.m_region_model,
1427 : &ctxt,
1428 : nullptr))
1429 : {
1430 45112 : bool unknown_side_effects;
1431 45112 : handle_on_stmt_for_state_machines (op_ctxt,
1432 : dst_state,
1433 : nullptr,
1434 : unknown_side_effects,
1435 : m_ctrlflow_stmt);
1436 :
1437 45112 : if (!ctxt.terminate_path_p ())
1438 : {
1439 45084 : auto dst_point (op_ctxt.get_next_intraprocedural_point ());
1440 45084 : op_ctxt.add_outcome (dst_point, dst_state, false, nullptr);
1441 : }
1442 : }
1443 51985 : }
1444 :
1445 : bool
1446 32913 : control_flow_op::
1447 : execute_for_feasibility (const exploded_edge &eedge,
1448 : feasibility_state &fstate,
1449 : region_model_context *ctxt,
1450 : std::unique_ptr<rejected_constraint> *out_rc) const
1451 : {
1452 32913 : gcc_assert (eedge.m_sedge);
1453 32913 : return apply_constraints (eedge.m_sedge,
1454 : fstate.get_model (),
1455 : ctxt,
1456 32913 : out_rc);
1457 : }
1458 :
1459 : // class gcond_edge_op : public control_flow_op
1460 :
1461 14986 : gcond_edge_op::gcond_edge_op (::edge cfg_edge,
1462 14986 : const gcond &cond_stmt)
1463 : : control_flow_op (kind::cond_edge, cfg_edge, cond_stmt),
1464 14986 : m_true_value (get_flags () & EDGE_TRUE_VALUE)
1465 : {
1466 : /* Exactly one of EDGE_TRUE_VALUE and EDGE_FALSE_VALUE must
1467 : be set on CFG_EDGE. */
1468 14986 : gcc_assert (static_cast<bool> (get_flags () & EDGE_TRUE_VALUE)
1469 : ^ static_cast<bool> (get_flags () & EDGE_FALSE_VALUE));
1470 14986 : }
1471 :
1472 : void
1473 7154 : gcond_edge_op::print_as_edge_label (pretty_printer *pp,
1474 : bool user_facing) const
1475 : {
1476 7154 : if (!user_facing)
1477 228 : pp_gimple_stmt_1 (pp, &get_ctrlflow_stmt (), 0, (dump_flags_t)0);
1478 :
1479 7154 : if (m_true_value)
1480 3768 : pp_printf (pp, "true");
1481 : else
1482 3386 : pp_printf (pp, "false");
1483 7154 : }
1484 :
1485 : label_text
1486 6926 : gcond_edge_op::maybe_describe_condition (bool can_colorize) const
1487 : {
1488 6926 : const gcond &cond_stmt = get_gcond ();
1489 6926 : enum tree_code op = gimple_cond_code (&cond_stmt);
1490 6926 : tree lhs = gimple_cond_lhs (&cond_stmt);
1491 6926 : tree rhs = gimple_cond_rhs (&cond_stmt);
1492 6926 : if (!m_true_value)
1493 3282 : op = invert_tree_comparison (op, false /* honor_nans */);
1494 6926 : return maybe_describe_condition (can_colorize,
1495 6926 : lhs, op, rhs);
1496 : }
1497 :
1498 : /* Subroutine of gcond_edge_op::maybe_describe_condition above.
1499 :
1500 : Attempt to generate a user-facing description of the condition
1501 : LHS OP RHS, but only if it is likely to make it easier for the
1502 : user to understand a condition. */
1503 :
1504 : label_text
1505 6926 : gcond_edge_op::maybe_describe_condition (bool can_colorize,
1506 : tree lhs,
1507 : enum tree_code op,
1508 : tree rhs)
1509 : {
1510 : /* In theory we could just build a tree via
1511 : fold_build2 (op, boolean_type_node, lhs, rhs)
1512 : and print it with %qE on it, but this leads to warts such as
1513 : parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
1514 :
1515 : /* Special-case: describe testing the result of strcmp, as figuring
1516 : out what the "true" or "false" path is can be confusing to the user. */
1517 6926 : if (TREE_CODE (lhs) == SSA_NAME
1518 6926 : && zerop (rhs))
1519 : {
1520 5313 : if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
1521 1977 : if (is_special_named_call_p (*call, "strcmp", 2))
1522 : {
1523 60 : if (op == EQ_EXPR)
1524 9 : return label_text::borrow ("when the strings are equal");
1525 51 : if (op == NE_EXPR)
1526 51 : return label_text::borrow ("when the strings are non-equal");
1527 : }
1528 : }
1529 :
1530 : /* Only attempt to generate text for sufficiently simple expressions. */
1531 6866 : if (!should_print_expr_p (lhs))
1532 2705 : return label_text::borrow (nullptr);
1533 4161 : if (!should_print_expr_p (rhs))
1534 47 : return label_text::borrow (nullptr);
1535 :
1536 : /* Special cases for pointer comparisons against NULL. */
1537 6600 : if (POINTER_TYPE_P (TREE_TYPE (lhs))
1538 1628 : && POINTER_TYPE_P (TREE_TYPE (rhs))
1539 5742 : && zerop (rhs))
1540 : {
1541 1530 : if (op == EQ_EXPR)
1542 369 : return make_label_text (can_colorize, "when %qE is NULL",
1543 369 : lhs);
1544 1161 : if (op == NE_EXPR)
1545 1161 : return make_label_text (can_colorize, "when %qE is non-NULL",
1546 1161 : lhs);
1547 : }
1548 :
1549 2584 : return make_label_text (can_colorize, "when %<%E %s %E%>",
1550 2584 : lhs, op_symbol_code (op), rhs);
1551 : }
1552 :
1553 : /* Subroutine of maybe_describe_condition.
1554 :
1555 : Return true if EXPR is we will get suitable user-facing output
1556 : from %E on it. */
1557 :
1558 : bool
1559 11027 : gcond_edge_op::should_print_expr_p (tree expr)
1560 : {
1561 15462 : if (TREE_CODE (expr) == SSA_NAME)
1562 : {
1563 7187 : if (SSA_NAME_VAR (expr))
1564 : return should_print_expr_p (SSA_NAME_VAR (expr));
1565 : else
1566 : return false;
1567 : }
1568 :
1569 8275 : if (DECL_P (expr))
1570 : return true;
1571 :
1572 3840 : if (CONSTANT_CLASS_P (expr))
1573 3840 : return true;
1574 :
1575 : return false;
1576 : }
1577 :
1578 : bool
1579 76064 : gcond_edge_op::
1580 : apply_constraints (const superedge *,
1581 : region_model &model,
1582 : region_model_context *ctxt,
1583 : std::unique_ptr<rejected_constraint> *out) const
1584 : {
1585 76064 : const gcond &cond_stmt = get_gcond ();
1586 76064 : enum tree_code op = gimple_cond_code (&cond_stmt);
1587 76064 : tree lhs = gimple_cond_lhs (&cond_stmt);
1588 76064 : tree rhs = gimple_cond_rhs (&cond_stmt);
1589 76064 : if (!m_true_value)
1590 34465 : op = invert_tree_comparison (op, false /* honor_nans */);
1591 76064 : return model.add_constraint (lhs, op, rhs, ctxt, out);
1592 : }
1593 :
1594 : // class ggoto_edge_op : public control_flow_op
1595 :
1596 36 : ggoto_edge_op::ggoto_edge_op (::edge cfg_edge,
1597 : const ggoto &goto_stmt,
1598 36 : tree dst_label)
1599 : : control_flow_op (kind::goto_edge, cfg_edge, goto_stmt),
1600 36 : m_dst_label (dst_label)
1601 : {
1602 36 : }
1603 :
1604 : void
1605 60 : ggoto_edge_op::print_as_edge_label (pretty_printer *pp,
1606 : bool user_facing) const
1607 : {
1608 60 : if (!user_facing)
1609 0 : pp_gimple_stmt_1 (pp, &get_ctrlflow_stmt (), 0, (dump_flags_t)0);
1610 :
1611 60 : if (m_dst_label)
1612 60 : pp_printf (pp, "%qD", m_dst_label);
1613 60 : }
1614 :
1615 : label_text
1616 60 : ggoto_edge_op::maybe_describe_condition (bool) const
1617 : {
1618 60 : return label_text::borrow ("");
1619 : }
1620 :
1621 : bool
1622 122 : ggoto_edge_op::
1623 : apply_constraints (const superedge *,
1624 : region_model &model,
1625 : region_model_context *ctxt,
1626 : std::unique_ptr<rejected_constraint> *out_rc) const
1627 : {
1628 122 : const ggoto &goto_stmt = get_ggoto ();
1629 122 : tree dest = gimple_goto_dest (&goto_stmt);
1630 122 : const svalue *dest_sval = model.get_rvalue (dest, ctxt);
1631 :
1632 : /* If we know we were jumping to a specific label. */
1633 122 : if (m_dst_label)
1634 : {
1635 122 : auto mgr = model.get_manager ();
1636 122 : const label_region *dst_label_reg
1637 122 : = mgr->get_region_for_label (m_dst_label);
1638 122 : const svalue *dst_label_ptr
1639 122 : = mgr->get_ptr_svalue (ptr_type_node, dst_label_reg);
1640 :
1641 122 : if (!model.add_constraint (dest_sval, EQ_EXPR, dst_label_ptr, ctxt))
1642 : {
1643 12 : if (out_rc)
1644 3 : *out_rc
1645 3 : = std::make_unique <rejected_op_constraint> (model,
1646 : dest_sval,
1647 6 : EQ_EXPR,
1648 3 : dst_label_ptr);
1649 12 : return false;
1650 : }
1651 : }
1652 :
1653 : return true;
1654 : }
1655 :
1656 : // class switch_case_op : public control_flow_op
1657 :
1658 2983 : switch_case_op::switch_case_op (function &fun,
1659 : ::edge cfg_edge,
1660 : const gswitch &switch_stmt,
1661 2983 : bounded_ranges_manager &mgr)
1662 2983 : : control_flow_op (kind::switch_edge, cfg_edge, switch_stmt)
1663 : {
1664 : /* Populate m_case_labels with all cases which go to DST. */
1665 542488 : for (unsigned i = 0; i < gimple_switch_num_labels (&switch_stmt); i++)
1666 : {
1667 539505 : tree case_ = gimple_switch_label (&switch_stmt, i);
1668 539505 : basic_block bb = label_to_block (&fun,
1669 539505 : CASE_LABEL (case_));
1670 539505 : if (bb == cfg_edge->dest)
1671 3552 : m_case_labels.push_back (case_);
1672 : }
1673 :
1674 2983 : auto_vec <const bounded_ranges *> case_ranges_vec
1675 2983 : (gimple_switch_num_labels (&switch_stmt));
1676 6535 : for (auto case_label : m_case_labels)
1677 : {
1678 : /* Get the ranges for this case label. */
1679 3552 : const bounded_ranges *case_ranges
1680 3552 : = mgr.make_case_label_ranges (&switch_stmt, case_label);
1681 3552 : case_ranges_vec.quick_push (case_ranges);
1682 : }
1683 :
1684 2983 : m_all_cases_ranges = mgr.get_or_create_union (case_ranges_vec);
1685 2983 : }
1686 :
1687 : /* Print "case VAL:", "case LOWER ... UPPER:", or "default:" to PP. */
1688 :
1689 : void
1690 460 : switch_case_op::print_as_edge_label (pretty_printer *pp,
1691 : bool user_facing) const
1692 : {
1693 460 : if (user_facing)
1694 : {
1695 906 : for (unsigned i = 0; i < m_case_labels.size (); ++i)
1696 : {
1697 456 : if (i > 0)
1698 6 : pp_string (pp, ", ");
1699 456 : tree case_label = m_case_labels[i];
1700 456 : gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
1701 456 : tree lower_bound = CASE_LOW (case_label);
1702 456 : tree upper_bound = CASE_HIGH (case_label);
1703 456 : if (lower_bound)
1704 : {
1705 171 : pp_printf (pp, "case ");
1706 171 : dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0, false);
1707 171 : if (upper_bound)
1708 : {
1709 12 : pp_printf (pp, " ... ");
1710 12 : dump_generic_node (pp, upper_bound, 0, (dump_flags_t)0,
1711 : false);
1712 : }
1713 171 : pp_printf (pp, ":");
1714 : }
1715 : else
1716 285 : pp_printf (pp, "default:");
1717 : }
1718 : }
1719 : else
1720 : {
1721 10 : pp_character (pp, '{');
1722 21 : for (unsigned i = 0; i < m_case_labels.size (); ++i)
1723 : {
1724 11 : if (i > 0)
1725 1 : pp_string (pp, ", ");
1726 11 : tree case_label = m_case_labels[i];
1727 11 : gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
1728 11 : tree lower_bound = CASE_LOW (case_label);
1729 11 : tree upper_bound = CASE_HIGH (case_label);
1730 11 : if (lower_bound)
1731 : {
1732 9 : if (upper_bound)
1733 : {
1734 0 : pp_character (pp, '[');
1735 0 : dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0,
1736 : false);
1737 0 : pp_string (pp, ", ");
1738 0 : dump_generic_node (pp, upper_bound, 0, (dump_flags_t)0,
1739 : false);
1740 0 : pp_character (pp, ']');
1741 : }
1742 : else
1743 9 : dump_generic_node (pp, lower_bound, 0, (dump_flags_t)0, false);
1744 : }
1745 : else
1746 2 : pp_printf (pp, "default");
1747 : }
1748 10 : pp_character (pp, '}');
1749 10 : if (implicitly_created_default_p ())
1750 : {
1751 2 : pp_string (pp, " IMPLICITLY CREATED");
1752 : }
1753 : }
1754 460 : }
1755 :
1756 : /* Return true iff SWITCH_STMT has a non-default label that contains
1757 : INT_CST. */
1758 :
1759 : static bool
1760 142 : has_nondefault_case_for_value_p (const gswitch *switch_stmt, tree int_cst)
1761 : {
1762 : /* We expect the initial label to be the default; skip it. */
1763 142 : gcc_assert (CASE_LOW (gimple_switch_label (switch_stmt, 0)) == NULL_TREE);
1764 142 : unsigned min_idx = 1;
1765 142 : unsigned max_idx = gimple_switch_num_labels (switch_stmt) - 1;
1766 :
1767 : /* Binary search: try to find the label containing INT_CST.
1768 : This requires the cases to be sorted by CASE_LOW (done by the
1769 : gimplifier). */
1770 257 : while (max_idx >= min_idx)
1771 : {
1772 247 : unsigned case_idx = (min_idx + max_idx) / 2;
1773 247 : tree label = gimple_switch_label (switch_stmt, case_idx);
1774 247 : tree low = CASE_LOW (label);
1775 247 : gcc_assert (low);
1776 247 : tree high = CASE_HIGH (label);
1777 247 : if (!high)
1778 195 : high = low;
1779 247 : if (tree_int_cst_compare (int_cst, low) < 0)
1780 : {
1781 : /* INT_CST is below the range of this label. */
1782 27 : gcc_assert (case_idx > 0);
1783 27 : max_idx = case_idx - 1;
1784 : }
1785 220 : else if (tree_int_cst_compare (int_cst, high) > 0)
1786 : {
1787 : /* INT_CST is above the range of this case. */
1788 88 : min_idx = case_idx + 1;
1789 : }
1790 : else
1791 : /* This case contains INT_CST. */
1792 : return true;
1793 : }
1794 : /* Not found. */
1795 : return false;
1796 : }
1797 :
1798 : /* Return true iff SWITCH_STMT (which must be on an enum value)
1799 : has nondefault cases handling all values in the enum. */
1800 :
1801 : static bool
1802 45 : has_nondefault_cases_for_all_enum_values_p (const gswitch *switch_stmt,
1803 : tree type)
1804 : {
1805 45 : gcc_assert (switch_stmt);
1806 45 : gcc_assert (TREE_CODE (type) == ENUMERAL_TYPE);
1807 :
1808 45 : for (tree enum_val_iter = TYPE_VALUES (type);
1809 177 : enum_val_iter;
1810 132 : enum_val_iter = TREE_CHAIN (enum_val_iter))
1811 : {
1812 142 : tree enum_val = TREE_VALUE (enum_val_iter);
1813 142 : gcc_assert (TREE_CODE (enum_val) == CONST_DECL);
1814 142 : gcc_assert (TREE_CODE (DECL_INITIAL (enum_val)) == INTEGER_CST);
1815 142 : if (!has_nondefault_case_for_value_p (switch_stmt,
1816 142 : DECL_INITIAL (enum_val)))
1817 : return false;
1818 : }
1819 : return true;
1820 : }
1821 :
1822 : /* Given an EDGE guarded by SWITCH_STMT, determine appropriate constraints
1823 : for the edge to be taken.
1824 :
1825 : If they are feasible, add the constraints and return true.
1826 :
1827 : Return false if the constraints contradict existing knowledge
1828 : (and so the edge should not be taken).
1829 : When returning false, if OUT is non-NULL, write a new rejected_constraint
1830 : to it. */
1831 :
1832 : bool
1833 8307 : switch_case_op::
1834 : apply_constraints (const superedge *,
1835 : region_model &model,
1836 : region_model_context *ctxt,
1837 : std::unique_ptr<rejected_constraint> *out) const
1838 : {
1839 8307 : const gswitch *switch_stmt = &get_gswitch ();
1840 8307 : tree index = gimple_switch_index (switch_stmt);
1841 8307 : const svalue *index_sval = model.get_rvalue (index, ctxt);
1842 8307 : bool check_index_type = true;
1843 :
1844 : /* With -fshort-enum, there may be a type cast. */
1845 6812 : if (ctxt && index_sval->get_kind () == SK_UNARYOP
1846 8754 : && TREE_CODE (index_sval->get_type ()) == INTEGER_TYPE)
1847 : {
1848 429 : const unaryop_svalue *unaryop = as_a <const unaryop_svalue *> (index_sval);
1849 429 : if (unaryop->get_op () == NOP_EXPR
1850 429 : && is_a <const initial_svalue *> (unaryop->get_arg ()))
1851 411 : if (const initial_svalue *initvalop = (as_a <const initial_svalue *>
1852 411 : (unaryop->get_arg ())))
1853 411 : if (initvalop->get_type ()
1854 411 : && TREE_CODE (initvalop->get_type ()) == ENUMERAL_TYPE)
1855 : {
1856 : index_sval = initvalop;
1857 : check_index_type = false;
1858 : }
1859 : }
1860 :
1861 : /* If we're switching based on an enum type, assume that the user is only
1862 : working with values from the enum. Hence if this is an
1863 : implicitly-created "default", assume it doesn't get followed.
1864 : This fixes numerous "uninitialized" false positives where we otherwise
1865 : consider jumping past the initialization cases. */
1866 :
1867 8307 : if (/* Don't check during feasibility-checking (when ctxt is NULL). */
1868 : ctxt
1869 : /* Must be an enum value. */
1870 6812 : && index_sval->get_type ()
1871 6812 : && (!check_index_type
1872 6497 : || TREE_CODE (TREE_TYPE (index)) == ENUMERAL_TYPE)
1873 663 : && TREE_CODE (index_sval->get_type ()) == ENUMERAL_TYPE
1874 : /* If we have a constant, then we can check it directly. */
1875 663 : && index_sval->get_kind () != SK_CONSTANT
1876 634 : && implicitly_created_default_p ()
1877 45 : && has_nondefault_cases_for_all_enum_values_p (switch_stmt,
1878 : index_sval->get_type ())
1879 : /* Don't do this if there's a chance that the index is
1880 : attacker-controlled. */
1881 8342 : && !ctxt->possibly_tainted_p (index_sval))
1882 : {
1883 33 : if (out)
1884 0 : *out = std::make_unique <rejected_default_case> (model);
1885 33 : return false;
1886 : }
1887 :
1888 8274 : bool sat
1889 16548 : = model.get_constraints ()->add_bounded_ranges (index_sval,
1890 8274 : m_all_cases_ranges);
1891 8274 : if (!sat && out)
1892 48 : *out = std::make_unique <rejected_ranges_constraint>
1893 48 : (model, index, m_all_cases_ranges);
1894 8274 : if (sat && ctxt && !m_all_cases_ranges->empty_p ())
1895 6202 : ctxt->on_bounded_ranges (*index_sval, *m_all_cases_ranges);
1896 : return sat;
1897 : }
1898 :
1899 : /* Return true iff this op's edge is purely for an
1900 : implicitly-created "default". */
1901 :
1902 : bool
1903 662 : switch_case_op::implicitly_created_default_p () const
1904 : {
1905 662 : if (m_case_labels.size () != 1)
1906 : return false;
1907 :
1908 595 : tree case_label = m_case_labels[0];
1909 595 : gcc_assert (TREE_CODE (case_label) == CASE_LABEL_EXPR);
1910 595 : if (CASE_LOW (case_label))
1911 : return false;
1912 :
1913 : /* We have a single "default" case.
1914 : Assume that it was implicitly created if it has UNKNOWN_LOCATION. */
1915 172 : return EXPR_LOCATION (case_label) == UNKNOWN_LOCATION;
1916 : }
1917 :
1918 : /* Given an ERT_TRY region, get the eh_catch corresponding to
1919 : the label of DST_SNODE, if any. */
1920 :
1921 : static eh_catch
1922 179 : get_catch (eh_region eh_reg, supernode *dst_snode)
1923 : {
1924 179 : gcc_assert (eh_reg->type == ERT_TRY);
1925 :
1926 179 : tree dst_snode_label = dst_snode->get_label ();
1927 179 : if (!dst_snode_label)
1928 : return nullptr;
1929 :
1930 124 : for (eh_catch iter = eh_reg->u.eh_try.first_catch;
1931 184 : iter;
1932 60 : iter = iter->next_catch)
1933 184 : if (iter->label == dst_snode_label)
1934 : return iter;
1935 :
1936 : return nullptr;
1937 : }
1938 :
1939 : class rejected_eh_dispatch : public rejected_constraint
1940 : {
1941 : public:
1942 0 : rejected_eh_dispatch (const region_model &model)
1943 0 : : rejected_constraint (model)
1944 : {}
1945 :
1946 0 : void dump_to_pp (pretty_printer *pp) const final override
1947 : {
1948 0 : pp_printf (pp, "rejected_eh_dispatch");
1949 0 : }
1950 : };
1951 :
1952 : static bool
1953 330 : exception_matches_type_p (tree exception_type,
1954 : tree catch_type)
1955 : {
1956 0 : if (catch_type == exception_type)
1957 0 : return true;
1958 :
1959 : /* TODO (PR analyzer/119697): we should also handle subclasses etc;
1960 : see the rules in https://en.cppreference.com/w/cpp/language/catch
1961 :
1962 : It looks like we should be calling (or emulating)
1963 : can_convert_eh from the C++ FE, but that's specific to the C++ FE. */
1964 :
1965 : return false;
1966 : }
1967 :
1968 : static bool
1969 353 : matches_any_exception_type_p (eh_catch ehc, tree exception_type)
1970 : {
1971 353 : if (ehc->type_list == NULL_TREE)
1972 : /* All exceptions are caught here. */
1973 : return true;
1974 :
1975 440 : for (tree iter = ehc->type_list; iter; iter = TREE_CHAIN (iter))
1976 353 : if (exception_matches_type_p (TREE_VALUE (iter),
1977 : exception_type))
1978 : return true;
1979 : return false;
1980 : }
1981 :
1982 : // class eh_dispatch_edge_op : public control_flow_op
1983 :
1984 : std::unique_ptr<eh_dispatch_edge_op>
1985 191 : eh_dispatch_edge_op::make (supernode *src_snode,
1986 : supernode *dst_snode,
1987 : ::edge cfg_edge,
1988 : const geh_dispatch &eh_dispatch_stmt)
1989 : {
1990 191 : const eh_status *eh = src_snode->get_function ()->eh;
1991 191 : gcc_assert (eh);
1992 191 : int region_idx = gimple_eh_dispatch_region (&eh_dispatch_stmt);
1993 191 : gcc_assert (region_idx > 0);
1994 191 : gcc_assert ((*eh->region_array)[region_idx]);
1995 191 : eh_region eh_reg = (*eh->region_array)[region_idx];
1996 191 : gcc_assert (eh_reg);
1997 191 : switch (eh_reg->type)
1998 : {
1999 0 : default:
2000 0 : gcc_unreachable ();
2001 0 : case ERT_CLEANUP:
2002 : // TODO
2003 0 : gcc_unreachable ();
2004 179 : break;
2005 179 : case ERT_TRY:
2006 179 : {
2007 179 : eh_catch ehc = get_catch (eh_reg, dst_snode);
2008 179 : return std::make_unique<eh_dispatch_try_edge_op>
2009 179 : (src_snode,
2010 : cfg_edge, eh_dispatch_stmt,
2011 179 : eh_reg, ehc);
2012 : }
2013 12 : break;
2014 12 : case ERT_ALLOWED_EXCEPTIONS:
2015 12 : return std::make_unique<eh_dispatch_allowed_edge_op>
2016 12 : (src_snode, dst_snode,
2017 : cfg_edge, eh_dispatch_stmt,
2018 12 : eh_reg);
2019 0 : break;
2020 0 : case ERT_MUST_NOT_THROW:
2021 : // TODO
2022 0 : gcc_unreachable ();
2023 : break;
2024 : }
2025 : }
2026 :
2027 191 : eh_dispatch_edge_op::
2028 : eh_dispatch_edge_op (supernode *src_snode,
2029 : enum kind kind_,
2030 : ::edge cfg_edge,
2031 : const geh_dispatch &geh_dispatch_stmt,
2032 191 : eh_region eh_reg)
2033 : : control_flow_op (kind_, cfg_edge, geh_dispatch_stmt),
2034 191 : m_src_snode (src_snode),
2035 191 : m_eh_region (eh_reg)
2036 : {
2037 191 : }
2038 :
2039 : bool
2040 405 : eh_dispatch_edge_op::
2041 : apply_constraints (const superedge *sedge,
2042 : region_model &model,
2043 : region_model_context *ctxt,
2044 : std::unique_ptr<rejected_constraint> *out) const
2045 : {
2046 405 : const exception_node *current_node = model.get_current_thrown_exception ();
2047 :
2048 402 : if (!current_node)
2049 : return false;
2050 :
2051 402 : gcc_assert (current_node);
2052 402 : tree curr_exception_type = current_node->maybe_get_type ();
2053 402 : if (!curr_exception_type)
2054 : /* We don't know the specific type. */
2055 : return true;
2056 :
2057 300 : return apply_eh_constraints (sedge, model, ctxt, curr_exception_type, out);
2058 : }
2059 :
2060 : // class eh_dispatch_try_edge_op : public eh_dispatch_edge_op
2061 :
2062 179 : eh_dispatch_try_edge_op::
2063 : eh_dispatch_try_edge_op (supernode *src_snode,
2064 : ::edge cfg_edge,
2065 : const geh_dispatch &geh_dispatch_stmt,
2066 : eh_region eh_reg,
2067 179 : eh_catch ehc)
2068 : : eh_dispatch_edge_op (src_snode,
2069 : kind::eh_dispatch_try_edge,
2070 : cfg_edge, geh_dispatch_stmt, eh_reg),
2071 179 : m_eh_catch (ehc)
2072 : {
2073 179 : gcc_assert (eh_reg->type == ERT_TRY);
2074 179 : }
2075 :
2076 : void
2077 0 : eh_dispatch_try_edge_op::print_as_edge_label (pretty_printer *pp,
2078 : bool user_facing) const
2079 : {
2080 0 : if (!user_facing)
2081 0 : pp_string (pp, "ERT_TRY: ");
2082 0 : if (m_eh_catch)
2083 : {
2084 0 : bool first = true;
2085 0 : for (tree iter = m_eh_catch->type_list; iter; iter = TREE_CHAIN (iter))
2086 : {
2087 0 : if (!first)
2088 0 : pp_string (pp, ", ");
2089 0 : pp_printf (pp, "on catch %qT", TREE_VALUE (iter));
2090 0 : first = false;
2091 : }
2092 : }
2093 : else
2094 0 : pp_string (pp, "on uncaught exception");
2095 0 : }
2096 :
2097 : void
2098 69 : eh_dispatch_try_edge_op::add_any_events_for_eedge (const exploded_edge &eedge,
2099 : checker_path &out_path) const
2100 : {
2101 69 : if (m_eh_catch)
2102 : {
2103 66 : const region_model *model = eedge.m_src->get_state ().m_region_model;
2104 66 : auto curr_thrown_exception_node
2105 66 : = model->get_current_thrown_exception ();
2106 0 : gcc_assert (curr_thrown_exception_node);
2107 66 : tree type = curr_thrown_exception_node->maybe_get_type ();
2108 66 : out_path.add_event
2109 66 : (std::make_unique<catch_cfg_edge_event>
2110 66 : (eedge,
2111 132 : event_loc_info (eedge.m_dest),
2112 : *this,
2113 : type));
2114 : }
2115 : else
2116 : {
2117 : /* We have the "uncaught exception" sedge, from eh_dispatch
2118 : to a block containing resx.
2119 : Don't add any events for this, so that we can consolidate
2120 : adjacent stack unwinding events. */
2121 : }
2122 69 : }
2123 :
2124 : bool
2125 284 : eh_dispatch_try_edge_op::
2126 : apply_eh_constraints (const superedge *sedge,
2127 : region_model &model,
2128 : region_model_context */*ctxt*/,
2129 : tree exception_type,
2130 : std::unique_ptr<rejected_constraint> *out) const
2131 : {
2132 : /* TODO: can we rely on this ordering?
2133 : or do we need to iterate through prev_catch ? */
2134 : /* The exception must not match any of the previous edges. */
2135 945 : for (auto sibling_sedge : get_src_snode ()->m_succs)
2136 : {
2137 377 : if (sibling_sedge == sedge)
2138 : break;
2139 :
2140 154 : const eh_dispatch_try_edge_op *sibling_edge_op
2141 154 : = (const eh_dispatch_try_edge_op *)sibling_sedge->get_op ();
2142 154 : if (eh_catch ehc = sibling_edge_op->m_eh_catch)
2143 154 : if (matches_any_exception_type_p (ehc, exception_type))
2144 : {
2145 : /* The earlier sibling matches, so the "unhandled" edge is
2146 : not taken. */
2147 61 : if (out)
2148 0 : *out = std::make_unique<rejected_eh_dispatch> (model);
2149 61 : return false;
2150 : }
2151 : }
2152 :
2153 223 : if (eh_catch ehc = m_eh_catch)
2154 : {
2155 : /* We have an edge that tried to match one or more types. */
2156 :
2157 : /* The exception must not match any of the previous edges. */
2158 :
2159 : /* It must match this type. */
2160 199 : if (matches_any_exception_type_p (ehc, exception_type))
2161 : return true;
2162 : else
2163 : {
2164 : /* Exception type doesn't match. */
2165 33 : if (out)
2166 0 : *out = std::make_unique<rejected_eh_dispatch> (model);
2167 33 : return false;
2168 : }
2169 : }
2170 : else
2171 : {
2172 : /* This is the "unhandled exception" edge.
2173 : If we get here then no sibling edges matched;
2174 : we will follow this edge. */
2175 : return true;
2176 : }
2177 : }
2178 :
2179 : // class eh_dispatch_allowed_edge_op : public eh_dispatch_edge_op
2180 :
2181 12 : eh_dispatch_allowed_edge_op::
2182 : eh_dispatch_allowed_edge_op (supernode *src_snode,
2183 : supernode *dst_snode,
2184 : ::edge cfg_edge,
2185 : const geh_dispatch &geh_dispatch_stmt,
2186 12 : eh_region eh_reg)
2187 : : eh_dispatch_edge_op (src_snode,
2188 : kind::eh_dispatch_try_edge,
2189 12 : cfg_edge, geh_dispatch_stmt, eh_reg)
2190 : {
2191 12 : gcc_assert (eh_reg->type == ERT_ALLOWED_EXCEPTIONS);
2192 :
2193 : /* We expect two sibling out-edges at an eh_dispatch from such a region:
2194 :
2195 : - one to a bb without a gimple label, with a resx,
2196 : for exceptions of expected types
2197 :
2198 : - one to a bb with a gimple label, with a call to __cxa_unexpected,
2199 : for exceptions of unexpected types.
2200 :
2201 : Set m_kind for this edge accordingly. */
2202 12 : gcc_assert (cfg_edge->src->succs->length () == 2);
2203 12 : tree label_for_unexpected_exceptions = eh_reg->u.allowed.label;
2204 12 : tree label_for_dest_enode = dst_snode->get_label ();
2205 12 : if (label_for_dest_enode == label_for_unexpected_exceptions)
2206 6 : m_kind = eh_kind::unexpected;
2207 : else
2208 : {
2209 6 : gcc_assert (label_for_dest_enode == nullptr);
2210 6 : m_kind = eh_kind::expected;
2211 : }
2212 12 : }
2213 :
2214 : void
2215 3 : eh_dispatch_allowed_edge_op::print_as_edge_label (pretty_printer *pp,
2216 : bool user_facing) const
2217 : {
2218 3 : if (!user_facing)
2219 : {
2220 0 : switch (m_kind)
2221 : {
2222 0 : default:
2223 0 : gcc_unreachable ();
2224 0 : case eh_kind::expected:
2225 0 : pp_string (pp, "expected: ");
2226 0 : break;
2227 0 : case eh_kind::unexpected:
2228 0 : pp_string (pp, "unexpected: ");
2229 0 : break;
2230 : }
2231 0 : pp_string (pp, "ERT_ALLOWED_EXCEPTIONS: ");
2232 0 : eh_region eh_reg = get_eh_region ();
2233 0 : bool first = true;
2234 0 : for (tree iter = eh_reg->u.allowed.type_list; iter;
2235 0 : iter = TREE_CHAIN (iter))
2236 : {
2237 0 : if (!first)
2238 0 : pp_string (pp, ", ");
2239 0 : pp_printf (pp, "%qT", TREE_VALUE (iter));
2240 0 : first = false;
2241 : }
2242 : }
2243 3 : }
2244 :
2245 : bool
2246 16 : eh_dispatch_allowed_edge_op::
2247 : apply_eh_constraints (const superedge *,
2248 : region_model &model,
2249 : region_model_context */*ctxt*/,
2250 : tree exception_type,
2251 : std::unique_ptr<rejected_constraint> *out) const
2252 : {
2253 16 : auto curr_thrown_exception_node = model.get_current_thrown_exception ();
2254 0 : gcc_assert (curr_thrown_exception_node);
2255 16 : tree curr_exception_type = curr_thrown_exception_node->maybe_get_type ();
2256 16 : eh_region eh_reg = get_eh_region ();
2257 16 : tree type_list = eh_reg->u.allowed.type_list;
2258 :
2259 16 : switch (get_eh_kind ())
2260 : {
2261 0 : default:
2262 0 : gcc_unreachable ();
2263 5 : case eh_kind::expected:
2264 5 : if (!curr_exception_type)
2265 : {
2266 : /* We don't know the specific type;
2267 : assume we have one of an expected type. */
2268 : return true;
2269 : }
2270 8 : for (tree iter = type_list; iter; iter = TREE_CHAIN (iter))
2271 14 : if (exception_matches_type_p (TREE_VALUE (iter),
2272 : exception_type))
2273 : return true;
2274 3 : if (out)
2275 0 : *out = std::make_unique<rejected_eh_dispatch> (model);
2276 : return false;
2277 :
2278 11 : case eh_kind::unexpected:
2279 11 : if (!curr_exception_type)
2280 : {
2281 : /* We don't know the specific type;
2282 : assume we don't have one of an expected type. */
2283 0 : if (out)
2284 0 : *out = std::make_unique<rejected_eh_dispatch> (model);
2285 0 : return false;
2286 : }
2287 20 : for (tree iter = type_list; iter; iter = TREE_CHAIN (iter))
2288 11 : if (exception_matches_type_p (TREE_VALUE (iter),
2289 : exception_type))
2290 : {
2291 2 : if (out)
2292 0 : *out = std::make_unique<rejected_eh_dispatch> (model);
2293 2 : return false;
2294 : }
2295 : return true;
2296 : }
2297 : }
2298 :
2299 : // class phis_for_edge_op : public operation
2300 :
2301 : std::unique_ptr<operation>
2302 15654 : phis_for_edge_op::maybe_make (::edge cfg_in_edge)
2303 : {
2304 15654 : std::vector<pair> pairs = get_pairs_for_phi_along_in_edge (cfg_in_edge);
2305 15654 : if (pairs.empty ())
2306 6404 : return nullptr;
2307 :
2308 9250 : return std::make_unique <phis_for_edge_op> (std::move (pairs));
2309 15654 : }
2310 :
2311 9250 : phis_for_edge_op::phis_for_edge_op (std::vector<pair> &&pairs)
2312 : : operation (kind::phis),
2313 9250 : m_pairs (std::move (pairs))
2314 : {
2315 9250 : }
2316 :
2317 : std::vector<phis_for_edge_op::pair>
2318 15654 : phis_for_edge_op::get_pairs_for_phi_along_in_edge (::edge cfg_in_edge)
2319 : {
2320 15654 : std::vector<pair> result;
2321 :
2322 15654 : const size_t phi_arg_idx = cfg_in_edge->dest_idx;
2323 15654 : for (gphi_iterator gpi = gsi_start_phis (cfg_in_edge->dest);
2324 38127 : !gsi_end_p (gpi); gsi_next (&gpi))
2325 : {
2326 22473 : gphi * const phi = gpi.phi ();
2327 22473 : tree dst = gimple_phi_result (phi);
2328 :
2329 : /* We don't bother tracking the .MEM SSA names. */
2330 22473 : if (tree var = SSA_NAME_VAR (dst))
2331 17636 : if (TREE_CODE (var) == VAR_DECL)
2332 17043 : if (VAR_DECL_IS_VIRTUAL_OPERAND (var))
2333 11278 : continue;
2334 :
2335 11195 : tree src = gimple_phi_arg_def (phi, phi_arg_idx);
2336 :
2337 11195 : result.push_back ({dst, src});
2338 : }
2339 :
2340 15654 : return result;
2341 : }
2342 :
2343 : void
2344 87 : phis_for_edge_op::print_as_edge_label (pretty_printer *pp,
2345 : bool ) const
2346 : {
2347 87 : pp_printf (pp, "PHI(");
2348 87 : bool first = true;
2349 174 : for (auto &p : m_pairs)
2350 : {
2351 87 : if (first)
2352 : first = false;
2353 : else
2354 0 : pp_string (pp, ", ");
2355 :
2356 87 : pp_printf (pp, "%E = %E", p.m_dst, p.m_src);
2357 : }
2358 87 : pp_printf (pp, ");");
2359 87 : }
2360 :
2361 : void
2362 9250 : phis_for_edge_op::
2363 : walk_load_store_addr_ops (void */*data*/ ,
2364 : walk_stmt_load_store_addr_fn /*load_cb*/,
2365 : walk_stmt_load_store_addr_fn /*store_cb*/,
2366 : walk_stmt_load_store_addr_fn /*addr_cb*/) const
2367 : {
2368 9250 : }
2369 :
2370 : bool
2371 20769 : phis_for_edge_op::defines_ssa_name_p (const_tree ssa_name) const
2372 : {
2373 38066 : for (auto &p : m_pairs)
2374 28531 : if (p.m_dst == ssa_name)
2375 20769 : return true;
2376 : return false;
2377 : }
2378 :
2379 : void
2380 21431 : phis_for_edge_op::execute (operation_context &op_ctxt) const
2381 : {
2382 21431 : auto logger = op_ctxt.get_logger ();
2383 21431 : LOG_SCOPE (logger);
2384 :
2385 21431 : auto dst_point (op_ctxt.get_next_intraprocedural_point ());
2386 :
2387 21431 : const program_state &src_state (op_ctxt.get_initial_state ());
2388 21431 : program_state dst_state (src_state);
2389 :
2390 21431 : impl_path_context path_ctxt (&dst_state, logger);
2391 21431 : uncertainty_t uncertainty;
2392 21431 : impl_region_model_context ctxt (op_ctxt.m_eg,
2393 21431 : &op_ctxt.m_src_enode,
2394 :
2395 : /* TODO: should we be getting the ECs from the
2396 : old state, rather than the new? */
2397 21431 : &op_ctxt.get_initial_state (),
2398 : &dst_state,
2399 : &uncertainty,
2400 : &path_ctxt,
2401 : nullptr,
2402 21431 : nullptr);
2403 :
2404 21431 : update_state (src_state, dst_state, &ctxt);
2405 :
2406 21431 : op_ctxt.add_outcome (dst_point, dst_state, false, &uncertainty);
2407 42862 : }
2408 :
2409 : void
2410 21845 : phis_for_edge_op::update_state (const program_state &src_state,
2411 : program_state &dst_state,
2412 : region_model_context *ctxt) const
2413 : {
2414 21845 : const region_model &src_model = *src_state.m_region_model;
2415 21845 : region_model &dst_model = *dst_state.m_region_model;
2416 :
2417 21845 : hash_set<const svalue *> svals_changing_meaning;
2418 :
2419 : /* Get state from src_state so that all of the phi stmts for an edge
2420 : are effectively handled simultaneously. */
2421 52145 : for (auto &p : m_pairs)
2422 : {
2423 30300 : const svalue *src_sval = src_model.get_rvalue (p.m_src, nullptr);
2424 30300 : const region *dst_reg = src_model.get_lvalue (p.m_dst, nullptr);
2425 :
2426 30300 : const svalue *old_sval = src_model.get_rvalue (p.m_dst, nullptr);
2427 30300 : if (old_sval->get_kind () == SK_WIDENING)
2428 12 : svals_changing_meaning.add (old_sval);
2429 :
2430 30300 : dst_model.set_value (dst_reg, src_sval, ctxt);
2431 : }
2432 :
2433 43702 : for (auto iter : svals_changing_meaning)
2434 12 : dst_model.get_constraints ()->purge_state_involving (iter);
2435 21845 : }
2436 :
2437 : bool
2438 12405 : phis_for_edge_op::
2439 : execute_for_feasibility (const exploded_edge &eedge,
2440 : feasibility_state &fstate,
2441 : region_model_context *ctxt,
2442 : std::unique_ptr<rejected_constraint> */*out_rc*/) const
2443 : {
2444 12405 : hash_set<const svalue *> svals_changing_meaning;
2445 : /* Get state from src_state so that all of the phi stmts for an edge
2446 : are effectively handled simultaneously. */
2447 12405 : region_model &model = fstate.get_model ();
2448 12405 : region_model src_model (model);
2449 27647 : for (auto &p : m_pairs)
2450 : {
2451 15242 : const svalue *src_sval = src_model.get_rvalue (p.m_src, ctxt);
2452 15242 : const region *dst_reg = model.get_lvalue (p.m_dst, ctxt);
2453 :
2454 15242 : const svalue *sval = model.get_rvalue (p.m_dst, ctxt);
2455 15242 : if (sval->get_kind () == SK_WIDENING)
2456 24 : svals_changing_meaning.add (sval);
2457 :
2458 15242 : model.set_value (dst_reg, src_sval, ctxt);
2459 : }
2460 :
2461 12429 : for (auto iter : svals_changing_meaning)
2462 24 : model.get_constraints ()->purge_state_involving (iter);
2463 :
2464 12405 : {
2465 : /* If we've entering an snode that we've already visited on this
2466 : epath, then we need do fix things up for loops; see the
2467 : comment for store::loop_replay_fixup.
2468 : Perhaps we should probably also verify the callstring,
2469 : and track program_points, but hopefully doing it by supernode
2470 : is good enough. */
2471 12405 : const exploded_node &dst_enode = *eedge.m_dest;
2472 12405 : const unsigned dst_snode_idx = dst_enode.get_supernode ()->m_id;
2473 12405 : if (bitmap_bit_p (fstate.get_snodes_visited (), dst_snode_idx))
2474 4661 : model.loop_replay_fixup (dst_enode.get_state ().m_region_model);
2475 : }
2476 :
2477 24810 : return true;
2478 12405 : }
2479 :
2480 : void
2481 414 : phis_for_edge_op::
2482 : update_state_for_bulk_merger (const program_state &src_state,
2483 : program_state &dst_state) const
2484 : {
2485 414 : update_state (src_state, dst_state, nullptr);
2486 414 : }
2487 :
2488 : void
2489 1278 : phis_for_edge_op::add_any_events_for_eedge (const exploded_edge &,
2490 : checker_path &) const
2491 : {
2492 : // No-op
2493 1278 : }
2494 :
2495 : bool
2496 1290 : phis_for_edge_op::try_to_rewind_data_flow (rewind_context &ctxt) const
2497 : {
2498 1290 : auto logger = ctxt.m_logger;
2499 1290 : LOG_SCOPE (logger);
2500 3119 : for (auto iter : m_pairs)
2501 1829 : ctxt.on_data_flow (iter.m_src, iter.m_dst);
2502 2580 : return true;
2503 1290 : }
2504 :
2505 : // class resx_op : public gimple_stmt_op
2506 :
2507 : void
2508 605 : resx_op::execute (operation_context &op_ctxt) const
2509 : {
2510 605 : auto logger = op_ctxt.get_logger ();
2511 605 : LOG_SCOPE (logger);
2512 :
2513 605 : program_point dst_point (op_ctxt.get_next_intraprocedural_point ());
2514 605 : program_state dst_state (op_ctxt.get_initial_state ());
2515 605 : op_region_model_context ctxt (op_ctxt, dst_state);
2516 :
2517 1210 : if (exploded_node *dst_enode
2518 605 : = op_ctxt.m_eg.get_or_create_node (dst_point, dst_state,
2519 605 : &op_ctxt.m_src_enode,
2520 : // Don't add to worklist:
2521 : false))
2522 : {
2523 605 : op_ctxt.m_eg.add_edge (&op_ctxt.m_src_enode,
2524 : dst_enode,
2525 605 : &op_ctxt.m_sedge,
2526 : false,
2527 605 : nullptr);
2528 : /* Try to adding eedges and enodes that unwind to the next
2529 : eh_dispatch statement, if any.
2530 : Only the final enode is added to the worklist. */
2531 605 : op_ctxt.m_eg.unwind_from_exception (*dst_enode,
2532 : nullptr,
2533 : &ctxt);
2534 : }
2535 605 : }
2536 :
2537 : void
2538 18 : resx_op::add_any_events_for_eedge (const exploded_edge &,
2539 : checker_path &) const
2540 : {
2541 18 : }
2542 :
2543 : } // namespace ana
2544 :
2545 : #endif /* #if ENABLE_ANALYZER */
|