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 "__errno_location". */
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 (),
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). */
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
)
446 /* Initial argument ought to be of type "int". */
447 if (cd
.get_arg_type (0) != integer_type_node
)
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;
460 /* Handle the on_call_pre part of "fgets" and "fgets_unlocked". */
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". */
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
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". */
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.
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),
546 const region
*src_reg
= deref_rvalue (src_ptr_sval
, cd
.get_arg_tree (1),
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". */
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),
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
,
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". */
585 region_model::impl_call_pipe (const call_details
&cd
)
587 class failure
: public failed_call_info
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);
603 class success
: public success_call_info
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
));
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
,
635 model
->set_value (element_reg
, fd_sval
, cd
.get_ctxt ());
636 model
->mark_as_valid_fd (fd_sval
, cd
.get_ctxt ());
643 /* Body of region_model::impl_call_pipe. */
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
>
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");
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
);
699 warned
= warning_meta (rich_loc
, m
, get_controlling_option (),
700 "%qE on a pointer to an on-stack buffer",
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",
714 label_text
describe_final_event (const evdesc::final_event
&ev
) final override
717 return ev
.formatted_print ("%qE on a pointer to automatic variable %qE",
718 m_fndecl
, m_var_decl
);
720 return ev
.formatted_print ("%qE on a pointer to an on-stack buffer",
724 void mark_interesting_stuff (interesting_t
*interest
) final override
727 interest
->add_region_creation (m_reg
->get_base_region ());
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
743 region_model::impl_call_putenv (const call_details
&cd
)
745 tree fndecl
= cd
.get_fndecl_for_call ();
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 ();
756 case MEMSPACE_UNKNOWN
:
758 case MEMSPACE_GLOBALS
:
760 case MEMSPACE_READONLY_DATA
:
764 ctxt
->warn (make_unique
<putenv_of_auto_var
> (fndecl
, reg
));
769 /* Handle the on_call_pre part of "operator new". */
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
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. */
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
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 ())
848 = model
->m_mgr
->get_or_create_int_cst (cd
.get_lhs_type (), 0);
849 model
->set_value (cd
.get_lhs_region (),
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
862 success_no_move (const call_details
&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",
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
,
892 if (const region
*buffer_reg
= model
->deref_rvalue (ptr_sval
, NULL_TREE
,
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 ());
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 ());
908 /* Concrete custom_edge_info: a realloc call that succeeds, freeing
909 the existing buffer and moving the content to a freshly allocated
911 class success_with_move
: public call_info
914 success_with_move (const call_details
&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",
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
,
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
,
949 const svalue
*old_size_sval
= model
->get_dynamic_extents (freed_reg
);
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
,
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
,
962 model
->set_value (copied_new_reg
, buffer_content_sval
,
967 /* We don't know how big the old region was;
968 mark the new region as having been touched to avoid uninit
970 model
->mark_region_as_unknown (new_reg
, cd
.get_uncertainty ());
973 /* Free the old region, so that pointers to the old buffer become
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 ())
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
,
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
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
;
1019 /* Body of region_model::impl_call_realloc. */
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". */
1033 region_model::impl_call_strchr (const call_details
&cd
)
1035 class strchr_call_info
: public call_info
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
1046 return make_label_text (can_colorize
,
1047 "when %qE returns non-NULL",
1050 return make_label_text (can_colorize
,
1051 "when %qE returns NULL",
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
;
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),
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 (),
1077 conjured_purge (model
,
1079 result
= mgr
->get_or_create_binop (lhs_type
, POINTER_PLUS_EXPR
,
1083 result
= mgr
->get_or_create_int_cst (lhs_type
, 0);
1084 cd
.maybe_set_lhs (result
);
1092 /* Body of region_model::impl_call_strchr. */
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". */
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),
1109 const svalue
*src_sval
= cd
.get_arg_svalue (1);
1110 const region
*src_reg
= deref_rvalue (src_sval
, cd
.get_arg_tree (1),
1112 const svalue
*src_contents_sval
= get_store_value (src_reg
,
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". */
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
);
1152 /* Otherwise a conjured value. */
1155 /* Handle calls to functions referenced by
1156 __attribute__((malloc(FOO))). */
1159 region_model::impl_deallocation_call (const call_details
&cd
)
1161 impl_call_free (cd
);
1166 #endif /* #if ENABLE_ANALYZER */