c++: Tweaks for -Wredundant-move [PR107363]
[official-gcc.git] / gcc / analyzer / region-model-impl-calls.cc
blob9ef31f6ab0517f6cf3c931c5d0ca007980f9a9a3
1 /* Handling for the known behavior of various specific functions.
2 Copyright (C) 2020-2022 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #define INCLUDE_MEMORY
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tree.h"
26 #include "function.h"
27 #include "basic-block.h"
28 #include "gimple.h"
29 #include "gimple-iterator.h"
30 #include "diagnostic-core.h"
31 #include "graphviz.h"
32 #include "options.h"
33 #include "cgraph.h"
34 #include "tree-dfa.h"
35 #include "stringpool.h"
36 #include "convert.h"
37 #include "target.h"
38 #include "fold-const.h"
39 #include "tree-pretty-print.h"
40 #include "diagnostic-color.h"
41 #include "diagnostic-metadata.h"
42 #include "bitmap.h"
43 #include "analyzer/analyzer.h"
44 #include "analyzer/analyzer-logging.h"
45 #include "ordered-hash-map.h"
46 #include "options.h"
47 #include "analyzer/supergraph.h"
48 #include "sbitmap.h"
49 #include "analyzer/call-string.h"
50 #include "analyzer/program-point.h"
51 #include "analyzer/store.h"
52 #include "analyzer/region-model.h"
53 #include "analyzer/call-info.h"
54 #include "analyzer/sm.h"
55 #include "diagnostic-path.h"
56 #include "analyzer/pending-diagnostic.h"
57 #include "gimple-pretty-print.h"
58 #include "make-unique.h"
60 #if ENABLE_ANALYZER
62 namespace ana {
64 /* class call_details. */
66 /* call_details's ctor. */
68 call_details::call_details (const gcall *call, region_model *model,
69 region_model_context *ctxt)
70 : m_call (call), m_model (model), m_ctxt (ctxt),
71 m_lhs_type (NULL_TREE), m_lhs_region (NULL)
73 m_lhs_type = NULL_TREE;
74 if (tree lhs = gimple_call_lhs (call))
76 m_lhs_region = model->get_lvalue (lhs, ctxt);
77 m_lhs_type = TREE_TYPE (lhs);
81 /* Get the manager from m_model. */
83 region_model_manager *
84 call_details::get_manager () const
86 return m_model->get_manager ();
89 /* Get any logger associated with this object. */
91 logger *
92 call_details::get_logger () const
94 if (m_ctxt)
95 return m_ctxt->get_logger ();
96 else
97 return NULL;
100 /* Get any uncertainty_t associated with the region_model_context. */
102 uncertainty_t *
103 call_details::get_uncertainty () const
105 if (m_ctxt)
106 return m_ctxt->get_uncertainty ();
107 else
108 return NULL;
111 /* If the callsite has a left-hand-side region, set it to RESULT
112 and return true.
113 Otherwise do nothing and return false. */
115 bool
116 call_details::maybe_set_lhs (const svalue *result) const
118 gcc_assert (result);
119 if (m_lhs_region)
121 m_model->set_value (m_lhs_region, result, m_ctxt);
122 return true;
124 else
125 return false;
128 /* Return the number of arguments used by the call statement. */
130 unsigned
131 call_details::num_args () const
133 return gimple_call_num_args (m_call);
136 /* Get argument IDX at the callsite as a tree. */
138 tree
139 call_details::get_arg_tree (unsigned idx) const
141 return gimple_call_arg (m_call, idx);
144 /* Get the type of argument IDX. */
146 tree
147 call_details::get_arg_type (unsigned idx) const
149 return TREE_TYPE (gimple_call_arg (m_call, idx));
152 /* Get argument IDX at the callsite as an svalue. */
154 const svalue *
155 call_details::get_arg_svalue (unsigned idx) const
157 tree arg = get_arg_tree (idx);
158 return m_model->get_rvalue (arg, m_ctxt);
161 /* Attempt to get the string literal for argument IDX, or return NULL
162 otherwise.
163 For use when implementing "__analyzer_*" functions that take
164 string literals. */
166 const char *
167 call_details::get_arg_string_literal (unsigned idx) const
169 const svalue *str_arg = get_arg_svalue (idx);
170 if (const region *pointee = str_arg->maybe_get_region ())
171 if (const string_region *string_reg = pointee->dyn_cast_string_region ())
173 tree string_cst = string_reg->get_string_cst ();
174 return TREE_STRING_POINTER (string_cst);
176 return NULL;
179 /* Attempt to get the fndecl used at this call, if known, or NULL_TREE
180 otherwise. */
182 tree
183 call_details::get_fndecl_for_call () const
185 return m_model->get_fndecl_for_call (m_call, m_ctxt);
188 /* Dump a multiline representation of this call to PP. */
190 void
191 call_details::dump_to_pp (pretty_printer *pp, bool simple) const
193 pp_string (pp, "gcall: ");
194 pp_gimple_stmt_1 (pp, m_call, 0 /* spc */, TDF_NONE /* flags */);
195 pp_newline (pp);
196 pp_string (pp, "return region: ");
197 if (m_lhs_region)
198 m_lhs_region->dump_to_pp (pp, simple);
199 else
200 pp_string (pp, "NULL");
201 pp_newline (pp);
202 for (unsigned i = 0; i < gimple_call_num_args (m_call); i++)
204 const svalue *arg_sval = get_arg_svalue (i);
205 pp_printf (pp, "arg %i: ", i);
206 arg_sval->dump_to_pp (pp, simple);
207 pp_newline (pp);
211 /* Dump a multiline representation of this call to stderr. */
213 DEBUG_FUNCTION void
214 call_details::dump (bool simple) const
216 pretty_printer pp;
217 pp_format_decoder (&pp) = default_tree_printer;
218 pp_show_color (&pp) = pp_show_color (global_dc->printer);
219 pp.buffer->stream = stderr;
220 dump_to_pp (&pp, simple);
221 pp_flush (&pp);
224 /* Get a conjured_svalue for this call for REG,
225 and purge any state already relating to that conjured_svalue. */
227 const svalue *
228 call_details::get_or_create_conjured_svalue (const region *reg) const
230 region_model_manager *mgr = m_model->get_manager ();
231 return mgr->get_or_create_conjured_svalue (reg->get_type (), m_call, reg,
232 conjured_purge (m_model, m_ctxt));
235 /* Implementations of specific functions. */
237 /* Handle the on_call_pre part of "alloca". */
239 void
240 region_model::impl_call_alloca (const call_details &cd)
242 const svalue *size_sval = cd.get_arg_svalue (0);
243 const region *new_reg = create_region_for_alloca (size_sval, cd.get_ctxt ());
244 const svalue *ptr_sval
245 = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
246 cd.maybe_set_lhs (ptr_sval);
249 /* Handle a call to "__analyzer_describe".
251 Emit a warning describing the 2nd argument (which can be of any
252 type), at the given verbosity level. This is for use when
253 debugging, and may be of use in DejaGnu tests. */
255 void
256 region_model::impl_call_analyzer_describe (const gcall *call,
257 region_model_context *ctxt)
259 tree t_verbosity = gimple_call_arg (call, 0);
260 tree t_val = gimple_call_arg (call, 1);
261 const svalue *sval = get_rvalue (t_val, ctxt);
262 bool simple = zerop (t_verbosity);
263 label_text desc = sval->get_desc (simple);
264 warning_at (call->location, 0, "svalue: %qs", desc.get ());
267 /* Handle a call to "__analyzer_dump_capacity".
269 Emit a warning describing the capacity of the base region of
270 the region pointed to by the 1st argument.
271 This is for use when debugging, and may be of use in DejaGnu tests. */
273 void
274 region_model::impl_call_analyzer_dump_capacity (const gcall *call,
275 region_model_context *ctxt)
277 tree t_ptr = gimple_call_arg (call, 0);
278 const svalue *sval_ptr = get_rvalue (t_ptr, ctxt);
279 const region *reg = deref_rvalue (sval_ptr, t_ptr, ctxt);
280 const region *base_reg = reg->get_base_region ();
281 const svalue *capacity = get_capacity (base_reg);
282 label_text desc = capacity->get_desc (true);
283 warning_at (call->location, 0, "capacity: %qs", desc.get ());
286 /* Compare D1 and D2 using their names, and then IDs to order them. */
288 static int
289 cmp_decls (tree d1, tree d2)
291 gcc_assert (DECL_P (d1));
292 gcc_assert (DECL_P (d2));
293 if (DECL_NAME (d1) && DECL_NAME (d2))
294 if (int cmp = strcmp (IDENTIFIER_POINTER (DECL_NAME (d1)),
295 IDENTIFIER_POINTER (DECL_NAME (d2))))
296 return cmp;
297 return (int)DECL_UID (d1) - (int)DECL_UID (d2);
300 /* Comparator for use by vec<tree>::qsort,
301 using their names, and then IDs to order them. */
303 static int
304 cmp_decls_ptr_ptr (const void *p1, const void *p2)
306 tree const *d1 = (tree const *)p1;
307 tree const *d2 = (tree const *)p2;
309 return cmp_decls (*d1, *d2);
312 /* Handle a call to "__analyzer_dump_escaped".
314 Emit a warning giving the number of decls that have escaped, followed
315 by a comma-separated list of their names, in alphabetical order.
317 This is for use when debugging, and may be of use in DejaGnu tests. */
319 void
320 region_model::impl_call_analyzer_dump_escaped (const gcall *call)
322 auto_vec<tree> escaped_decls;
323 for (auto iter : m_store)
325 const binding_cluster *c = iter.second;
326 if (!c->escaped_p ())
327 continue;
328 if (tree decl = c->get_base_region ()->maybe_get_decl ())
329 escaped_decls.safe_push (decl);
332 /* Sort them into deterministic order; alphabetical is
333 probably most user-friendly. */
334 escaped_decls.qsort (cmp_decls_ptr_ptr);
336 pretty_printer pp;
337 pp_format_decoder (&pp) = default_tree_printer;
338 pp_show_color (&pp) = pp_show_color (global_dc->printer);
339 bool first = true;
340 for (auto iter : escaped_decls)
342 if (first)
343 first = false;
344 else
345 pp_string (&pp, ", ");
346 pp_printf (&pp, "%qD", iter);
348 /* Print the number to make it easier to write DejaGnu tests for
349 the "nothing has escaped" case. */
350 warning_at (call->location, 0, "escaped: %i: %s",
351 escaped_decls.length (),
352 pp_formatted_text (&pp));
355 /* Handle a call to "__analyzer_eval" by evaluating the input
356 and dumping as a dummy warning, so that test cases can use
357 dg-warning to validate the result (and so unexpected warnings will
358 lead to DejaGnu failures).
359 Broken out as a subroutine to make it easier to put a breakpoint on it
360 - though typically this doesn't help, as we have an SSA name as the arg,
361 and what's more interesting is usually the def stmt for that name. */
363 void
364 region_model::impl_call_analyzer_eval (const gcall *call,
365 region_model_context *ctxt)
367 tree t_arg = gimple_call_arg (call, 0);
368 tristate t = eval_condition (t_arg, NE_EXPR, integer_zero_node, ctxt);
369 warning_at (call->location, 0, "%s", t.as_string ());
372 /* Handle the on_call_pre part of "__analyzer_get_unknown_ptr". */
374 void
375 region_model::impl_call_analyzer_get_unknown_ptr (const call_details &cd)
377 const svalue *ptr_sval
378 = m_mgr->get_or_create_unknown_svalue (cd.get_lhs_type ());
379 cd.maybe_set_lhs (ptr_sval);
382 /* Handle the on_call_pre part of "__builtin_expect" etc. */
384 void
385 region_model::impl_call_builtin_expect (const call_details &cd)
387 /* __builtin_expect's return value is its initial argument. */
388 const svalue *sval = cd.get_arg_svalue (0);
389 cd.maybe_set_lhs (sval);
392 /* Handle the on_call_pre part of "calloc". */
394 void
395 region_model::impl_call_calloc (const call_details &cd)
397 const svalue *nmemb_sval = cd.get_arg_svalue (0);
398 const svalue *size_sval = cd.get_arg_svalue (1);
399 /* TODO: check for overflow here? */
400 const svalue *prod_sval
401 = m_mgr->get_or_create_binop (size_type_node, MULT_EXPR,
402 nmemb_sval, size_sval);
403 const region *new_reg
404 = create_region_for_heap_alloc (prod_sval, cd.get_ctxt ());
405 const region *sized_reg
406 = m_mgr->get_sized_region (new_reg, NULL_TREE, prod_sval);
407 zero_fill_region (sized_reg);
408 if (cd.get_lhs_type ())
410 const svalue *ptr_sval
411 = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
412 cd.maybe_set_lhs (ptr_sval);
416 /* Handle the on_call_pre part of "__errno_location". */
418 void
419 region_model::impl_call_errno_location (const call_details &cd)
421 if (cd.get_lhs_region ())
423 const region *errno_reg = m_mgr->get_errno_region ();
424 const svalue *errno_ptr = m_mgr->get_ptr_svalue (cd.get_lhs_type (),
425 errno_reg);
426 cd.maybe_set_lhs (errno_ptr);
430 /* Handle the on_call_pre part of "error" and "error_at_line" from
431 GNU's non-standard <error.h>.
432 MIN_ARGS identifies the minimum number of expected arguments
433 to be consistent with such a call (3 and 5 respectively).
434 Return true if handling it as one of these functions.
435 Write true to *OUT_TERMINATE_PATH if this execution path should be
436 terminated (e.g. the function call terminates the process). */
438 bool
439 region_model::impl_call_error (const call_details &cd, unsigned min_args,
440 bool *out_terminate_path)
442 /* Bail if not enough args. */
443 if (cd.num_args () < min_args)
444 return false;
446 /* Initial argument ought to be of type "int". */
447 if (cd.get_arg_type (0) != integer_type_node)
448 return false;
450 /* The process exits if status != 0, so it only continues
451 for the case where status == 0.
452 Add that constraint, or terminate this analysis path. */
453 tree status = cd.get_arg_tree (0);
454 if (!add_constraint (status, EQ_EXPR, integer_zero_node, cd.get_ctxt ()))
455 *out_terminate_path = true;
457 return true;
460 /* Handle the on_call_pre part of "fgets" and "fgets_unlocked". */
462 void
463 region_model::impl_call_fgets (const call_details &cd)
465 /* Ideally we would bifurcate state here between the
466 error vs no error cases. */
467 const svalue *ptr_sval = cd.get_arg_svalue (0);
468 if (const region *reg = ptr_sval->maybe_get_region ())
470 const region *base_reg = reg->get_base_region ();
471 const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg);
472 set_value (base_reg, new_sval, cd.get_ctxt ());
476 /* Handle the on_call_pre part of "fread". */
478 void
479 region_model::impl_call_fread (const call_details &cd)
481 const svalue *ptr_sval = cd.get_arg_svalue (0);
482 if (const region *reg = ptr_sval->maybe_get_region ())
484 const region *base_reg = reg->get_base_region ();
485 const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg);
486 set_value (base_reg, new_sval, cd.get_ctxt ());
490 /* Handle the on_call_post part of "free", after sm-handling.
492 If the ptr points to an underlying heap region, delete the region,
493 poisoning pointers to it and regions within it.
495 We delay this until after sm-state has been updated so that the
496 sm-handling can transition all of the various casts of the pointer
497 to a "freed" state *before* we delete the related region here.
499 This has to be done here so that the sm-handling can use the fact
500 that they point to the same region to establish that they are equal
501 (in region_model::eval_condition), and thus transition
502 all pointers to the region to the "freed" state together, regardless
503 of casts. */
505 void
506 region_model::impl_call_free (const call_details &cd)
508 const svalue *ptr_sval = cd.get_arg_svalue (0);
509 if (const region *freed_reg = ptr_sval->maybe_get_region ())
511 /* If the ptr points to an underlying heap region, delete it,
512 poisoning pointers. */
513 unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
514 m_dynamic_extents.remove (freed_reg);
518 /* Handle the on_call_pre part of "malloc". */
520 void
521 region_model::impl_call_malloc (const call_details &cd)
523 const svalue *size_sval = cd.get_arg_svalue (0);
524 const region *new_reg
525 = create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
526 if (cd.get_lhs_type ())
528 const svalue *ptr_sval
529 = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
530 cd.maybe_set_lhs (ptr_sval);
534 /* Handle the on_call_pre part of "memcpy" and "__builtin_memcpy". */
535 // TODO: complain about overlapping src and dest.
537 void
538 region_model::impl_call_memcpy (const call_details &cd)
540 const svalue *dest_ptr_sval = cd.get_arg_svalue (0);
541 const svalue *src_ptr_sval = cd.get_arg_svalue (1);
542 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
544 const region *dest_reg = deref_rvalue (dest_ptr_sval, cd.get_arg_tree (0),
545 cd.get_ctxt ());
546 const region *src_reg = deref_rvalue (src_ptr_sval, cd.get_arg_tree (1),
547 cd.get_ctxt ());
549 cd.maybe_set_lhs (dest_ptr_sval);
551 const region *sized_src_reg
552 = m_mgr->get_sized_region (src_reg, NULL_TREE, num_bytes_sval);
553 const region *sized_dest_reg
554 = m_mgr->get_sized_region (dest_reg, NULL_TREE, num_bytes_sval);
555 const svalue *src_contents_sval
556 = get_store_value (sized_src_reg, cd.get_ctxt ());
557 set_value (sized_dest_reg, src_contents_sval, cd.get_ctxt ());
560 /* Handle the on_call_pre part of "memset" and "__builtin_memset". */
562 void
563 region_model::impl_call_memset (const call_details &cd)
565 const svalue *dest_sval = cd.get_arg_svalue (0);
566 const svalue *fill_value_sval = cd.get_arg_svalue (1);
567 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
569 const region *dest_reg = deref_rvalue (dest_sval, cd.get_arg_tree (0),
570 cd.get_ctxt ());
572 const svalue *fill_value_u8
573 = m_mgr->get_or_create_cast (unsigned_char_type_node, fill_value_sval);
575 const region *sized_dest_reg = m_mgr->get_sized_region (dest_reg,
576 NULL_TREE,
577 num_bytes_sval);
578 check_region_for_write (sized_dest_reg, cd.get_ctxt ());
579 fill_region (sized_dest_reg, fill_value_u8);
582 /* Handle the on_call_post part of "pipe". */
584 void
585 region_model::impl_call_pipe (const call_details &cd)
587 class failure : public failed_call_info
589 public:
590 failure (const call_details &cd) : failed_call_info (cd) {}
592 bool update_model (region_model *model,
593 const exploded_edge *,
594 region_model_context *ctxt) const final override
596 /* Return -1; everything else is unchanged. */
597 const call_details cd (get_call_details (model, ctxt));
598 model->update_for_int_cst_return (cd, -1, true);
599 return true;
603 class success : public success_call_info
605 public:
606 success (const call_details &cd) : success_call_info (cd) {}
608 bool update_model (region_model *model,
609 const exploded_edge *,
610 region_model_context *ctxt) const final override
612 const call_details cd (get_call_details (model, ctxt));
614 /* Return 0. */
615 model->update_for_zero_return (cd, true);
617 /* Update fd array. */
618 region_model_manager *mgr = cd.get_manager ();
619 tree arr_tree = cd.get_arg_tree (0);
620 const svalue *arr_sval = cd.get_arg_svalue (0);
621 for (int idx = 0; idx < 2; idx++)
623 const region *arr_reg
624 = model->deref_rvalue (arr_sval, arr_tree, cd.get_ctxt ());
625 const svalue *idx_sval
626 = mgr->get_or_create_int_cst (integer_type_node, idx);
627 const region *element_reg
628 = mgr->get_element_region (arr_reg, integer_type_node, idx_sval);
629 conjured_purge p (model, cd.get_ctxt ());
630 const svalue *fd_sval
631 = mgr->get_or_create_conjured_svalue (integer_type_node,
632 cd.get_call_stmt (),
633 element_reg,
635 model->set_value (element_reg, fd_sval, cd.get_ctxt ());
636 model->mark_as_valid_fd (fd_sval, cd.get_ctxt ());
639 return true;
643 /* Body of region_model::impl_call_pipe. */
644 if (cd.get_ctxt ())
646 cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
647 cd.get_ctxt ()->bifurcate (make_unique<success> (cd));
648 cd.get_ctxt ()->terminate_path ();
652 /* A subclass of pending_diagnostic for complaining about 'putenv'
653 called on an auto var. */
655 class putenv_of_auto_var
656 : public pending_diagnostic_subclass<putenv_of_auto_var>
658 public:
659 putenv_of_auto_var (tree fndecl, const region *reg)
660 : m_fndecl (fndecl), m_reg (reg),
661 m_var_decl (reg->get_base_region ()->maybe_get_decl ())
665 const char *get_kind () const final override
667 return "putenv_of_auto_var";
670 bool operator== (const putenv_of_auto_var &other) const
672 return (m_fndecl == other.m_fndecl
673 && m_reg == other.m_reg
674 && same_tree_p (m_var_decl, other.m_var_decl));
677 int get_controlling_option () const final override
679 return OPT_Wanalyzer_putenv_of_auto_var;
682 bool emit (rich_location *rich_loc) final override
684 auto_diagnostic_group d;
685 diagnostic_metadata m;
687 /* SEI CERT C Coding Standard: "POS34-C. Do not call putenv() with a
688 pointer to an automatic variable as the argument". */
689 diagnostic_metadata::precanned_rule
690 rule ("POS34-C", "https://wiki.sei.cmu.edu/confluence/x/6NYxBQ");
691 m.add_rule (rule);
693 bool warned;
694 if (m_var_decl)
695 warned = warning_meta (rich_loc, m, get_controlling_option (),
696 "%qE on a pointer to automatic variable %qE",
697 m_fndecl, m_var_decl);
698 else
699 warned = warning_meta (rich_loc, m, get_controlling_option (),
700 "%qE on a pointer to an on-stack buffer",
701 m_fndecl);
702 if (warned)
704 if (m_var_decl)
705 inform (DECL_SOURCE_LOCATION (m_var_decl),
706 "%qE declared on stack here", m_var_decl);
707 inform (rich_loc->get_loc (), "perhaps use %qs rather than %qE",
708 "setenv", m_fndecl);
711 return warned;
714 label_text describe_final_event (const evdesc::final_event &ev) final override
716 if (m_var_decl)
717 return ev.formatted_print ("%qE on a pointer to automatic variable %qE",
718 m_fndecl, m_var_decl);
719 else
720 return ev.formatted_print ("%qE on a pointer to an on-stack buffer",
721 m_fndecl);
724 void mark_interesting_stuff (interesting_t *interest) final override
726 if (!m_var_decl)
727 interest->add_region_creation (m_reg->get_base_region ());
730 private:
731 tree m_fndecl; // non-NULL
732 const region *m_reg; // non-NULL
733 tree m_var_decl; // could be NULL
736 /* Handle the on_call_pre part of "putenv".
738 In theory we could try to model the state of the environment variables
739 for the process; for now we merely complain about putenv of regions
740 on the stack. */
742 void
743 region_model::impl_call_putenv (const call_details &cd)
745 tree fndecl = cd.get_fndecl_for_call ();
746 gcc_assert (fndecl);
747 region_model_context *ctxt = cd.get_ctxt ();
748 const svalue *ptr_sval = cd.get_arg_svalue (0);
749 const region *reg = deref_rvalue (ptr_sval, cd.get_arg_tree (0), ctxt);
750 m_store.mark_as_escaped (reg);
751 enum memory_space mem_space = reg->get_memory_space ();
752 switch (mem_space)
754 default:
755 gcc_unreachable ();
756 case MEMSPACE_UNKNOWN:
757 case MEMSPACE_CODE:
758 case MEMSPACE_GLOBALS:
759 case MEMSPACE_HEAP:
760 case MEMSPACE_READONLY_DATA:
761 break;
762 case MEMSPACE_STACK:
763 if (ctxt)
764 ctxt->warn (make_unique<putenv_of_auto_var> (fndecl, reg));
765 break;
769 /* Handle the on_call_pre part of "operator new". */
771 void
772 region_model::impl_call_operator_new (const call_details &cd)
774 const svalue *size_sval = cd.get_arg_svalue (0);
775 const region *new_reg
776 = create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
777 if (cd.get_lhs_type ())
779 const svalue *ptr_sval
780 = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
781 cd.maybe_set_lhs (ptr_sval);
785 /* Handle the on_call_pre part of "operator delete", which comes in
786 both sized and unsized variants (2 arguments and 1 argument
787 respectively). */
789 void
790 region_model::impl_call_operator_delete (const call_details &cd)
792 const svalue *ptr_sval = cd.get_arg_svalue (0);
793 if (const region *freed_reg = ptr_sval->maybe_get_region ())
795 /* If the ptr points to an underlying heap region, delete it,
796 poisoning pointers. */
797 unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
801 /* Handle the on_call_post part of "realloc":
803 void *realloc(void *ptr, size_t size);
805 realloc(3) is awkward, since it has various different outcomes
806 that are best modelled as separate exploded nodes/edges.
808 We first check for sm-state, in
809 malloc_state_machine::on_realloc_call, so that we
810 can complain about issues such as realloc of a non-heap
811 pointer, and terminate the path for such cases (and issue
812 the complaints at the call's exploded node).
814 Assuming that these checks pass, we split the path here into
815 three special cases (and terminate the "standard" path):
816 (A) failure, returning NULL
817 (B) success, growing the buffer in-place without moving it
818 (C) success, allocating a new buffer, copying the content
819 of the old buffer to it, and freeing the old buffer.
821 Each of these has a custom_edge_info subclass, which updates
822 the region_model and sm-state of the destination state. */
824 void
825 region_model::impl_call_realloc (const call_details &cd)
827 /* Three custom subclasses of custom_edge_info, for handling the various
828 outcomes of "realloc". */
830 /* Concrete custom_edge_info: a realloc call that fails, returning NULL. */
831 class failure : public failed_call_info
833 public:
834 failure (const call_details &cd)
835 : failed_call_info (cd)
839 bool update_model (region_model *model,
840 const exploded_edge *,
841 region_model_context *ctxt) const final override
843 /* Return NULL; everything else is unchanged. */
844 const call_details cd (get_call_details (model, ctxt));
845 if (cd.get_lhs_type ())
847 const svalue *zero
848 = model->m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
849 model->set_value (cd.get_lhs_region (),
850 zero,
851 cd.get_ctxt ());
853 return true;
857 /* Concrete custom_edge_info: a realloc call that succeeds, growing
858 the existing buffer without moving it. */
859 class success_no_move : public call_info
861 public:
862 success_no_move (const call_details &cd)
863 : call_info (cd)
867 label_text get_desc (bool can_colorize) const final override
869 return make_label_text (can_colorize,
870 "when %qE succeeds, without moving buffer",
871 get_fndecl ());
874 bool update_model (region_model *model,
875 const exploded_edge *,
876 region_model_context *ctxt) const final override
878 /* Update size of buffer and return the ptr unchanged. */
879 const call_details cd (get_call_details (model, ctxt));
880 const svalue *ptr_sval = cd.get_arg_svalue (0);
881 const svalue *size_sval = cd.get_arg_svalue (1);
883 /* We can only grow in place with a non-NULL pointer. */
885 const svalue *null_ptr
886 = model->m_mgr->get_or_create_int_cst (ptr_sval->get_type (), 0);
887 if (!model->add_constraint (ptr_sval, NE_EXPR, null_ptr,
888 cd.get_ctxt ()))
889 return false;
892 if (const region *buffer_reg = model->deref_rvalue (ptr_sval, NULL_TREE,
893 ctxt))
894 if (compat_types_p (size_sval->get_type (), size_type_node))
895 model->set_dynamic_extents (buffer_reg, size_sval, ctxt);
896 if (cd.get_lhs_region ())
898 model->set_value (cd.get_lhs_region (), ptr_sval, cd.get_ctxt ());
899 const svalue *zero
900 = model->m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
901 return model->add_constraint (ptr_sval, NE_EXPR, zero, cd.get_ctxt ());
903 else
904 return true;
908 /* Concrete custom_edge_info: a realloc call that succeeds, freeing
909 the existing buffer and moving the content to a freshly allocated
910 buffer. */
911 class success_with_move : public call_info
913 public:
914 success_with_move (const call_details &cd)
915 : call_info (cd)
919 label_text get_desc (bool can_colorize) const final override
921 return make_label_text (can_colorize,
922 "when %qE succeeds, moving buffer",
923 get_fndecl ());
925 bool update_model (region_model *model,
926 const exploded_edge *,
927 region_model_context *ctxt) const final override
929 const call_details cd (get_call_details (model, ctxt));
930 const svalue *old_ptr_sval = cd.get_arg_svalue (0);
931 const svalue *new_size_sval = cd.get_arg_svalue (1);
933 /* Create the new region. */
934 const region *new_reg
935 = model->create_region_for_heap_alloc (new_size_sval, ctxt);
936 const svalue *new_ptr_sval
937 = model->m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
938 if (!model->add_constraint (new_ptr_sval, NE_EXPR, old_ptr_sval,
939 cd.get_ctxt ()))
940 return false;
942 if (cd.get_lhs_type ())
943 cd.maybe_set_lhs (new_ptr_sval);
945 if (const region *freed_reg = model->deref_rvalue (old_ptr_sval,
946 NULL_TREE, ctxt))
948 /* Copy the data. */
949 const svalue *old_size_sval = model->get_dynamic_extents (freed_reg);
950 if (old_size_sval)
952 const svalue *copied_size_sval
953 = get_copied_size (model, old_size_sval, new_size_sval);
954 const region *copied_old_reg
955 = model->m_mgr->get_sized_region (freed_reg, NULL,
956 copied_size_sval);
957 const svalue *buffer_content_sval
958 = model->get_store_value (copied_old_reg, cd.get_ctxt ());
959 const region *copied_new_reg
960 = model->m_mgr->get_sized_region (new_reg, NULL,
961 copied_size_sval);
962 model->set_value (copied_new_reg, buffer_content_sval,
963 cd.get_ctxt ());
965 else
967 /* We don't know how big the old region was;
968 mark the new region as having been touched to avoid uninit
969 issues. */
970 model->mark_region_as_unknown (new_reg, cd.get_uncertainty ());
973 /* Free the old region, so that pointers to the old buffer become
974 invalid. */
976 /* If the ptr points to an underlying heap region, delete it,
977 poisoning pointers. */
978 model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
979 model->m_dynamic_extents.remove (freed_reg);
982 /* Update the sm-state: mark the old_ptr_sval as "freed",
983 and the new_ptr_sval as "nonnull". */
984 model->on_realloc_with_move (cd, old_ptr_sval, new_ptr_sval);
986 if (cd.get_lhs_type ())
988 const svalue *zero
989 = model->m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
990 return model->add_constraint (new_ptr_sval, NE_EXPR, zero,
991 cd.get_ctxt ());
993 else
994 return true;
997 private:
998 /* Return the lesser of OLD_SIZE_SVAL and NEW_SIZE_SVAL.
999 If unknown, OLD_SIZE_SVAL is returned. */
1000 const svalue *get_copied_size (region_model *model,
1001 const svalue *old_size_sval,
1002 const svalue *new_size_sval) const
1004 tristate res
1005 = model->eval_condition (old_size_sval, GT_EXPR, new_size_sval);
1006 switch (res.get_value ())
1008 case tristate::TS_TRUE:
1009 return new_size_sval;
1010 case tristate::TS_FALSE:
1011 case tristate::TS_UNKNOWN:
1012 return old_size_sval;
1013 default:
1014 gcc_unreachable ();
1019 /* Body of region_model::impl_call_realloc. */
1021 if (cd.get_ctxt ())
1023 cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
1024 cd.get_ctxt ()->bifurcate (make_unique<success_no_move> (cd));
1025 cd.get_ctxt ()->bifurcate (make_unique<success_with_move> (cd));
1026 cd.get_ctxt ()->terminate_path ();
1030 /* Handle the on_call_post part of "strchr" and "__builtin_strchr". */
1032 void
1033 region_model::impl_call_strchr (const call_details &cd)
1035 class strchr_call_info : public call_info
1037 public:
1038 strchr_call_info (const call_details &cd, bool found)
1039 : call_info (cd), m_found (found)
1043 label_text get_desc (bool can_colorize) const final override
1045 if (m_found)
1046 return make_label_text (can_colorize,
1047 "when %qE returns non-NULL",
1048 get_fndecl ());
1049 else
1050 return make_label_text (can_colorize,
1051 "when %qE returns NULL",
1052 get_fndecl ());
1055 bool update_model (region_model *model,
1056 const exploded_edge *,
1057 region_model_context *ctxt) const final override
1059 const call_details cd (get_call_details (model, ctxt));
1060 if (tree lhs_type = cd.get_lhs_type ())
1062 region_model_manager *mgr = model->get_manager ();
1063 const svalue *result;
1064 if (m_found)
1066 const svalue *str_sval = cd.get_arg_svalue (0);
1067 const region *str_reg
1068 = model->deref_rvalue (str_sval, cd.get_arg_tree (0),
1069 cd.get_ctxt ());
1070 /* We want str_sval + OFFSET for some unknown OFFSET.
1071 Use a conjured_svalue to represent the offset,
1072 using the str_reg as the id of the conjured_svalue. */
1073 const svalue *offset
1074 = mgr->get_or_create_conjured_svalue (size_type_node,
1075 cd.get_call_stmt (),
1076 str_reg,
1077 conjured_purge (model,
1078 ctxt));
1079 result = mgr->get_or_create_binop (lhs_type, POINTER_PLUS_EXPR,
1080 str_sval, offset);
1082 else
1083 result = mgr->get_or_create_int_cst (lhs_type, 0);
1084 cd.maybe_set_lhs (result);
1086 return true;
1088 private:
1089 bool m_found;
1092 /* Body of region_model::impl_call_strchr. */
1093 if (cd.get_ctxt ())
1095 cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, false));
1096 cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, true));
1097 cd.get_ctxt ()->terminate_path ();
1101 /* Handle the on_call_pre part of "strcpy" and "__builtin_strcpy_chk". */
1103 void
1104 region_model::impl_call_strcpy (const call_details &cd)
1106 const svalue *dest_sval = cd.get_arg_svalue (0);
1107 const region *dest_reg = deref_rvalue (dest_sval, cd.get_arg_tree (0),
1108 cd.get_ctxt ());
1109 const svalue *src_sval = cd.get_arg_svalue (1);
1110 const region *src_reg = deref_rvalue (src_sval, cd.get_arg_tree (1),
1111 cd.get_ctxt ());
1112 const svalue *src_contents_sval = get_store_value (src_reg,
1113 cd.get_ctxt ());
1115 cd.maybe_set_lhs (dest_sval);
1117 /* Try to get the string size if SRC_REG is a string_region. */
1118 const svalue *copied_bytes_sval = get_string_size (src_reg);
1119 /* Otherwise, check if the contents of SRC_REG is a string. */
1120 if (copied_bytes_sval->get_kind () == SK_UNKNOWN)
1121 copied_bytes_sval = get_string_size (src_contents_sval);
1123 const region *sized_dest_reg
1124 = m_mgr->get_sized_region (dest_reg, NULL_TREE, copied_bytes_sval);
1125 set_value (sized_dest_reg, src_contents_sval, cd.get_ctxt ());
1128 /* Handle the on_call_pre part of "strlen". */
1130 void
1131 region_model::impl_call_strlen (const call_details &cd)
1133 region_model_context *ctxt = cd.get_ctxt ();
1134 const svalue *arg_sval = cd.get_arg_svalue (0);
1135 const region *buf_reg = deref_rvalue (arg_sval, cd.get_arg_tree (0), ctxt);
1136 if (const string_region *str_reg
1137 = buf_reg->dyn_cast_string_region ())
1139 tree str_cst = str_reg->get_string_cst ();
1140 /* TREE_STRING_LENGTH is sizeof, not strlen. */
1141 int sizeof_cst = TREE_STRING_LENGTH (str_cst);
1142 int strlen_cst = sizeof_cst - 1;
1143 if (cd.get_lhs_type ())
1145 tree t_cst = build_int_cst (cd.get_lhs_type (), strlen_cst);
1146 const svalue *result_sval
1147 = m_mgr->get_or_create_constant_svalue (t_cst);
1148 cd.maybe_set_lhs (result_sval);
1149 return;
1152 /* Otherwise a conjured value. */
1155 /* Handle calls to functions referenced by
1156 __attribute__((malloc(FOO))). */
1158 void
1159 region_model::impl_deallocation_call (const call_details &cd)
1161 impl_call_free (cd);
1164 } // namespace ana
1166 #endif /* #if ENABLE_ANALYZER */