46dbbb53bdc0e741d8069aa65f6d2054e72eb6af
[platform/upstream/gcc.git] / gcc / analyzer / region-model-impl-calls.cc
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>.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20
21 #include "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"
59
60 #if ENABLE_ANALYZER
61
62 namespace ana {
63
64 /* class call_details.  */
65
66 /* call_details's ctor.  */
67
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)
72 {
73   m_lhs_type = NULL_TREE;
74   if (tree lhs = gimple_call_lhs (call))
75     {
76       m_lhs_region = model->get_lvalue (lhs, ctxt);
77       m_lhs_type = TREE_TYPE (lhs);
78     }
79 }
80
81 /* Get the manager from m_model.  */
82
83 region_model_manager *
84 call_details::get_manager () const
85 {
86   return m_model->get_manager ();
87 }
88
89 /* Get any logger associated with this object.  */
90
91 logger *
92 call_details::get_logger () const
93 {
94   if (m_ctxt)
95     return m_ctxt->get_logger ();
96   else
97     return NULL;
98 }
99
100 /* Get any uncertainty_t associated with the region_model_context.  */
101
102 uncertainty_t *
103 call_details::get_uncertainty () const
104 {
105   if (m_ctxt)
106     return m_ctxt->get_uncertainty ();
107   else
108     return NULL;
109 }
110
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.  */
114
115 bool
116 call_details::maybe_set_lhs (const svalue *result) const
117 {
118   gcc_assert (result);
119   if (m_lhs_region)
120     {
121       m_model->set_value (m_lhs_region, result, m_ctxt);
122       return true;
123     }
124   else
125     return false;
126 }
127
128 /* Return the number of arguments used by the call statement.  */
129
130 unsigned
131 call_details::num_args () const
132 {
133   return gimple_call_num_args (m_call);
134 }
135
136 /* Get argument IDX at the callsite as a tree.  */
137
138 tree
139 call_details::get_arg_tree (unsigned idx) const
140 {
141   return gimple_call_arg (m_call, idx);
142 }
143
144 /* Get the type of argument IDX.  */
145
146 tree
147 call_details::get_arg_type (unsigned idx) const
148 {
149   return TREE_TYPE (gimple_call_arg (m_call, idx));
150 }
151
152 /* Get argument IDX at the callsite as an svalue.  */
153
154 const svalue *
155 call_details::get_arg_svalue (unsigned idx) const
156 {
157   tree arg = get_arg_tree (idx);
158   return m_model->get_rvalue (arg, m_ctxt);
159 }
160
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.  */
165
166 const char *
167 call_details::get_arg_string_literal (unsigned idx) const
168 {
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 ())
172       {
173         tree string_cst = string_reg->get_string_cst ();
174         return TREE_STRING_POINTER (string_cst);
175       }
176   return NULL;
177 }
178
179 /* Attempt to get the fndecl used at this call, if known, or NULL_TREE
180    otherwise.  */
181
182 tree
183 call_details::get_fndecl_for_call () const
184 {
185   return m_model->get_fndecl_for_call (m_call, m_ctxt);
186 }
187
188 /* Dump a multiline representation of this call to PP.  */
189
190 void
191 call_details::dump_to_pp (pretty_printer *pp, bool simple) const
192 {
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++)
203     {
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);
208     }
209 }
210
211 /* Dump a multiline representation of this call to stderr.  */
212
213 DEBUG_FUNCTION void
214 call_details::dump (bool simple) const
215 {
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);
222 }
223
224 /* Get a conjured_svalue for this call for REG,
225    and purge any state already relating to that conjured_svalue.  */
226
227 const svalue *
228 call_details::get_or_create_conjured_svalue (const region *reg) const
229 {
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));
233 }
234
235 /* Implementations of specific functions.  */
236
237 /* Handle the on_call_pre part of "alloca".  */
238
239 void
240 region_model::impl_call_alloca (const call_details &cd)
241 {
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);
247 }
248
249 /* Handle a call to "__analyzer_describe".
250
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.  */
254
255 void
256 region_model::impl_call_analyzer_describe (const gcall *call,
257                                            region_model_context *ctxt)
258 {
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 ());
265 }
266
267 /* Handle a call to "__analyzer_dump_capacity".
268
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.  */
272
273 void
274 region_model::impl_call_analyzer_dump_capacity (const gcall *call,
275                                                 region_model_context *ctxt)
276 {
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 ());
284 }
285
286 /* Compare D1 and D2 using their names, and then IDs to order them.  */
287
288 static int
289 cmp_decls (tree d1, tree d2)
290 {
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);
298 }
299
300 /* Comparator for use by vec<tree>::qsort,
301    using their names, and then IDs to order them.  */
302
303 static int
304 cmp_decls_ptr_ptr (const void *p1, const void *p2)
305 {
306   tree const *d1 = (tree const *)p1;
307   tree const *d2 = (tree const *)p2;
308
309   return cmp_decls (*d1, *d2);
310 }
311
312 /* Handle a call to "__analyzer_dump_escaped".
313
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.
316
317    This is for use when debugging, and may be of use in DejaGnu tests.  */
318
319 void
320 region_model::impl_call_analyzer_dump_escaped (const gcall *call)
321 {
322   auto_vec<tree> escaped_decls;
323   for (auto iter : m_store)
324     {
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);
330     }
331
332   /* Sort them into deterministic order; alphabetical is
333      probably most user-friendly.  */
334   escaped_decls.qsort (cmp_decls_ptr_ptr);
335
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)
341     {
342       if (first)
343         first = false;
344       else
345         pp_string (&pp, ", ");
346       pp_printf (&pp, "%qD", iter);
347     }
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));
353 }
354
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.  */
362
363 void
364 region_model::impl_call_analyzer_eval (const gcall *call,
365                                        region_model_context *ctxt)
366 {
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 ());
370 }
371
372 /* Handle the on_call_pre part of "__analyzer_get_unknown_ptr".  */
373
374 void
375 region_model::impl_call_analyzer_get_unknown_ptr (const call_details &cd)
376 {
377   const svalue *ptr_sval
378     = m_mgr->get_or_create_unknown_svalue (cd.get_lhs_type ());
379   cd.maybe_set_lhs (ptr_sval);
380 }
381
382 /* Handle the on_call_pre part of "__builtin_expect" etc.  */
383
384 void
385 region_model::impl_call_builtin_expect (const call_details &cd)
386 {
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);
390 }
391
392 /* Handle the on_call_pre part of "calloc".  */
393
394 void
395 region_model::impl_call_calloc (const call_details &cd)
396 {
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 ())
409     {
410       const svalue *ptr_sval
411         = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
412       cd.maybe_set_lhs (ptr_sval);
413     }
414 }
415
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).  */
423
424 bool
425 region_model::impl_call_error (const call_details &cd, unsigned min_args,
426                                bool *out_terminate_path)
427 {
428   /* Bail if not enough args.  */
429   if (cd.num_args () < min_args)
430     return false;
431
432   /* Initial argument ought to be of type "int".  */
433   if (cd.get_arg_type (0) != integer_type_node)
434     return false;
435
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;
442
443   return true;
444 }
445
446 /* Handle the on_call_pre part of "fgets" and "fgets_unlocked".  */
447
448 void
449 region_model::impl_call_fgets (const call_details &cd)
450 {
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 ())
455     {
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 ());
459     }
460 }
461
462 /* Handle the on_call_pre part of "fread".  */
463
464 void
465 region_model::impl_call_fread (const call_details &cd)
466 {
467   const svalue *ptr_sval = cd.get_arg_svalue (0);
468   if (const region *reg = ptr_sval->maybe_get_region ())
469     {
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 ());
473     }
474 }
475
476 /* Handle the on_call_post part of "free", after sm-handling.
477
478    If the ptr points to an underlying heap region, delete the region,
479    poisoning pointers to it and regions within it.
480
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.
484
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
489    of casts.  */
490
491 void
492 region_model::impl_call_free (const call_details &cd)
493 {
494   const svalue *ptr_sval = cd.get_arg_svalue (0);
495   if (const region *freed_reg = ptr_sval->maybe_get_region ())
496     {
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);
501     }
502 }
503
504 /* Handle the on_call_pre part of "malloc".  */
505
506 void
507 region_model::impl_call_malloc (const call_details &cd)
508 {
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 ())
513     {
514       const svalue *ptr_sval
515         = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
516       cd.maybe_set_lhs (ptr_sval);
517     }
518 }
519
520 /* Handle the on_call_pre part of "memcpy" and "__builtin_memcpy".  */
521 // TODO: complain about overlapping src and dest.
522
523 void
524 region_model::impl_call_memcpy (const call_details &cd)
525 {
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);
529
530   const region *dest_reg = deref_rvalue (dest_ptr_sval, cd.get_arg_tree (0),
531                                          cd.get_ctxt ());
532   const region *src_reg = deref_rvalue (src_ptr_sval, cd.get_arg_tree (1),
533                                         cd.get_ctxt ());
534
535   cd.maybe_set_lhs (dest_ptr_sval);
536
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 ());
544 }
545
546 /* Handle the on_call_pre part of "memset" and "__builtin_memset".  */
547
548 void
549 region_model::impl_call_memset (const call_details &cd)
550 {
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);
554
555   const region *dest_reg = deref_rvalue (dest_sval, cd.get_arg_tree (0),
556                                           cd.get_ctxt ());
557
558   const svalue *fill_value_u8
559     = m_mgr->get_or_create_cast (unsigned_char_type_node, fill_value_sval);
560
561   const region *sized_dest_reg = m_mgr->get_sized_region (dest_reg,
562                                                           NULL_TREE,
563                                                           num_bytes_sval);
564   check_region_for_write (sized_dest_reg, cd.get_ctxt ());
565   fill_region (sized_dest_reg, fill_value_u8);
566 }
567
568 /* Handle the on_call_post part of "pipe".  */
569
570 void
571 region_model::impl_call_pipe (const call_details &cd)
572 {
573   class failure : public failed_call_info
574   {
575   public:
576     failure (const call_details &cd) : failed_call_info (cd) {}
577
578     bool update_model (region_model *model,
579                        const exploded_edge *,
580                        region_model_context *ctxt) const final override
581     {
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);
585       return true;
586     }
587   };
588
589   class success : public success_call_info
590   {
591   public:
592     success (const call_details &cd) : success_call_info (cd) {}
593
594     bool update_model (region_model *model,
595                        const exploded_edge *,
596                        region_model_context *ctxt) const final override
597     {
598       const call_details cd (get_call_details (model, ctxt));
599
600       /* Return 0.  */
601       model->update_for_zero_return (cd, true);
602
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++)
608         {
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,
618                                                   cd.get_call_stmt (),
619                                                   element_reg,
620                                                   p);
621           model->set_value (element_reg, fd_sval, cd.get_ctxt ());
622           model->mark_as_valid_fd (fd_sval, cd.get_ctxt ());
623
624         }
625       return true;
626     }
627   };
628
629   /* Body of region_model::impl_call_pipe.  */
630   if (cd.get_ctxt ())
631     {
632       cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
633       cd.get_ctxt ()->bifurcate (make_unique<success> (cd));
634       cd.get_ctxt ()->terminate_path ();
635     }
636 }
637
638 /* A subclass of pending_diagnostic for complaining about 'putenv'
639    called on an auto var.  */
640
641 class putenv_of_auto_var
642 : public pending_diagnostic_subclass<putenv_of_auto_var>
643 {
644 public:
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 ())
648   {
649   }
650
651   const char *get_kind () const final override
652   {
653     return "putenv_of_auto_var";
654   }
655
656   bool operator== (const putenv_of_auto_var &other) const
657   {
658     return (m_fndecl == other.m_fndecl
659             && m_reg == other.m_reg
660             && same_tree_p (m_var_decl, other.m_var_decl));
661   }
662
663   int get_controlling_option () const final override
664   {
665     return OPT_Wanalyzer_putenv_of_auto_var;
666   }
667
668   bool emit (rich_location *rich_loc) final override
669   {
670     auto_diagnostic_group d;
671     diagnostic_metadata m;
672
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");
677     m.add_rule (rule);
678
679     bool warned;
680     if (m_var_decl)
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);
684     else
685       warned = warning_meta (rich_loc, m, get_controlling_option (),
686                              "%qE on a pointer to an on-stack buffer",
687                              m_fndecl);
688     if (warned)
689       {
690         if (m_var_decl)
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",
694                 "setenv", m_fndecl);
695       }
696
697     return warned;
698   }
699
700   label_text describe_final_event (const evdesc::final_event &ev) final override
701   {
702     if (m_var_decl)
703       return ev.formatted_print ("%qE on a pointer to automatic variable %qE",
704                                  m_fndecl, m_var_decl);
705     else
706       return ev.formatted_print ("%qE on a pointer to an on-stack buffer",
707                                  m_fndecl);
708   }
709
710   void mark_interesting_stuff (interesting_t *interest) final override
711   {
712     if (!m_var_decl)
713       interest->add_region_creation (m_reg->get_base_region ());
714   }
715
716 private:
717   tree m_fndecl; // non-NULL
718   const region *m_reg; // non-NULL
719   tree m_var_decl; // could be NULL
720 };
721
722 /* Handle the on_call_pre part of "putenv".
723
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
726    on the stack.  */
727
728 void
729 region_model::impl_call_putenv (const call_details &cd)
730 {
731   tree fndecl = cd.get_fndecl_for_call ();
732   gcc_assert (fndecl);
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 ();
738   switch (mem_space)
739     {
740     default:
741       gcc_unreachable ();
742     case MEMSPACE_UNKNOWN:
743     case MEMSPACE_CODE:
744     case MEMSPACE_GLOBALS:
745     case MEMSPACE_HEAP:
746     case MEMSPACE_READONLY_DATA:
747       break;
748     case MEMSPACE_STACK:
749       if (ctxt)
750         ctxt->warn (make_unique<putenv_of_auto_var> (fndecl, reg));
751       break;
752     }
753 }
754
755 /* Handle the on_call_pre part of "operator new".  */
756
757 void
758 region_model::impl_call_operator_new (const call_details &cd)
759 {
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 ())
764     {
765       const svalue *ptr_sval
766         = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
767       cd.maybe_set_lhs (ptr_sval);
768     }
769 }
770
771 /* Handle the on_call_pre part of "operator delete", which comes in
772    both sized and unsized variants (2 arguments and 1 argument
773    respectively).  */
774
775 void
776 region_model::impl_call_operator_delete (const call_details &cd)
777 {
778   const svalue *ptr_sval = cd.get_arg_svalue (0);
779   if (const region *freed_reg = ptr_sval->maybe_get_region ())
780     {
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);
784     }
785 }
786
787 /* Handle the on_call_post part of "realloc":
788
789      void *realloc(void *ptr, size_t size);
790
791    realloc(3) is awkward, since it has various different outcomes
792    that are best modelled as separate exploded nodes/edges.
793
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).
799
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.
806
807    Each of these has a custom_edge_info subclass, which updates
808    the region_model and sm-state of the destination state.  */
809
810 void
811 region_model::impl_call_realloc (const call_details &cd)
812 {
813   /* Three custom subclasses of custom_edge_info, for handling the various
814      outcomes of "realloc".  */
815
816   /* Concrete custom_edge_info: a realloc call that fails, returning NULL.  */
817   class failure : public failed_call_info
818   {
819   public:
820     failure (const call_details &cd)
821     : failed_call_info (cd)
822     {
823     }
824
825     bool update_model (region_model *model,
826                        const exploded_edge *,
827                        region_model_context *ctxt) const final override
828     {
829       /* Return NULL; everything else is unchanged.  */
830       const call_details cd (get_call_details (model, ctxt));
831       if (cd.get_lhs_type ())
832         {
833           const svalue *zero
834             = model->m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
835           model->set_value (cd.get_lhs_region (),
836                             zero,
837                             cd.get_ctxt ());
838         }
839       return true;
840     }
841   };
842
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
846   {
847   public:
848     success_no_move (const call_details &cd)
849     : call_info (cd)
850     {
851     }
852
853     label_text get_desc (bool can_colorize) const final override
854     {
855       return make_label_text (can_colorize,
856                               "when %qE succeeds, without moving buffer",
857                               get_fndecl ());
858     }
859
860     bool update_model (region_model *model,
861                        const exploded_edge *,
862                        region_model_context *ctxt) const final override
863     {
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);
868
869       /* We can only grow in place with a non-NULL pointer.  */
870       {
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,
874                                     cd.get_ctxt ()))
875           return false;
876       }
877
878       if (const region *buffer_reg = model->deref_rvalue (ptr_sval, NULL_TREE,
879                                                           ctxt))
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 ())
883         {
884           model->set_value (cd.get_lhs_region (), ptr_sval, cd.get_ctxt ());
885           const svalue *zero
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 ());
888         }
889       else
890         return true;
891     }
892   };
893
894   /* Concrete custom_edge_info: a realloc call that succeeds, freeing
895      the existing buffer and moving the content to a freshly allocated
896      buffer.  */
897   class success_with_move : public call_info
898   {
899   public:
900     success_with_move (const call_details &cd)
901     : call_info (cd)
902     {
903     }
904
905     label_text get_desc (bool can_colorize) const final override
906     {
907       return make_label_text (can_colorize,
908                               "when %qE succeeds, moving buffer",
909                               get_fndecl ());
910     }
911     bool update_model (region_model *model,
912                        const exploded_edge *,
913                        region_model_context *ctxt) const final override
914     {
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);
918
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,
925                                   cd.get_ctxt ()))
926         return false;
927
928       if (cd.get_lhs_type ())
929         cd.maybe_set_lhs (new_ptr_sval);
930
931       if (const region *freed_reg = model->deref_rvalue (old_ptr_sval,
932                                                          NULL_TREE, ctxt))
933         {
934           /* Copy the data.  */
935           const svalue *old_size_sval = model->get_dynamic_extents (freed_reg);
936           if (old_size_sval)
937             {
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,
942                                                   copied_size_sval);
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,
947                                                   copied_size_sval);
948               model->set_value (copied_new_reg, buffer_content_sval,
949                                 cd.get_ctxt ());
950             }
951           else
952             {
953               /* We don't know how big the old region was;
954                  mark the new region as having been touched to avoid uninit
955                  issues.  */
956               model->mark_region_as_unknown (new_reg, cd.get_uncertainty ());
957             }
958
959           /* Free the old region, so that pointers to the old buffer become
960              invalid.  */
961
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);
966         }
967
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);
971
972       if (cd.get_lhs_type ())
973         {
974           const svalue *zero
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,
977                                         cd.get_ctxt ());
978         }
979       else
980         return true;
981     }
982
983   private:
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
989     {
990       tristate res
991         = model->eval_condition (old_size_sval, GT_EXPR, new_size_sval);
992       switch (res.get_value ())
993         {
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;
999         default:
1000           gcc_unreachable ();
1001         }
1002     }
1003   };
1004
1005   /* Body of region_model::impl_call_realloc.  */
1006
1007   if (cd.get_ctxt ())
1008     {
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 ();
1013     }
1014 }
1015
1016 /* Handle the on_call_post part of "strchr" and "__builtin_strchr".  */
1017
1018 void
1019 region_model::impl_call_strchr (const call_details &cd)
1020 {
1021   class strchr_call_info : public call_info
1022   {
1023   public:
1024     strchr_call_info (const call_details &cd, bool found)
1025     : call_info (cd), m_found (found)
1026     {
1027     }
1028
1029     label_text get_desc (bool can_colorize) const final override
1030     {
1031       if (m_found)
1032         return make_label_text (can_colorize,
1033                                 "when %qE returns non-NULL",
1034                                 get_fndecl ());
1035       else
1036         return make_label_text (can_colorize,
1037                                 "when %qE returns NULL",
1038                                 get_fndecl ());
1039     }
1040
1041     bool update_model (region_model *model,
1042                        const exploded_edge *,
1043                        region_model_context *ctxt) const final override
1044     {
1045       const call_details cd (get_call_details (model, ctxt));
1046       if (tree lhs_type = cd.get_lhs_type ())
1047         {
1048           region_model_manager *mgr = model->get_manager ();
1049           const svalue *result;
1050           if (m_found)
1051             {
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),
1055                                        cd.get_ctxt ());
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 (),
1062                                                       str_reg,
1063                                                       conjured_purge (model,
1064                                                                       ctxt));
1065               result = mgr->get_or_create_binop (lhs_type, POINTER_PLUS_EXPR,
1066                                                  str_sval, offset);
1067             }
1068           else
1069             result = mgr->get_or_create_int_cst (lhs_type, 0);
1070           cd.maybe_set_lhs (result);
1071         }
1072       return true;
1073     }
1074   private:
1075     bool m_found;
1076   };
1077
1078   /* Body of region_model::impl_call_strchr.  */
1079   if (cd.get_ctxt ())
1080     {
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 ();
1084     }
1085 }
1086
1087 /* Handle the on_call_pre part of "strcpy" and "__builtin_strcpy_chk".  */
1088
1089 void
1090 region_model::impl_call_strcpy (const call_details &cd)
1091 {
1092   const svalue *dest_sval = cd.get_arg_svalue (0);
1093   const region *dest_reg = deref_rvalue (dest_sval, cd.get_arg_tree (0),
1094                                          cd.get_ctxt ());
1095   const svalue *src_sval = cd.get_arg_svalue (1);
1096   const region *src_reg = deref_rvalue (src_sval, cd.get_arg_tree (1),
1097                                         cd.get_ctxt ());
1098   const svalue *src_contents_sval = get_store_value (src_reg,
1099                                                      cd.get_ctxt ());
1100
1101   cd.maybe_set_lhs (dest_sval);
1102
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);
1108
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 ());
1112 }
1113
1114 /* Handle the on_call_pre part of "strlen".  */
1115
1116 void
1117 region_model::impl_call_strlen (const call_details &cd)
1118 {
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 ())
1124     {
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 ())
1130         {
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);
1135           return;
1136         }
1137     }
1138   /* Otherwise a conjured value.  */
1139 }
1140
1141 /* Handle calls to functions referenced by
1142    __attribute__((malloc(FOO))).  */
1143
1144 void
1145 region_model::impl_deallocation_call (const call_details &cd)
1146 {
1147   impl_call_free (cd);
1148 }
1149
1150 } // namespace ana
1151
1152 #endif /* #if ENABLE_ANALYZER */