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 #include "system.h"
23 #include "coretypes.h"
24 #include "tree.h"
25 #include "function.h"
26 #include "basic-block.h"
27 #include "gimple.h"
28 #include "gimple-iterator.h"
29 #include "diagnostic-core.h"
30 #include "graphviz.h"
31 #include "options.h"
32 #include "cgraph.h"
33 #include "tree-dfa.h"
34 #include "stringpool.h"
35 #include "convert.h"
36 #include "target.h"
37 #include "fold-const.h"
38 #include "tree-pretty-print.h"
39 #include "diagnostic-color.h"
40 #include "diagnostic-metadata.h"
41 #include "tristate.h"
42 #include "bitmap.h"
43 #include "selftest.h"
44 #include "function.h"
45 #include "json.h"
46 #include "analyzer/analyzer.h"
47 #include "analyzer/analyzer-logging.h"
48 #include "ordered-hash-map.h"
49 #include "options.h"
50 #include "cgraph.h"
51 #include "cfg.h"
52 #include "digraph.h"
53 #include "analyzer/supergraph.h"
54 #include "sbitmap.h"
55 #include "analyzer/call-string.h"
56 #include "analyzer/program-point.h"
57 #include "analyzer/store.h"
58 #include "analyzer/region-model.h"
59 #include "analyzer/call-info.h"
60 #include "gimple-pretty-print.h"
61
62 #if ENABLE_ANALYZER
63
64 namespace ana {
65
66 /* class call_details. */
67
68 /* call_details's ctor. */
69
call_details(const gcall * call,region_model * model,region_model_context * ctxt)70 call_details::call_details (const gcall *call, region_model *model,
71 region_model_context *ctxt)
72 : m_call (call), m_model (model), m_ctxt (ctxt),
73 m_lhs_type (NULL_TREE), m_lhs_region (NULL)
74 {
75 m_lhs_type = NULL_TREE;
76 if (tree lhs = gimple_call_lhs (call))
77 {
78 m_lhs_region = model->get_lvalue (lhs, ctxt);
79 m_lhs_type = TREE_TYPE (lhs);
80 }
81 }
82
83 /* Get the manager from m_model. */
84
85 region_model_manager *
get_manager() const86 call_details::get_manager () const
87 {
88 return m_model->get_manager ();
89 }
90
91 /* Get any uncertainty_t associated with the region_model_context. */
92
93 uncertainty_t *
get_uncertainty() const94 call_details::get_uncertainty () const
95 {
96 if (m_ctxt)
97 return m_ctxt->get_uncertainty ();
98 else
99 return NULL;
100 }
101
102 /* If the callsite has a left-hand-side region, set it to RESULT
103 and return true.
104 Otherwise do nothing and return false. */
105
106 bool
maybe_set_lhs(const svalue * result) const107 call_details::maybe_set_lhs (const svalue *result) const
108 {
109 gcc_assert (result);
110 if (m_lhs_region)
111 {
112 m_model->set_value (m_lhs_region, result, m_ctxt);
113 return true;
114 }
115 else
116 return false;
117 }
118
119 /* Return the number of arguments used by the call statement. */
120
121 unsigned
num_args() const122 call_details::num_args () const
123 {
124 return gimple_call_num_args (m_call);
125 }
126
127 /* Get argument IDX at the callsite as a tree. */
128
129 tree
get_arg_tree(unsigned idx) const130 call_details::get_arg_tree (unsigned idx) const
131 {
132 return gimple_call_arg (m_call, idx);
133 }
134
135 /* Get the type of argument IDX. */
136
137 tree
get_arg_type(unsigned idx) const138 call_details::get_arg_type (unsigned idx) const
139 {
140 return TREE_TYPE (gimple_call_arg (m_call, idx));
141 }
142
143 /* Get argument IDX at the callsite as an svalue. */
144
145 const svalue *
get_arg_svalue(unsigned idx) const146 call_details::get_arg_svalue (unsigned idx) const
147 {
148 tree arg = get_arg_tree (idx);
149 return m_model->get_rvalue (arg, m_ctxt);
150 }
151
152 /* Attempt to get the string literal for argument IDX, or return NULL
153 otherwise.
154 For use when implementing "__analyzer_*" functions that take
155 string literals. */
156
157 const char *
get_arg_string_literal(unsigned idx) const158 call_details::get_arg_string_literal (unsigned idx) const
159 {
160 const svalue *str_arg = get_arg_svalue (idx);
161 if (const region *pointee = str_arg->maybe_get_region ())
162 if (const string_region *string_reg = pointee->dyn_cast_string_region ())
163 {
164 tree string_cst = string_reg->get_string_cst ();
165 return TREE_STRING_POINTER (string_cst);
166 }
167 return NULL;
168 }
169
170 /* Attempt to get the fndecl used at this call, if known, or NULL_TREE
171 otherwise. */
172
173 tree
get_fndecl_for_call() const174 call_details::get_fndecl_for_call () const
175 {
176 return m_model->get_fndecl_for_call (m_call, m_ctxt);
177 }
178
179 /* Dump a multiline representation of this call to PP. */
180
181 void
dump_to_pp(pretty_printer * pp,bool simple) const182 call_details::dump_to_pp (pretty_printer *pp, bool simple) const
183 {
184 pp_string (pp, "gcall: ");
185 pp_gimple_stmt_1 (pp, m_call, 0 /* spc */, TDF_NONE /* flags */);
186 pp_newline (pp);
187 pp_string (pp, "return region: ");
188 if (m_lhs_region)
189 m_lhs_region->dump_to_pp (pp, simple);
190 else
191 pp_string (pp, "NULL");
192 pp_newline (pp);
193 for (unsigned i = 0; i < gimple_call_num_args (m_call); i++)
194 {
195 const svalue *arg_sval = get_arg_svalue (i);
196 pp_printf (pp, "arg %i: ", i);
197 arg_sval->dump_to_pp (pp, simple);
198 pp_newline (pp);
199 }
200 }
201
202 /* Dump a multiline representation of this call to stderr. */
203
204 DEBUG_FUNCTION void
dump(bool simple) const205 call_details::dump (bool simple) const
206 {
207 pretty_printer pp;
208 pp_format_decoder (&pp) = default_tree_printer;
209 pp_show_color (&pp) = pp_show_color (global_dc->printer);
210 pp.buffer->stream = stderr;
211 dump_to_pp (&pp, simple);
212 pp_flush (&pp);
213 }
214
215 /* Get a conjured_svalue for this call for REG,
216 and purge any state already relating to that conjured_svalue. */
217
218 const svalue *
get_or_create_conjured_svalue(const region * reg) const219 call_details::get_or_create_conjured_svalue (const region *reg) const
220 {
221 region_model_manager *mgr = m_model->get_manager ();
222 return mgr->get_or_create_conjured_svalue (reg->get_type (), m_call, reg,
223 conjured_purge (m_model, m_ctxt));
224 }
225
226 /* Implementations of specific functions. */
227
228 /* Handle the on_call_pre part of "alloca". */
229
230 void
impl_call_alloca(const call_details & cd)231 region_model::impl_call_alloca (const call_details &cd)
232 {
233 const svalue *size_sval = cd.get_arg_svalue (0);
234 const region *new_reg = create_region_for_alloca (size_sval, cd.get_ctxt ());
235 const svalue *ptr_sval
236 = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
237 cd.maybe_set_lhs (ptr_sval);
238 }
239
240 /* Handle a call to "__analyzer_describe".
241
242 Emit a warning describing the 2nd argument (which can be of any
243 type), at the given verbosity level. This is for use when
244 debugging, and may be of use in DejaGnu tests. */
245
246 void
impl_call_analyzer_describe(const gcall * call,region_model_context * ctxt)247 region_model::impl_call_analyzer_describe (const gcall *call,
248 region_model_context *ctxt)
249 {
250 tree t_verbosity = gimple_call_arg (call, 0);
251 tree t_val = gimple_call_arg (call, 1);
252 const svalue *sval = get_rvalue (t_val, ctxt);
253 bool simple = zerop (t_verbosity);
254 label_text desc = sval->get_desc (simple);
255 warning_at (call->location, 0, "svalue: %qs", desc.m_buffer);
256 }
257
258 /* Handle a call to "__analyzer_dump_capacity".
259
260 Emit a warning describing the capacity of the base region of
261 the region pointed to by the 1st argument.
262 This is for use when debugging, and may be of use in DejaGnu tests. */
263
264 void
impl_call_analyzer_dump_capacity(const gcall * call,region_model_context * ctxt)265 region_model::impl_call_analyzer_dump_capacity (const gcall *call,
266 region_model_context *ctxt)
267 {
268 tree t_ptr = gimple_call_arg (call, 0);
269 const svalue *sval_ptr = get_rvalue (t_ptr, ctxt);
270 const region *reg = deref_rvalue (sval_ptr, t_ptr, ctxt);
271 const region *base_reg = reg->get_base_region ();
272 const svalue *capacity = get_capacity (base_reg);
273 label_text desc = capacity->get_desc (true);
274 warning_at (call->location, 0, "capacity: %qs", desc.m_buffer);
275 }
276
277 /* Compare D1 and D2 using their names, and then IDs to order them. */
278
279 static int
cmp_decls(tree d1,tree d2)280 cmp_decls (tree d1, tree d2)
281 {
282 gcc_assert (DECL_P (d1));
283 gcc_assert (DECL_P (d2));
284 if (DECL_NAME (d1) && DECL_NAME (d2))
285 if (int cmp = strcmp (IDENTIFIER_POINTER (DECL_NAME (d1)),
286 IDENTIFIER_POINTER (DECL_NAME (d2))))
287 return cmp;
288 return (int)DECL_UID (d1) - (int)DECL_UID (d2);
289 }
290
291 /* Comparator for use by vec<tree>::qsort,
292 using their names, and then IDs to order them. */
293
294 static int
cmp_decls_ptr_ptr(const void * p1,const void * p2)295 cmp_decls_ptr_ptr (const void *p1, const void *p2)
296 {
297 tree const *d1 = (tree const *)p1;
298 tree const *d2 = (tree const *)p2;
299
300 return cmp_decls (*d1, *d2);
301 }
302
303 /* Handle a call to "__analyzer_dump_escaped".
304
305 Emit a warning giving the number of decls that have escaped, followed
306 by a comma-separated list of their names, in alphabetical order.
307
308 This is for use when debugging, and may be of use in DejaGnu tests. */
309
310 void
impl_call_analyzer_dump_escaped(const gcall * call)311 region_model::impl_call_analyzer_dump_escaped (const gcall *call)
312 {
313 auto_vec<tree> escaped_decls;
314 for (auto iter : m_store)
315 {
316 const binding_cluster *c = iter.second;
317 if (!c->escaped_p ())
318 continue;
319 if (tree decl = c->get_base_region ()->maybe_get_decl ())
320 escaped_decls.safe_push (decl);
321 }
322
323 /* Sort them into deterministic order; alphabetical is
324 probably most user-friendly. */
325 escaped_decls.qsort (cmp_decls_ptr_ptr);
326
327 pretty_printer pp;
328 pp_format_decoder (&pp) = default_tree_printer;
329 pp_show_color (&pp) = pp_show_color (global_dc->printer);
330 bool first = true;
331 for (auto iter : escaped_decls)
332 {
333 if (first)
334 first = false;
335 else
336 pp_string (&pp, ", ");
337 pp_printf (&pp, "%qD", iter);
338 }
339 /* Print the number to make it easier to write DejaGnu tests for
340 the "nothing has escaped" case. */
341 warning_at (call->location, 0, "escaped: %i: %s",
342 escaped_decls.length (),
343 pp_formatted_text (&pp));
344 }
345
346 /* Handle a call to "__analyzer_eval" by evaluating the input
347 and dumping as a dummy warning, so that test cases can use
348 dg-warning to validate the result (and so unexpected warnings will
349 lead to DejaGnu failures).
350 Broken out as a subroutine to make it easier to put a breakpoint on it
351 - though typically this doesn't help, as we have an SSA name as the arg,
352 and what's more interesting is usually the def stmt for that name. */
353
354 void
impl_call_analyzer_eval(const gcall * call,region_model_context * ctxt)355 region_model::impl_call_analyzer_eval (const gcall *call,
356 region_model_context *ctxt)
357 {
358 tree t_arg = gimple_call_arg (call, 0);
359 tristate t = eval_condition (t_arg, NE_EXPR, integer_zero_node, ctxt);
360 warning_at (call->location, 0, "%s", t.as_string ());
361 }
362
363 /* Handle the on_call_pre part of "__builtin_expect" etc. */
364
365 void
impl_call_builtin_expect(const call_details & cd)366 region_model::impl_call_builtin_expect (const call_details &cd)
367 {
368 /* __builtin_expect's return value is its initial argument. */
369 const svalue *sval = cd.get_arg_svalue (0);
370 cd.maybe_set_lhs (sval);
371 }
372
373 /* Handle the on_call_pre part of "calloc". */
374
375 void
impl_call_calloc(const call_details & cd)376 region_model::impl_call_calloc (const call_details &cd)
377 {
378 const svalue *nmemb_sval = cd.get_arg_svalue (0);
379 const svalue *size_sval = cd.get_arg_svalue (1);
380 /* TODO: check for overflow here? */
381 const svalue *prod_sval
382 = m_mgr->get_or_create_binop (size_type_node, MULT_EXPR,
383 nmemb_sval, size_sval);
384 const region *new_reg
385 = create_region_for_heap_alloc (prod_sval, cd.get_ctxt ());
386 const region *sized_reg
387 = m_mgr->get_sized_region (new_reg, NULL_TREE, prod_sval);
388 zero_fill_region (sized_reg);
389 if (cd.get_lhs_type ())
390 {
391 const svalue *ptr_sval
392 = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
393 cd.maybe_set_lhs (ptr_sval);
394 }
395 }
396
397 /* Handle the on_call_pre part of "error" and "error_at_line" from
398 GNU's non-standard <error.h>.
399 MIN_ARGS identifies the minimum number of expected arguments
400 to be consistent with such a call (3 and 5 respectively).
401 Return true if handling it as one of these functions.
402 Write true to *OUT_TERMINATE_PATH if this execution path should be
403 terminated (e.g. the function call terminates the process). */
404
405 bool
impl_call_error(const call_details & cd,unsigned min_args,bool * out_terminate_path)406 region_model::impl_call_error (const call_details &cd, unsigned min_args,
407 bool *out_terminate_path)
408 {
409 /* Bail if not enough args. */
410 if (cd.num_args () < min_args)
411 return false;
412
413 /* Initial argument ought to be of type "int". */
414 if (cd.get_arg_type (0) != integer_type_node)
415 return false;
416
417 /* The process exits if status != 0, so it only continues
418 for the case where status == 0.
419 Add that constraint, or terminate this analysis path. */
420 tree status = cd.get_arg_tree (0);
421 if (!add_constraint (status, EQ_EXPR, integer_zero_node, cd.get_ctxt ()))
422 *out_terminate_path = true;
423
424 return true;
425 }
426
427 /* Handle the on_call_pre part of "fgets" and "fgets_unlocked". */
428
429 void
impl_call_fgets(const call_details & cd)430 region_model::impl_call_fgets (const call_details &cd)
431 {
432 /* Ideally we would bifurcate state here between the
433 error vs no error cases. */
434 const svalue *ptr_sval = cd.get_arg_svalue (0);
435 if (const region *reg = ptr_sval->maybe_get_region ())
436 {
437 const region *base_reg = reg->get_base_region ();
438 const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg);
439 set_value (base_reg, new_sval, cd.get_ctxt ());
440 }
441 }
442
443 /* Handle the on_call_pre part of "fread". */
444
445 void
impl_call_fread(const call_details & cd)446 region_model::impl_call_fread (const call_details &cd)
447 {
448 const svalue *ptr_sval = cd.get_arg_svalue (0);
449 if (const region *reg = ptr_sval->maybe_get_region ())
450 {
451 const region *base_reg = reg->get_base_region ();
452 const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg);
453 set_value (base_reg, new_sval, cd.get_ctxt ());
454 }
455 }
456
457 /* Handle the on_call_post part of "free", after sm-handling.
458
459 If the ptr points to an underlying heap region, delete the region,
460 poisoning pointers to it and regions within it.
461
462 We delay this until after sm-state has been updated so that the
463 sm-handling can transition all of the various casts of the pointer
464 to a "freed" state *before* we delete the related region here.
465
466 This has to be done here so that the sm-handling can use the fact
467 that they point to the same region to establish that they are equal
468 (in region_model::eval_condition_without_cm), and thus transition
469 all pointers to the region to the "freed" state together, regardless
470 of casts. */
471
472 void
impl_call_free(const call_details & cd)473 region_model::impl_call_free (const call_details &cd)
474 {
475 const svalue *ptr_sval = cd.get_arg_svalue (0);
476 if (const region *freed_reg = ptr_sval->maybe_get_region ())
477 {
478 /* If the ptr points to an underlying heap region, delete it,
479 poisoning pointers. */
480 unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
481 m_dynamic_extents.remove (freed_reg);
482 }
483 }
484
485 /* Handle the on_call_pre part of "malloc". */
486
487 void
impl_call_malloc(const call_details & cd)488 region_model::impl_call_malloc (const call_details &cd)
489 {
490 const svalue *size_sval = cd.get_arg_svalue (0);
491 const region *new_reg
492 = create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
493 if (cd.get_lhs_type ())
494 {
495 const svalue *ptr_sval
496 = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
497 cd.maybe_set_lhs (ptr_sval);
498 }
499 }
500
501 /* Handle the on_call_pre part of "memcpy" and "__builtin_memcpy". */
502 // TODO: complain about overlapping src and dest.
503
504 void
impl_call_memcpy(const call_details & cd)505 region_model::impl_call_memcpy (const call_details &cd)
506 {
507 const svalue *dest_ptr_sval = cd.get_arg_svalue (0);
508 const svalue *src_ptr_sval = cd.get_arg_svalue (1);
509 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
510
511 const region *dest_reg = deref_rvalue (dest_ptr_sval, cd.get_arg_tree (0),
512 cd.get_ctxt ());
513 const region *src_reg = deref_rvalue (src_ptr_sval, cd.get_arg_tree (1),
514 cd.get_ctxt ());
515
516 cd.maybe_set_lhs (dest_ptr_sval);
517
518 const region *sized_src_reg
519 = m_mgr->get_sized_region (src_reg, NULL_TREE, num_bytes_sval);
520 const region *sized_dest_reg
521 = m_mgr->get_sized_region (dest_reg, NULL_TREE, num_bytes_sval);
522 const svalue *src_contents_sval
523 = get_store_value (sized_src_reg, cd.get_ctxt ());
524 set_value (sized_dest_reg, src_contents_sval, cd.get_ctxt ());
525 }
526
527 /* Handle the on_call_pre part of "memset" and "__builtin_memset". */
528
529 void
impl_call_memset(const call_details & cd)530 region_model::impl_call_memset (const call_details &cd)
531 {
532 const svalue *dest_sval = cd.get_arg_svalue (0);
533 const svalue *fill_value_sval = cd.get_arg_svalue (1);
534 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
535
536 const region *dest_reg = deref_rvalue (dest_sval, cd.get_arg_tree (0),
537 cd.get_ctxt ());
538
539 const svalue *fill_value_u8
540 = m_mgr->get_or_create_cast (unsigned_char_type_node, fill_value_sval);
541
542 const region *sized_dest_reg = m_mgr->get_sized_region (dest_reg,
543 NULL_TREE,
544 num_bytes_sval);
545 check_region_for_write (sized_dest_reg, cd.get_ctxt ());
546 fill_region (sized_dest_reg, fill_value_u8);
547 }
548
549 /* Handle the on_call_pre part of "operator new". */
550
551 void
impl_call_operator_new(const call_details & cd)552 region_model::impl_call_operator_new (const call_details &cd)
553 {
554 const svalue *size_sval = cd.get_arg_svalue (0);
555 const region *new_reg
556 = create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
557 if (cd.get_lhs_type ())
558 {
559 const svalue *ptr_sval
560 = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
561 cd.maybe_set_lhs (ptr_sval);
562 }
563 }
564
565 /* Handle the on_call_pre part of "operator delete", which comes in
566 both sized and unsized variants (2 arguments and 1 argument
567 respectively). */
568
569 void
impl_call_operator_delete(const call_details & cd)570 region_model::impl_call_operator_delete (const call_details &cd)
571 {
572 const svalue *ptr_sval = cd.get_arg_svalue (0);
573 if (const region *freed_reg = ptr_sval->maybe_get_region ())
574 {
575 /* If the ptr points to an underlying heap region, delete it,
576 poisoning pointers. */
577 unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
578 }
579 }
580
581 /* Handle the on_call_post part of "realloc":
582
583 void *realloc(void *ptr, size_t size);
584
585 realloc(3) is awkward, since it has various different outcomes
586 that are best modelled as separate exploded nodes/edges.
587
588 We first check for sm-state, in
589 malloc_state_machine::on_realloc_call, so that we
590 can complain about issues such as realloc of a non-heap
591 pointer, and terminate the path for such cases (and issue
592 the complaints at the call's exploded node).
593
594 Assuming that these checks pass, we split the path here into
595 three special cases (and terminate the "standard" path):
596 (A) failure, returning NULL
597 (B) success, growing the buffer in-place without moving it
598 (C) success, allocating a new buffer, copying the content
599 of the old buffer to it, and freeing the old buffer.
600
601 Each of these has a custom_edge_info subclass, which updates
602 the region_model and sm-state of the destination state. */
603
604 void
impl_call_realloc(const call_details & cd)605 region_model::impl_call_realloc (const call_details &cd)
606 {
607 /* Three custom subclasses of custom_edge_info, for handling the various
608 outcomes of "realloc". */
609
610 /* Concrete custom_edge_info: a realloc call that fails, returning NULL. */
611 class failure : public failed_call_info
612 {
613 public:
614 failure (const call_details &cd)
615 : failed_call_info (cd)
616 {
617 }
618
619 bool update_model (region_model *model,
620 const exploded_edge *,
621 region_model_context *ctxt) const FINAL OVERRIDE
622 {
623 /* Return NULL; everything else is unchanged. */
624 const call_details cd (get_call_details (model, ctxt));
625 if (cd.get_lhs_type ())
626 {
627 const svalue *zero
628 = model->m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
629 model->set_value (cd.get_lhs_region (),
630 zero,
631 cd.get_ctxt ());
632 }
633 return true;
634 }
635 };
636
637 /* Concrete custom_edge_info: a realloc call that succeeds, growing
638 the existing buffer without moving it. */
639 class success_no_move : public call_info
640 {
641 public:
642 success_no_move (const call_details &cd)
643 : call_info (cd)
644 {
645 }
646
647 label_text get_desc (bool can_colorize) const FINAL OVERRIDE
648 {
649 return make_label_text (can_colorize,
650 "when %qE succeeds, without moving buffer",
651 get_fndecl ());
652 }
653
654 bool update_model (region_model *model,
655 const exploded_edge *,
656 region_model_context *ctxt) const FINAL OVERRIDE
657 {
658 /* Update size of buffer and return the ptr unchanged. */
659 const call_details cd (get_call_details (model, ctxt));
660 const svalue *ptr_sval = cd.get_arg_svalue (0);
661 const svalue *size_sval = cd.get_arg_svalue (1);
662
663 /* We can only grow in place with a non-NULL pointer. */
664 {
665 const svalue *null_ptr
666 = model->m_mgr->get_or_create_int_cst (ptr_sval->get_type (), 0);
667 if (!model->add_constraint (ptr_sval, NE_EXPR, null_ptr,
668 cd.get_ctxt ()))
669 return false;
670 }
671
672 if (const region *buffer_reg = model->deref_rvalue (ptr_sval, NULL_TREE,
673 ctxt))
674 if (compat_types_p (size_sval->get_type (), size_type_node))
675 model->set_dynamic_extents (buffer_reg, size_sval, ctxt);
676 if (cd.get_lhs_region ())
677 {
678 model->set_value (cd.get_lhs_region (), ptr_sval, cd.get_ctxt ());
679 const svalue *zero
680 = model->m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
681 return model->add_constraint (ptr_sval, NE_EXPR, zero, cd.get_ctxt ());
682 }
683 else
684 return true;
685 }
686 };
687
688 /* Concrete custom_edge_info: a realloc call that succeeds, freeing
689 the existing buffer and moving the content to a freshly allocated
690 buffer. */
691 class success_with_move : public call_info
692 {
693 public:
694 success_with_move (const call_details &cd)
695 : call_info (cd)
696 {
697 }
698
699 label_text get_desc (bool can_colorize) const FINAL OVERRIDE
700 {
701 return make_label_text (can_colorize,
702 "when %qE succeeds, moving buffer",
703 get_fndecl ());
704 }
705 bool update_model (region_model *model,
706 const exploded_edge *,
707 region_model_context *ctxt) const FINAL OVERRIDE
708 {
709 const call_details cd (get_call_details (model, ctxt));
710 const svalue *old_ptr_sval = cd.get_arg_svalue (0);
711 const svalue *new_size_sval = cd.get_arg_svalue (1);
712
713 /* Create the new region. */
714 const region *new_reg
715 = model->create_region_for_heap_alloc (new_size_sval, ctxt);
716 const svalue *new_ptr_sval
717 = model->m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
718 if (!model->add_constraint (new_ptr_sval, NE_EXPR, old_ptr_sval,
719 cd.get_ctxt ()))
720 return false;
721
722 if (cd.get_lhs_type ())
723 cd.maybe_set_lhs (new_ptr_sval);
724
725 if (const region *freed_reg = model->deref_rvalue (old_ptr_sval,
726 NULL_TREE, ctxt))
727 {
728 /* Copy the data. */
729 const svalue *old_size_sval = model->get_dynamic_extents (freed_reg);
730 if (old_size_sval)
731 {
732 const region *sized_old_reg
733 = model->m_mgr->get_sized_region (freed_reg, NULL,
734 old_size_sval);
735 const svalue *buffer_content_sval
736 = model->get_store_value (sized_old_reg, cd.get_ctxt ());
737 const region *sized_new_reg
738 = model->m_mgr->get_sized_region (new_reg, NULL,
739 old_size_sval);
740 model->set_value (sized_new_reg, buffer_content_sval,
741 cd.get_ctxt ());
742 }
743 else
744 {
745 /* We don't know how big the old region was;
746 mark the new region as having been touched to avoid uninit
747 issues. */
748 model->mark_region_as_unknown (new_reg, cd.get_uncertainty ());
749 }
750
751 /* Free the old region, so that pointers to the old buffer become
752 invalid. */
753
754 /* If the ptr points to an underlying heap region, delete it,
755 poisoning pointers. */
756 model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
757 model->m_dynamic_extents.remove (freed_reg);
758 }
759
760 /* Update the sm-state: mark the old_ptr_sval as "freed",
761 and the new_ptr_sval as "nonnull". */
762 model->on_realloc_with_move (cd, old_ptr_sval, new_ptr_sval);
763
764 if (cd.get_lhs_type ())
765 {
766 const svalue *zero
767 = model->m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
768 return model->add_constraint (new_ptr_sval, NE_EXPR, zero,
769 cd.get_ctxt ());
770 }
771 else
772 return true;
773 }
774 };
775
776 /* Body of region_model::impl_call_realloc. */
777
778 if (cd.get_ctxt ())
779 {
780 cd.get_ctxt ()->bifurcate (new failure (cd));
781 cd.get_ctxt ()->bifurcate (new success_no_move (cd));
782 cd.get_ctxt ()->bifurcate (new success_with_move (cd));
783 cd.get_ctxt ()->terminate_path ();
784 }
785 }
786
787 /* Handle the on_call_pre part of "strchr" and "__builtin_strchr". */
788
789 void
impl_call_strchr(const call_details & cd)790 region_model::impl_call_strchr (const call_details &cd)
791 {
792 class strchr_call_info : public call_info
793 {
794 public:
795 strchr_call_info (const call_details &cd, bool found)
796 : call_info (cd), m_found (found)
797 {
798 }
799
800 label_text get_desc (bool can_colorize) const FINAL OVERRIDE
801 {
802 if (m_found)
803 return make_label_text (can_colorize,
804 "when %qE returns non-NULL",
805 get_fndecl ());
806 else
807 return make_label_text (can_colorize,
808 "when %qE returns NULL",
809 get_fndecl ());
810 }
811
812 bool update_model (region_model *model,
813 const exploded_edge *,
814 region_model_context *ctxt) const FINAL OVERRIDE
815 {
816 const call_details cd (get_call_details (model, ctxt));
817 if (tree lhs_type = cd.get_lhs_type ())
818 {
819 region_model_manager *mgr = model->get_manager ();
820 const svalue *result;
821 if (m_found)
822 {
823 const svalue *str_sval = cd.get_arg_svalue (0);
824 const region *str_reg
825 = model->deref_rvalue (str_sval, cd.get_arg_tree (0),
826 cd.get_ctxt ());
827 /* We want str_sval + OFFSET for some unknown OFFSET.
828 Use a conjured_svalue to represent the offset,
829 using the str_reg as the id of the conjured_svalue. */
830 const svalue *offset
831 = mgr->get_or_create_conjured_svalue (size_type_node,
832 cd.get_call_stmt (),
833 str_reg,
834 conjured_purge (model,
835 ctxt));
836 result = mgr->get_or_create_binop (lhs_type, POINTER_PLUS_EXPR,
837 str_sval, offset);
838 }
839 else
840 result = mgr->get_or_create_int_cst (lhs_type, 0);
841 cd.maybe_set_lhs (result);
842 }
843 return true;
844 }
845 private:
846 bool m_found;
847 };
848
849 /* Bifurcate state, creating a "not found" out-edge. */
850 if (cd.get_ctxt ())
851 cd.get_ctxt ()->bifurcate (new strchr_call_info (cd, false));
852
853 /* The "unbifurcated" state is the "found" case. */
854 strchr_call_info found (cd, true);
855 found.update_model (this, NULL, cd.get_ctxt ());
856 }
857
858 /* Handle the on_call_pre part of "strcpy" and "__builtin_strcpy_chk". */
859
860 void
impl_call_strcpy(const call_details & cd)861 region_model::impl_call_strcpy (const call_details &cd)
862 {
863 const svalue *dest_sval = cd.get_arg_svalue (0);
864 const region *dest_reg = deref_rvalue (dest_sval, cd.get_arg_tree (0),
865 cd.get_ctxt ());
866
867 cd.maybe_set_lhs (dest_sval);
868
869 check_region_for_write (dest_reg, cd.get_ctxt ());
870
871 /* For now, just mark region's contents as unknown. */
872 mark_region_as_unknown (dest_reg, cd.get_uncertainty ());
873 }
874
875 /* Handle the on_call_pre part of "strlen". */
876
877 void
impl_call_strlen(const call_details & cd)878 region_model::impl_call_strlen (const call_details &cd)
879 {
880 region_model_context *ctxt = cd.get_ctxt ();
881 const svalue *arg_sval = cd.get_arg_svalue (0);
882 const region *buf_reg = deref_rvalue (arg_sval, cd.get_arg_tree (0), ctxt);
883 if (const string_region *str_reg
884 = buf_reg->dyn_cast_string_region ())
885 {
886 tree str_cst = str_reg->get_string_cst ();
887 /* TREE_STRING_LENGTH is sizeof, not strlen. */
888 int sizeof_cst = TREE_STRING_LENGTH (str_cst);
889 int strlen_cst = sizeof_cst - 1;
890 if (cd.get_lhs_type ())
891 {
892 tree t_cst = build_int_cst (cd.get_lhs_type (), strlen_cst);
893 const svalue *result_sval
894 = m_mgr->get_or_create_constant_svalue (t_cst);
895 cd.maybe_set_lhs (result_sval);
896 return;
897 }
898 }
899 /* Otherwise a conjured value. */
900 }
901
902 /* Handle calls to functions referenced by
903 __attribute__((malloc(FOO))). */
904
905 void
impl_deallocation_call(const call_details & cd)906 region_model::impl_deallocation_call (const call_details &cd)
907 {
908 impl_call_free (cd);
909 }
910
911 } // namespace ana
912
913 #endif /* #if ENABLE_ANALYZER */
914