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)
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/>. */
22 #define INCLUDE_MEMORY
24 #include "coretypes.h"
27 #include "basic-block.h"
29 #include "gimple-iterator.h"
30 #include "diagnostic-core.h"
35 #include "stringpool.h"
38 #include "fold-const.h"
39 #include "tree-pretty-print.h"
40 #include "diagnostic-color.h"
41 #include "diagnostic-metadata.h"
43 #include "analyzer/analyzer.h"
44 #include "analyzer/analyzer-logging.h"
45 #include "ordered-hash-map.h"
47 #include "analyzer/supergraph.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"
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. */
92 call_details::get_logger () const
95 return m_ctxt->get_logger ();
100 /* Get any uncertainty_t associated with the region_model_context. */
103 call_details::get_uncertainty () const
106 return m_ctxt->get_uncertainty ();
111 /* If the callsite has a left-hand-side region, set it to RESULT
113 Otherwise do nothing and return false. */
116 call_details::maybe_set_lhs (const svalue *result) const
121 m_model->set_value (m_lhs_region, result, m_ctxt);
128 /* Return the number of arguments used by the call statement. */
131 call_details::num_args () const
133 return gimple_call_num_args (m_call);
136 /* Get argument IDX at the callsite as a 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. */
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. */
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
163 For use when implementing "__analyzer_*" functions that take
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);
179 /* Attempt to get the fndecl used at this call, if known, or NULL_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. */
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 */);
196 pp_string (pp, "return region: ");
198 m_lhs_region->dump_to_pp (pp, simple);
200 pp_string (pp, "NULL");
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);
211 /* Dump a multiline representation of this call to stderr. */
214 call_details::dump (bool simple) const
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);
224 /* Get a conjured_svalue for this call for REG,
225 and purge any state already relating to that conjured_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". */
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. */
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. */
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. */
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))))
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. */
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. */
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 ())
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);
337 pp_format_decoder (&pp) = default_tree_printer;
338 pp_show_color (&pp) = pp_show_color (global_dc->printer);
340 for (auto iter : escaped_decls)
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. */
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". */
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. */
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". */
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 "error" and "error_at_line" from
417 GNU's non-standard <error.h>.
418 MIN_ARGS identifies the minimum number of expected arguments
419 to be consistent with such a call (3 and 5 respectively).
420 Return true if handling it as one of these functions.
421 Write true to *OUT_TERMINATE_PATH if this execution path should be
422 terminated (e.g. the function call terminates the process). */
425 region_model::impl_call_error (const call_details &cd, unsigned min_args,
426 bool *out_terminate_path)
428 /* Bail if not enough args. */
429 if (cd.num_args () < min_args)
432 /* Initial argument ought to be of type "int". */
433 if (cd.get_arg_type (0) != integer_type_node)
436 /* The process exits if status != 0, so it only continues
437 for the case where status == 0.
438 Add that constraint, or terminate this analysis path. */
439 tree status = cd.get_arg_tree (0);
440 if (!add_constraint (status, EQ_EXPR, integer_zero_node, cd.get_ctxt ()))
441 *out_terminate_path = true;
446 /* Handle the on_call_pre part of "fgets" and "fgets_unlocked". */
449 region_model::impl_call_fgets (const call_details &cd)
451 /* Ideally we would bifurcate state here between the
452 error vs no error cases. */
453 const svalue *ptr_sval = cd.get_arg_svalue (0);
454 if (const region *reg = ptr_sval->maybe_get_region ())
456 const region *base_reg = reg->get_base_region ();
457 const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg);
458 set_value (base_reg, new_sval, cd.get_ctxt ());
462 /* Handle the on_call_pre part of "fread". */
465 region_model::impl_call_fread (const call_details &cd)
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_post part of "free", after sm-handling.
478 If the ptr points to an underlying heap region, delete the region,
479 poisoning pointers to it and regions within it.
481 We delay this until after sm-state has been updated so that the
482 sm-handling can transition all of the various casts of the pointer
483 to a "freed" state *before* we delete the related region here.
485 This has to be done here so that the sm-handling can use the fact
486 that they point to the same region to establish that they are equal
487 (in region_model::eval_condition_without_cm), and thus transition
488 all pointers to the region to the "freed" state together, regardless
492 region_model::impl_call_free (const call_details &cd)
494 const svalue *ptr_sval = cd.get_arg_svalue (0);
495 if (const region *freed_reg = ptr_sval->maybe_get_region ())
497 /* If the ptr points to an underlying heap region, delete it,
498 poisoning pointers. */
499 unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
500 m_dynamic_extents.remove (freed_reg);
504 /* Handle the on_call_pre part of "malloc". */
507 region_model::impl_call_malloc (const call_details &cd)
509 const svalue *size_sval = cd.get_arg_svalue (0);
510 const region *new_reg
511 = create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
512 if (cd.get_lhs_type ())
514 const svalue *ptr_sval
515 = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
516 cd.maybe_set_lhs (ptr_sval);
520 /* Handle the on_call_pre part of "memcpy" and "__builtin_memcpy". */
521 // TODO: complain about overlapping src and dest.
524 region_model::impl_call_memcpy (const call_details &cd)
526 const svalue *dest_ptr_sval = cd.get_arg_svalue (0);
527 const svalue *src_ptr_sval = cd.get_arg_svalue (1);
528 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
530 const region *dest_reg = deref_rvalue (dest_ptr_sval, cd.get_arg_tree (0),
532 const region *src_reg = deref_rvalue (src_ptr_sval, cd.get_arg_tree (1),
535 cd.maybe_set_lhs (dest_ptr_sval);
537 const region *sized_src_reg
538 = m_mgr->get_sized_region (src_reg, NULL_TREE, num_bytes_sval);
539 const region *sized_dest_reg
540 = m_mgr->get_sized_region (dest_reg, NULL_TREE, num_bytes_sval);
541 const svalue *src_contents_sval
542 = get_store_value (sized_src_reg, cd.get_ctxt ());
543 set_value (sized_dest_reg, src_contents_sval, cd.get_ctxt ());
546 /* Handle the on_call_pre part of "memset" and "__builtin_memset". */
549 region_model::impl_call_memset (const call_details &cd)
551 const svalue *dest_sval = cd.get_arg_svalue (0);
552 const svalue *fill_value_sval = cd.get_arg_svalue (1);
553 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
555 const region *dest_reg = deref_rvalue (dest_sval, cd.get_arg_tree (0),
558 const svalue *fill_value_u8
559 = m_mgr->get_or_create_cast (unsigned_char_type_node, fill_value_sval);
561 const region *sized_dest_reg = m_mgr->get_sized_region (dest_reg,
564 check_region_for_write (sized_dest_reg, cd.get_ctxt ());
565 fill_region (sized_dest_reg, fill_value_u8);
568 /* Handle the on_call_post part of "pipe". */
571 region_model::impl_call_pipe (const call_details &cd)
573 class failure : public failed_call_info
576 failure (const call_details &cd) : failed_call_info (cd) {}
578 bool update_model (region_model *model,
579 const exploded_edge *,
580 region_model_context *ctxt) const final override
582 /* Return -1; everything else is unchanged. */
583 const call_details cd (get_call_details (model, ctxt));
584 model->update_for_int_cst_return (cd, -1, true);
589 class success : public success_call_info
592 success (const call_details &cd) : success_call_info (cd) {}
594 bool update_model (region_model *model,
595 const exploded_edge *,
596 region_model_context *ctxt) const final override
598 const call_details cd (get_call_details (model, ctxt));
601 model->update_for_zero_return (cd, true);
603 /* Update fd array. */
604 region_model_manager *mgr = cd.get_manager ();
605 tree arr_tree = cd.get_arg_tree (0);
606 const svalue *arr_sval = cd.get_arg_svalue (0);
607 for (int idx = 0; idx < 2; idx++)
609 const region *arr_reg
610 = model->deref_rvalue (arr_sval, arr_tree, cd.get_ctxt ());
611 const svalue *idx_sval
612 = mgr->get_or_create_int_cst (integer_type_node, idx);
613 const region *element_reg
614 = mgr->get_element_region (arr_reg, integer_type_node, idx_sval);
615 conjured_purge p (model, cd.get_ctxt ());
616 const svalue *fd_sval
617 = mgr->get_or_create_conjured_svalue (integer_type_node,
621 model->set_value (element_reg, fd_sval, cd.get_ctxt ());
622 model->mark_as_valid_fd (fd_sval, cd.get_ctxt ());
629 /* Body of region_model::impl_call_pipe. */
632 cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
633 cd.get_ctxt ()->bifurcate (make_unique<success> (cd));
634 cd.get_ctxt ()->terminate_path ();
638 /* A subclass of pending_diagnostic for complaining about 'putenv'
639 called on an auto var. */
641 class putenv_of_auto_var
642 : public pending_diagnostic_subclass<putenv_of_auto_var>
645 putenv_of_auto_var (tree fndecl, const region *reg)
646 : m_fndecl (fndecl), m_reg (reg),
647 m_var_decl (reg->get_base_region ()->maybe_get_decl ())
651 const char *get_kind () const final override
653 return "putenv_of_auto_var";
656 bool operator== (const putenv_of_auto_var &other) const
658 return (m_fndecl == other.m_fndecl
659 && m_reg == other.m_reg
660 && same_tree_p (m_var_decl, other.m_var_decl));
663 int get_controlling_option () const final override
665 return OPT_Wanalyzer_putenv_of_auto_var;
668 bool emit (rich_location *rich_loc) final override
670 auto_diagnostic_group d;
671 diagnostic_metadata m;
673 /* SEI CERT C Coding Standard: "POS34-C. Do not call putenv() with a
674 pointer to an automatic variable as the argument". */
675 diagnostic_metadata::precanned_rule
676 rule ("POS34-C", "https://wiki.sei.cmu.edu/confluence/x/6NYxBQ");
681 warned = warning_meta (rich_loc, m, get_controlling_option (),
682 "%qE on a pointer to automatic variable %qE",
683 m_fndecl, m_var_decl);
685 warned = warning_meta (rich_loc, m, get_controlling_option (),
686 "%qE on a pointer to an on-stack buffer",
691 inform (DECL_SOURCE_LOCATION (m_var_decl),
692 "%qE declared on stack here", m_var_decl);
693 inform (rich_loc->get_loc (), "perhaps use %qs rather than %qE",
700 label_text describe_final_event (const evdesc::final_event &ev) final override
703 return ev.formatted_print ("%qE on a pointer to automatic variable %qE",
704 m_fndecl, m_var_decl);
706 return ev.formatted_print ("%qE on a pointer to an on-stack buffer",
710 void mark_interesting_stuff (interesting_t *interest) final override
713 interest->add_region_creation (m_reg->get_base_region ());
717 tree m_fndecl; // non-NULL
718 const region *m_reg; // non-NULL
719 tree m_var_decl; // could be NULL
722 /* Handle the on_call_pre part of "putenv".
724 In theory we could try to model the state of the environment variables
725 for the process; for now we merely complain about putenv of regions
729 region_model::impl_call_putenv (const call_details &cd)
731 tree fndecl = cd.get_fndecl_for_call ();
733 region_model_context *ctxt = cd.get_ctxt ();
734 const svalue *ptr_sval = cd.get_arg_svalue (0);
735 const region *reg = deref_rvalue (ptr_sval, cd.get_arg_tree (0), ctxt);
736 m_store.mark_as_escaped (reg);
737 enum memory_space mem_space = reg->get_memory_space ();
742 case MEMSPACE_UNKNOWN:
744 case MEMSPACE_GLOBALS:
746 case MEMSPACE_READONLY_DATA:
750 ctxt->warn (make_unique<putenv_of_auto_var> (fndecl, reg));
755 /* Handle the on_call_pre part of "operator new". */
758 region_model::impl_call_operator_new (const call_details &cd)
760 const svalue *size_sval = cd.get_arg_svalue (0);
761 const region *new_reg
762 = create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
763 if (cd.get_lhs_type ())
765 const svalue *ptr_sval
766 = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
767 cd.maybe_set_lhs (ptr_sval);
771 /* Handle the on_call_pre part of "operator delete", which comes in
772 both sized and unsized variants (2 arguments and 1 argument
776 region_model::impl_call_operator_delete (const call_details &cd)
778 const svalue *ptr_sval = cd.get_arg_svalue (0);
779 if (const region *freed_reg = ptr_sval->maybe_get_region ())
781 /* If the ptr points to an underlying heap region, delete it,
782 poisoning pointers. */
783 unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
787 /* Handle the on_call_post part of "realloc":
789 void *realloc(void *ptr, size_t size);
791 realloc(3) is awkward, since it has various different outcomes
792 that are best modelled as separate exploded nodes/edges.
794 We first check for sm-state, in
795 malloc_state_machine::on_realloc_call, so that we
796 can complain about issues such as realloc of a non-heap
797 pointer, and terminate the path for such cases (and issue
798 the complaints at the call's exploded node).
800 Assuming that these checks pass, we split the path here into
801 three special cases (and terminate the "standard" path):
802 (A) failure, returning NULL
803 (B) success, growing the buffer in-place without moving it
804 (C) success, allocating a new buffer, copying the content
805 of the old buffer to it, and freeing the old buffer.
807 Each of these has a custom_edge_info subclass, which updates
808 the region_model and sm-state of the destination state. */
811 region_model::impl_call_realloc (const call_details &cd)
813 /* Three custom subclasses of custom_edge_info, for handling the various
814 outcomes of "realloc". */
816 /* Concrete custom_edge_info: a realloc call that fails, returning NULL. */
817 class failure : public failed_call_info
820 failure (const call_details &cd)
821 : failed_call_info (cd)
825 bool update_model (region_model *model,
826 const exploded_edge *,
827 region_model_context *ctxt) const final override
829 /* Return NULL; everything else is unchanged. */
830 const call_details cd (get_call_details (model, ctxt));
831 if (cd.get_lhs_type ())
834 = model->m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
835 model->set_value (cd.get_lhs_region (),
843 /* Concrete custom_edge_info: a realloc call that succeeds, growing
844 the existing buffer without moving it. */
845 class success_no_move : public call_info
848 success_no_move (const call_details &cd)
853 label_text get_desc (bool can_colorize) const final override
855 return make_label_text (can_colorize,
856 "when %qE succeeds, without moving buffer",
860 bool update_model (region_model *model,
861 const exploded_edge *,
862 region_model_context *ctxt) const final override
864 /* Update size of buffer and return the ptr unchanged. */
865 const call_details cd (get_call_details (model, ctxt));
866 const svalue *ptr_sval = cd.get_arg_svalue (0);
867 const svalue *size_sval = cd.get_arg_svalue (1);
869 /* We can only grow in place with a non-NULL pointer. */
871 const svalue *null_ptr
872 = model->m_mgr->get_or_create_int_cst (ptr_sval->get_type (), 0);
873 if (!model->add_constraint (ptr_sval, NE_EXPR, null_ptr,
878 if (const region *buffer_reg = model->deref_rvalue (ptr_sval, NULL_TREE,
880 if (compat_types_p (size_sval->get_type (), size_type_node))
881 model->set_dynamic_extents (buffer_reg, size_sval, ctxt);
882 if (cd.get_lhs_region ())
884 model->set_value (cd.get_lhs_region (), ptr_sval, cd.get_ctxt ());
886 = model->m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
887 return model->add_constraint (ptr_sval, NE_EXPR, zero, cd.get_ctxt ());
894 /* Concrete custom_edge_info: a realloc call that succeeds, freeing
895 the existing buffer and moving the content to a freshly allocated
897 class success_with_move : public call_info
900 success_with_move (const call_details &cd)
905 label_text get_desc (bool can_colorize) const final override
907 return make_label_text (can_colorize,
908 "when %qE succeeds, moving buffer",
911 bool update_model (region_model *model,
912 const exploded_edge *,
913 region_model_context *ctxt) const final override
915 const call_details cd (get_call_details (model, ctxt));
916 const svalue *old_ptr_sval = cd.get_arg_svalue (0);
917 const svalue *new_size_sval = cd.get_arg_svalue (1);
919 /* Create the new region. */
920 const region *new_reg
921 = model->create_region_for_heap_alloc (new_size_sval, ctxt);
922 const svalue *new_ptr_sval
923 = model->m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
924 if (!model->add_constraint (new_ptr_sval, NE_EXPR, old_ptr_sval,
928 if (cd.get_lhs_type ())
929 cd.maybe_set_lhs (new_ptr_sval);
931 if (const region *freed_reg = model->deref_rvalue (old_ptr_sval,
935 const svalue *old_size_sval = model->get_dynamic_extents (freed_reg);
938 const svalue *copied_size_sval
939 = get_copied_size (model, old_size_sval, new_size_sval);
940 const region *copied_old_reg
941 = model->m_mgr->get_sized_region (freed_reg, NULL,
943 const svalue *buffer_content_sval
944 = model->get_store_value (copied_old_reg, cd.get_ctxt ());
945 const region *copied_new_reg
946 = model->m_mgr->get_sized_region (new_reg, NULL,
948 model->set_value (copied_new_reg, buffer_content_sval,
953 /* We don't know how big the old region was;
954 mark the new region as having been touched to avoid uninit
956 model->mark_region_as_unknown (new_reg, cd.get_uncertainty ());
959 /* Free the old region, so that pointers to the old buffer become
962 /* If the ptr points to an underlying heap region, delete it,
963 poisoning pointers. */
964 model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
965 model->m_dynamic_extents.remove (freed_reg);
968 /* Update the sm-state: mark the old_ptr_sval as "freed",
969 and the new_ptr_sval as "nonnull". */
970 model->on_realloc_with_move (cd, old_ptr_sval, new_ptr_sval);
972 if (cd.get_lhs_type ())
975 = model->m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
976 return model->add_constraint (new_ptr_sval, NE_EXPR, zero,
984 /* Return the lesser of OLD_SIZE_SVAL and NEW_SIZE_SVAL.
985 If unknown, OLD_SIZE_SVAL is returned. */
986 const svalue *get_copied_size (region_model *model,
987 const svalue *old_size_sval,
988 const svalue *new_size_sval) const
991 = model->eval_condition (old_size_sval, GT_EXPR, new_size_sval);
992 switch (res.get_value ())
994 case tristate::TS_TRUE:
995 return new_size_sval;
996 case tristate::TS_FALSE:
997 case tristate::TS_UNKNOWN:
998 return old_size_sval;
1005 /* Body of region_model::impl_call_realloc. */
1009 cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
1010 cd.get_ctxt ()->bifurcate (make_unique<success_no_move> (cd));
1011 cd.get_ctxt ()->bifurcate (make_unique<success_with_move> (cd));
1012 cd.get_ctxt ()->terminate_path ();
1016 /* Handle the on_call_post part of "strchr" and "__builtin_strchr". */
1019 region_model::impl_call_strchr (const call_details &cd)
1021 class strchr_call_info : public call_info
1024 strchr_call_info (const call_details &cd, bool found)
1025 : call_info (cd), m_found (found)
1029 label_text get_desc (bool can_colorize) const final override
1032 return make_label_text (can_colorize,
1033 "when %qE returns non-NULL",
1036 return make_label_text (can_colorize,
1037 "when %qE returns NULL",
1041 bool update_model (region_model *model,
1042 const exploded_edge *,
1043 region_model_context *ctxt) const final override
1045 const call_details cd (get_call_details (model, ctxt));
1046 if (tree lhs_type = cd.get_lhs_type ())
1048 region_model_manager *mgr = model->get_manager ();
1049 const svalue *result;
1052 const svalue *str_sval = cd.get_arg_svalue (0);
1053 const region *str_reg
1054 = model->deref_rvalue (str_sval, cd.get_arg_tree (0),
1056 /* We want str_sval + OFFSET for some unknown OFFSET.
1057 Use a conjured_svalue to represent the offset,
1058 using the str_reg as the id of the conjured_svalue. */
1059 const svalue *offset
1060 = mgr->get_or_create_conjured_svalue (size_type_node,
1061 cd.get_call_stmt (),
1063 conjured_purge (model,
1065 result = mgr->get_or_create_binop (lhs_type, POINTER_PLUS_EXPR,
1069 result = mgr->get_or_create_int_cst (lhs_type, 0);
1070 cd.maybe_set_lhs (result);
1078 /* Body of region_model::impl_call_strchr. */
1081 cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, false));
1082 cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, true));
1083 cd.get_ctxt ()->terminate_path ();
1087 /* Handle the on_call_pre part of "strcpy" and "__builtin_strcpy_chk". */
1090 region_model::impl_call_strcpy (const call_details &cd)
1092 const svalue *dest_sval = cd.get_arg_svalue (0);
1093 const region *dest_reg = deref_rvalue (dest_sval, cd.get_arg_tree (0),
1095 const svalue *src_sval = cd.get_arg_svalue (1);
1096 const region *src_reg = deref_rvalue (src_sval, cd.get_arg_tree (1),
1098 const svalue *src_contents_sval = get_store_value (src_reg,
1101 cd.maybe_set_lhs (dest_sval);
1103 /* Try to get the string size if SRC_REG is a string_region. */
1104 const svalue *copied_bytes_sval = get_string_size (src_reg);
1105 /* Otherwise, check if the contents of SRC_REG is a string. */
1106 if (copied_bytes_sval->get_kind () == SK_UNKNOWN)
1107 copied_bytes_sval = get_string_size (src_contents_sval);
1109 const region *sized_dest_reg
1110 = m_mgr->get_sized_region (dest_reg, NULL_TREE, copied_bytes_sval);
1111 set_value (sized_dest_reg, src_contents_sval, cd.get_ctxt ());
1114 /* Handle the on_call_pre part of "strlen". */
1117 region_model::impl_call_strlen (const call_details &cd)
1119 region_model_context *ctxt = cd.get_ctxt ();
1120 const svalue *arg_sval = cd.get_arg_svalue (0);
1121 const region *buf_reg = deref_rvalue (arg_sval, cd.get_arg_tree (0), ctxt);
1122 if (const string_region *str_reg
1123 = buf_reg->dyn_cast_string_region ())
1125 tree str_cst = str_reg->get_string_cst ();
1126 /* TREE_STRING_LENGTH is sizeof, not strlen. */
1127 int sizeof_cst = TREE_STRING_LENGTH (str_cst);
1128 int strlen_cst = sizeof_cst - 1;
1129 if (cd.get_lhs_type ())
1131 tree t_cst = build_int_cst (cd.get_lhs_type (), strlen_cst);
1132 const svalue *result_sval
1133 = m_mgr->get_or_create_constant_svalue (t_cst);
1134 cd.maybe_set_lhs (result_sval);
1138 /* Otherwise a conjured value. */
1141 /* Handle calls to functions referenced by
1142 __attribute__((malloc(FOO))). */
1145 region_model::impl_deallocation_call (const call_details &cd)
1147 impl_call_free (cd);
1152 #endif /* #if ENABLE_ANALYZER */