]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/analyzer/region-model-impl-calls.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / analyzer / region-model-impl-calls.cc
CommitLineData
808f4dfe 1/* Handling for the known behavior of various specific functions.
7adcbafe 2 Copyright (C) 2020-2022 Free Software Foundation, Inc.
808f4dfe
DM
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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"
809192e7 45#include "json.h"
808f4dfe
DM
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"
eafa9d96 59#include "analyzer/call-info.h"
808f4dfe
DM
60#include "gimple-pretty-print.h"
61
62#if ENABLE_ANALYZER
63
64namespace ana {
65
66/* class call_details. */
67
68/* call_details's ctor. */
69
70call_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
3a66c289
DM
83/* Get any uncertainty_t associated with the region_model_context. */
84
85uncertainty_t *
86call_details::get_uncertainty () const
87{
33255ad3
DM
88 if (m_ctxt)
89 return m_ctxt->get_uncertainty ();
90 else
91 return NULL;
3a66c289
DM
92}
93
808f4dfe
DM
94/* If the callsite has a left-hand-side region, set it to RESULT
95 and return true.
96 Otherwise do nothing and return false. */
97
98bool
99call_details::maybe_set_lhs (const svalue *result) const
100{
101 gcc_assert (result);
102 if (m_lhs_region)
103 {
104 m_model->set_value (m_lhs_region, result, m_ctxt);
105 return true;
106 }
107 else
108 return false;
109}
110
5ee4ba03
DM
111/* Return the number of arguments used by the call statement. */
112
113unsigned
114call_details::num_args () const
115{
116 return gimple_call_num_args (m_call);
117}
118
808f4dfe
DM
119/* Get argument IDX at the callsite as a tree. */
120
121tree
122call_details::get_arg_tree (unsigned idx) const
123{
124 return gimple_call_arg (m_call, idx);
125}
126
1e19ecd7
DM
127/* Get the type of argument IDX. */
128
129tree
130call_details::get_arg_type (unsigned idx) const
131{
132 return TREE_TYPE (gimple_call_arg (m_call, idx));
133}
134
808f4dfe
DM
135/* Get argument IDX at the callsite as an svalue. */
136
137const svalue *
138call_details::get_arg_svalue (unsigned idx) const
139{
140 tree arg = get_arg_tree (idx);
141 return m_model->get_rvalue (arg, m_ctxt);
142}
143
9ea10c48
DM
144/* Attempt to get the string literal for argument IDX, or return NULL
145 otherwise.
146 For use when implementing "__analyzer_*" functions that take
147 string literals. */
148
149const char *
150call_details::get_arg_string_literal (unsigned idx) const
151{
152 const svalue *str_arg = get_arg_svalue (idx);
153 if (const region *pointee = str_arg->maybe_get_region ())
154 if (const string_region *string_reg = pointee->dyn_cast_string_region ())
155 {
156 tree string_cst = string_reg->get_string_cst ();
157 return TREE_STRING_POINTER (string_cst);
158 }
159 return NULL;
160}
161
eafa9d96
DM
162/* Attempt to get the fndecl used at this call, if known, or NULL_TREE
163 otherwise. */
164
165tree
166call_details::get_fndecl_for_call () const
167{
168 return m_model->get_fndecl_for_call (m_call, m_ctxt);
169}
170
808f4dfe
DM
171/* Dump a multiline representation of this call to PP. */
172
173void
174call_details::dump_to_pp (pretty_printer *pp, bool simple) const
175{
176 pp_string (pp, "gcall: ");
177 pp_gimple_stmt_1 (pp, m_call, 0 /* spc */, TDF_NONE /* flags */);
178 pp_newline (pp);
179 pp_string (pp, "return region: ");
180 if (m_lhs_region)
181 m_lhs_region->dump_to_pp (pp, simple);
182 else
183 pp_string (pp, "NULL");
184 pp_newline (pp);
185 for (unsigned i = 0; i < gimple_call_num_args (m_call); i++)
186 {
187 const svalue *arg_sval = get_arg_svalue (i);
188 pp_printf (pp, "arg %i: ", i);
189 arg_sval->dump_to_pp (pp, simple);
190 pp_newline (pp);
191 }
192}
193
194/* Dump a multiline representation of this call to stderr. */
195
196DEBUG_FUNCTION void
197call_details::dump (bool simple) const
198{
199 pretty_printer pp;
200 pp_format_decoder (&pp) = default_tree_printer;
201 pp_show_color (&pp) = pp_show_color (global_dc->printer);
202 pp.buffer->stream = stderr;
203 dump_to_pp (&pp, simple);
204 pp_flush (&pp);
205}
206
33255ad3
DM
207/* Get a conjured_svalue for this call for REG. */
208
209const svalue *
210call_details::get_or_create_conjured_svalue (const region *reg) const
211{
212 region_model_manager *mgr = m_model->get_manager ();
213 return mgr->get_or_create_conjured_svalue (reg->get_type (), m_call, reg);
214}
215
808f4dfe
DM
216/* Implementations of specific functions. */
217
218/* Handle the on_call_pre part of "alloca". */
219
b5081130 220void
808f4dfe
DM
221region_model::impl_call_alloca (const call_details &cd)
222{
223 const svalue *size_sval = cd.get_arg_svalue (0);
b9365b93 224 const region *new_reg = create_region_for_alloca (size_sval, cd.get_ctxt ());
808f4dfe
DM
225 const svalue *ptr_sval
226 = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
227 cd.maybe_set_lhs (ptr_sval);
808f4dfe
DM
228}
229
230/* Handle a call to "__analyzer_describe".
231
232 Emit a warning describing the 2nd argument (which can be of any
233 type), at the given verbosity level. This is for use when
234 debugging, and may be of use in DejaGnu tests. */
235
236void
237region_model::impl_call_analyzer_describe (const gcall *call,
238 region_model_context *ctxt)
239{
240 tree t_verbosity = gimple_call_arg (call, 0);
241 tree t_val = gimple_call_arg (call, 1);
242 const svalue *sval = get_rvalue (t_val, ctxt);
243 bool simple = zerop (t_verbosity);
244 label_text desc = sval->get_desc (simple);
245 warning_at (call->location, 0, "svalue: %qs", desc.m_buffer);
246}
247
9a2c9579
DM
248/* Handle a call to "__analyzer_dump_capacity".
249
250 Emit a warning describing the capacity of the base region of
251 the region pointed to by the 1st argument.
252 This is for use when debugging, and may be of use in DejaGnu tests. */
253
254void
255region_model::impl_call_analyzer_dump_capacity (const gcall *call,
256 region_model_context *ctxt)
257{
258 tree t_ptr = gimple_call_arg (call, 0);
259 const svalue *sval_ptr = get_rvalue (t_ptr, ctxt);
260 const region *reg = deref_rvalue (sval_ptr, t_ptr, ctxt);
261 const region *base_reg = reg->get_base_region ();
262 const svalue *capacity = get_capacity (base_reg);
263 label_text desc = capacity->get_desc (true);
264 warning_at (call->location, 0, "capacity: %qs", desc.m_buffer);
265}
266
808f4dfe
DM
267/* Handle a call to "__analyzer_eval" by evaluating the input
268 and dumping as a dummy warning, so that test cases can use
269 dg-warning to validate the result (and so unexpected warnings will
270 lead to DejaGnu failures).
271 Broken out as a subroutine to make it easier to put a breakpoint on it
272 - though typically this doesn't help, as we have an SSA name as the arg,
273 and what's more interesting is usually the def stmt for that name. */
274
275void
276region_model::impl_call_analyzer_eval (const gcall *call,
277 region_model_context *ctxt)
278{
279 tree t_arg = gimple_call_arg (call, 0);
280 tristate t = eval_condition (t_arg, NE_EXPR, integer_zero_node, ctxt);
281 warning_at (call->location, 0, "%s", t.as_string ());
282}
283
284/* Handle the on_call_pre part of "__builtin_expect" etc. */
285
b5081130 286void
808f4dfe
DM
287region_model::impl_call_builtin_expect (const call_details &cd)
288{
289 /* __builtin_expect's return value is its initial argument. */
290 const svalue *sval = cd.get_arg_svalue (0);
291 cd.maybe_set_lhs (sval);
808f4dfe
DM
292}
293
294/* Handle the on_call_pre part of "calloc". */
295
b5081130 296void
808f4dfe
DM
297region_model::impl_call_calloc (const call_details &cd)
298{
299 const svalue *nmemb_sval = cd.get_arg_svalue (0);
300 const svalue *size_sval = cd.get_arg_svalue (1);
301 /* TODO: check for overflow here? */
302 const svalue *prod_sval
303 = m_mgr->get_or_create_binop (size_type_node, MULT_EXPR,
304 nmemb_sval, size_sval);
b9365b93
DM
305 const region *new_reg
306 = create_region_for_heap_alloc (prod_sval, cd.get_ctxt ());
808f4dfe
DM
307 zero_fill_region (new_reg);
308 if (cd.get_lhs_type ())
309 {
310 const svalue *ptr_sval
311 = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
312 cd.maybe_set_lhs (ptr_sval);
313 }
808f4dfe
DM
314}
315
5ee4ba03
DM
316/* Handle the on_call_pre part of "error" and "error_at_line" from
317 GNU's non-standard <error.h>.
318 MIN_ARGS identifies the minimum number of expected arguments
319 to be consistent with such a call (3 and 5 respectively).
320 Return true if handling it as one of these functions.
321 Write true to *OUT_TERMINATE_PATH if this execution path should be
322 terminated (e.g. the function call terminates the process). */
323
324bool
325region_model::impl_call_error (const call_details &cd, unsigned min_args,
326 bool *out_terminate_path)
327{
328 /* Bail if not enough args. */
329 if (cd.num_args () < min_args)
330 return false;
331
332 /* Initial argument ought to be of type "int". */
333 if (cd.get_arg_type (0) != integer_type_node)
334 return false;
335
336 /* The process exits if status != 0, so it only continues
337 for the case where status == 0.
338 Add that constraint, or terminate this analysis path. */
339 tree status = cd.get_arg_tree (0);
340 if (!add_constraint (status, EQ_EXPR, integer_zero_node, cd.get_ctxt ()))
341 *out_terminate_path = true;
342
343 return true;
344}
345
33255ad3
DM
346/* Handle the on_call_pre part of "fgets" and "fgets_unlocked". */
347
348void
349region_model::impl_call_fgets (const call_details &cd)
350{
351 /* Ideally we would bifurcate state here between the
352 error vs no error cases. */
353 const svalue *ptr_sval = cd.get_arg_svalue (0);
5932dd35 354 if (const region *reg = ptr_sval->maybe_get_region ())
33255ad3 355 {
33255ad3
DM
356 const region *base_reg = reg->get_base_region ();
357 const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg);
358 purge_state_involving (new_sval, cd.get_ctxt ());
359 set_value (base_reg, new_sval, cd.get_ctxt ());
360 }
361}
362
363/* Handle the on_call_pre part of "fread". */
364
365void
366region_model::impl_call_fread (const call_details &cd)
367{
368 const svalue *ptr_sval = cd.get_arg_svalue (0);
5932dd35 369 if (const region *reg = ptr_sval->maybe_get_region ())
33255ad3 370 {
33255ad3
DM
371 const region *base_reg = reg->get_base_region ();
372 const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg);
373 purge_state_involving (new_sval, cd.get_ctxt ());
374 set_value (base_reg, new_sval, cd.get_ctxt ());
375 }
376}
377
808f4dfe
DM
378/* Handle the on_call_post part of "free", after sm-handling.
379
380 If the ptr points to an underlying heap region, delete the region,
381 poisoning pointers to it and regions within it.
382
383 We delay this until after sm-state has been updated so that the
384 sm-handling can transition all of the various casts of the pointer
385 to a "freed" state *before* we delete the related region here.
386
387 This has to be done here so that the sm-handling can use the fact
388 that they point to the same region to establish that they are equal
389 (in region_model::eval_condition_without_cm), and thus transition
390 all pointers to the region to the "freed" state together, regardless
391 of casts. */
392
393void
394region_model::impl_call_free (const call_details &cd)
395{
396 const svalue *ptr_sval = cd.get_arg_svalue (0);
5932dd35 397 if (const region *freed_reg = ptr_sval->maybe_get_region ())
808f4dfe
DM
398 {
399 /* If the ptr points to an underlying heap region, delete it,
400 poisoning pointers. */
808f4dfe 401 unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
9a2c9579 402 m_dynamic_extents.remove (freed_reg);
808f4dfe
DM
403 }
404}
405
406/* Handle the on_call_pre part of "malloc". */
407
b5081130 408void
808f4dfe
DM
409region_model::impl_call_malloc (const call_details &cd)
410{
411 const svalue *size_sval = cd.get_arg_svalue (0);
b9365b93
DM
412 const region *new_reg
413 = create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
808f4dfe
DM
414 if (cd.get_lhs_type ())
415 {
416 const svalue *ptr_sval
417 = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
418 cd.maybe_set_lhs (ptr_sval);
419 }
808f4dfe
DM
420}
421
b7028f06
DM
422/* Handle the on_call_pre part of "memcpy" and "__builtin_memcpy". */
423
424void
425region_model::impl_call_memcpy (const call_details &cd)
426{
427 const svalue *dest_sval = cd.get_arg_svalue (0);
428 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
429
430 const region *dest_reg = deref_rvalue (dest_sval, cd.get_arg_tree (0),
431 cd.get_ctxt ());
432
433 cd.maybe_set_lhs (dest_sval);
434
435 if (tree num_bytes = num_bytes_sval->maybe_get_constant ())
436 {
437 /* "memcpy" of zero size is a no-op. */
438 if (zerop (num_bytes))
439 return;
440 }
441
9faf8348 442 check_region_for_write (dest_reg, cd.get_ctxt ());
3175d40f 443
b7028f06 444 /* Otherwise, mark region's contents as unknown. */
3a66c289 445 mark_region_as_unknown (dest_reg, cd.get_uncertainty ());
b7028f06
DM
446}
447
808f4dfe
DM
448/* Handle the on_call_pre part of "memset" and "__builtin_memset". */
449
b5081130 450void
808f4dfe
DM
451region_model::impl_call_memset (const call_details &cd)
452{
453 const svalue *dest_sval = cd.get_arg_svalue (0);
454 const svalue *fill_value_sval = cd.get_arg_svalue (1);
455 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
456
457 const region *dest_reg = deref_rvalue (dest_sval, cd.get_arg_tree (0),
458 cd.get_ctxt ());
459
e61ffa20
DM
460 const svalue *fill_value_u8
461 = m_mgr->get_or_create_cast (unsigned_char_type_node, fill_value_sval);
462
463 const region *sized_dest_reg = m_mgr->get_sized_region (dest_reg,
464 NULL_TREE,
465 num_bytes_sval);
9faf8348 466 check_region_for_write (sized_dest_reg, cd.get_ctxt ());
e61ffa20 467 fill_region (sized_dest_reg, fill_value_u8);
808f4dfe
DM
468}
469
1690a839
DM
470/* Handle the on_call_pre part of "operator new". */
471
b5081130 472void
1690a839
DM
473region_model::impl_call_operator_new (const call_details &cd)
474{
475 const svalue *size_sval = cd.get_arg_svalue (0);
b9365b93
DM
476 const region *new_reg
477 = create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
1690a839
DM
478 if (cd.get_lhs_type ())
479 {
480 const svalue *ptr_sval
481 = m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
482 cd.maybe_set_lhs (ptr_sval);
483 }
1690a839
DM
484}
485
486/* Handle the on_call_pre part of "operator delete", which comes in
487 both sized and unsized variants (2 arguments and 1 argument
488 respectively). */
489
b5081130 490void
1690a839
DM
491region_model::impl_call_operator_delete (const call_details &cd)
492{
493 const svalue *ptr_sval = cd.get_arg_svalue (0);
5932dd35 494 if (const region *freed_reg = ptr_sval->maybe_get_region ())
1690a839
DM
495 {
496 /* If the ptr points to an underlying heap region, delete it,
497 poisoning pointers. */
1690a839
DM
498 unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
499 }
1690a839
DM
500}
501
eafa9d96
DM
502/* Handle the on_call_post part of "realloc":
503
504 void *realloc(void *ptr, size_t size);
505
506 realloc(3) is awkward, since it has various different outcomes
507 that are best modelled as separate exploded nodes/edges.
508
509 We first check for sm-state, in
510 malloc_state_machine::on_realloc_call, so that we
511 can complain about issues such as realloc of a non-heap
512 pointer, and terminate the path for such cases (and issue
513 the complaints at the call's exploded node).
514
515 Assuming that these checks pass, we split the path here into
516 three special cases (and terminate the "standard" path):
517 (A) failure, returning NULL
518 (B) success, growing the buffer in-place without moving it
519 (C) success, allocating a new buffer, copying the content
520 of the old buffer to it, and freeing the old buffer.
521
522 Each of these has a custom_edge_info subclass, which updates
523 the region_model and sm-state of the destination state. */
a6baafca
DM
524
525void
eafa9d96 526region_model::impl_call_realloc (const call_details &cd)
a6baafca 527{
eafa9d96
DM
528 /* Three custom subclasses of custom_edge_info, for handling the various
529 outcomes of "realloc". */
530
531 /* Concrete custom_edge_info: a realloc call that fails, returning NULL. */
532 class failure : public failed_call_info
533 {
534 public:
535 failure (const call_details &cd)
536 : failed_call_info (cd)
537 {
538 }
539
540 bool update_model (region_model *model,
541 const exploded_edge *,
542 region_model_context *ctxt) const FINAL OVERRIDE
543 {
544 /* Return NULL; everything else is unchanged. */
545 const call_details cd (get_call_details (model, ctxt));
e66b9f67
DM
546 if (cd.get_lhs_type ())
547 {
548 const svalue *zero
549 = model->m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
550 model->set_value (cd.get_lhs_region (),
551 zero,
552 cd.get_ctxt ());
553 }
eafa9d96
DM
554 return true;
555 }
556 };
557
558 /* Concrete custom_edge_info: a realloc call that succeeds, growing
559 the existing buffer without moving it. */
560 class success_no_move : public call_info
561 {
562 public:
563 success_no_move (const call_details &cd)
564 : call_info (cd)
565 {
566 }
567
568 label_text get_desc (bool can_colorize) const FINAL OVERRIDE
569 {
570 return make_label_text (can_colorize,
571 "when %qE succeeds, without moving buffer",
572 get_fndecl ());
573 }
574
575 bool update_model (region_model *model,
576 const exploded_edge *,
577 region_model_context *ctxt) const FINAL OVERRIDE
578 {
579 /* Update size of buffer and return the ptr unchanged. */
580 const call_details cd (get_call_details (model, ctxt));
581 const svalue *ptr_sval = cd.get_arg_svalue (0);
582 const svalue *size_sval = cd.get_arg_svalue (1);
583 if (const region *buffer_reg = ptr_sval->maybe_get_region ())
e66b9f67 584 if (compat_types_p (size_sval->get_type (), size_type_node))
b9365b93 585 model->set_dynamic_extents (buffer_reg, size_sval, ctxt);
e66b9f67
DM
586 if (cd.get_lhs_region ())
587 {
588 model->set_value (cd.get_lhs_region (), ptr_sval, cd.get_ctxt ());
589 const svalue *zero
590 = model->m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
591 return model->add_constraint (ptr_sval, NE_EXPR, zero, cd.get_ctxt ());
592 }
593 else
594 return true;
eafa9d96
DM
595 }
596 };
597
598 /* Concrete custom_edge_info: a realloc call that succeeds, freeing
599 the existing buffer and moving the content to a freshly allocated
600 buffer. */
601 class success_with_move : public call_info
602 {
603 public:
604 success_with_move (const call_details &cd)
605 : call_info (cd)
606 {
607 }
608
609 label_text get_desc (bool can_colorize) const FINAL OVERRIDE
610 {
611 return make_label_text (can_colorize,
612 "when %qE succeeds, moving buffer",
613 get_fndecl ());
614 }
615 bool update_model (region_model *model,
616 const exploded_edge *,
617 region_model_context *ctxt) const FINAL OVERRIDE
618 {
619 const call_details cd (get_call_details (model, ctxt));
620 const svalue *old_ptr_sval = cd.get_arg_svalue (0);
621 const svalue *new_size_sval = cd.get_arg_svalue (1);
622
623 /* Create the new region. */
624 const region *new_reg
b9365b93 625 = model->create_region_for_heap_alloc (new_size_sval, ctxt);
eafa9d96
DM
626 const svalue *new_ptr_sval
627 = model->m_mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
628 if (cd.get_lhs_type ())
629 cd.maybe_set_lhs (new_ptr_sval);
630
631 if (const region *freed_reg = old_ptr_sval->maybe_get_region ())
632 {
633 /* Copy the data. */
634 const svalue *old_size_sval = model->get_dynamic_extents (freed_reg);
635 if (old_size_sval)
636 {
637 const region *sized_old_reg
638 = model->m_mgr->get_sized_region (freed_reg, NULL,
639 old_size_sval);
640 const svalue *buffer_content_sval
641 = model->get_store_value (sized_old_reg, cd.get_ctxt ());
642 model->set_value (new_reg, buffer_content_sval, cd.get_ctxt ());
643 }
644
645 /* Free the old region, so that pointers to the old buffer become
646 invalid. */
647
648 /* If the ptr points to an underlying heap region, delete it,
649 poisoning pointers. */
650 model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
651 model->m_dynamic_extents.remove (freed_reg);
652 }
653
654 /* Update the sm-state: mark the old_ptr_sval as "freed",
655 and the new_ptr_sval as "nonnull". */
656 model->on_realloc_with_move (cd, old_ptr_sval, new_ptr_sval);
657
e66b9f67
DM
658 if (cd.get_lhs_type ())
659 {
660 const svalue *zero
661 = model->m_mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
662 return model->add_constraint (new_ptr_sval, NE_EXPR, zero,
663 cd.get_ctxt ());
664 }
665 else
666 return true;
eafa9d96
DM
667 }
668 };
669
670 /* Body of region_model::impl_call_realloc. */
671
672 if (cd.get_ctxt ())
673 {
674 cd.get_ctxt ()->bifurcate (new failure (cd));
675 cd.get_ctxt ()->bifurcate (new success_no_move (cd));
676 cd.get_ctxt ()->bifurcate (new success_with_move (cd));
677 cd.get_ctxt ()->terminate_path ();
678 }
a6baafca
DM
679}
680
111fd515
DM
681/* Handle the on_call_pre part of "strchr" and "__builtin_strchr". */
682
683void
684region_model::impl_call_strchr (const call_details &cd)
685{
686 class strchr_call_info : public call_info
687 {
688 public:
689 strchr_call_info (const call_details &cd, bool found)
690 : call_info (cd), m_found (found)
691 {
692 }
693
694 label_text get_desc (bool can_colorize) const FINAL OVERRIDE
695 {
696 if (m_found)
697 return make_label_text (can_colorize,
698 "when %qE returns non-NULL",
699 get_fndecl ());
700 else
701 return make_label_text (can_colorize,
702 "when %qE returns NULL",
703 get_fndecl ());
704 }
705
706 bool update_model (region_model *model,
707 const exploded_edge *,
708 region_model_context *ctxt) const FINAL OVERRIDE
709 {
710 const call_details cd (get_call_details (model, ctxt));
711 if (tree lhs_type = cd.get_lhs_type ())
712 {
713 region_model_manager *mgr = model->get_manager ();
714 const svalue *result;
715 if (m_found)
716 {
717 const svalue *str_sval = cd.get_arg_svalue (0);
718 const region *str_reg
719 = model->deref_rvalue (str_sval, cd.get_arg_tree (0),
720 cd.get_ctxt ());
721 /* We want str_sval + OFFSET for some unknown OFFSET.
722 Use a conjured_svalue to represent the offset,
723 using the str_reg as the id of the conjured_svalue. */
724 const svalue *offset
725 = mgr->get_or_create_conjured_svalue (size_type_node,
726 cd.get_call_stmt (),
727 str_reg);
728 result = mgr->get_or_create_binop (lhs_type, POINTER_PLUS_EXPR,
729 str_sval, offset);
730 }
731 else
732 result = mgr->get_or_create_int_cst (lhs_type, 0);
733 cd.maybe_set_lhs (result);
734 }
735 return true;
736 }
737 private:
738 bool m_found;
739 };
740
741 /* Bifurcate state, creating a "not found" out-edge. */
742 if (cd.get_ctxt ())
743 cd.get_ctxt ()->bifurcate (new strchr_call_info (cd, false));
744
745 /* The "unbifurcated" state is the "found" case. */
746 strchr_call_info found (cd, true);
747 found.update_model (this, NULL, cd.get_ctxt ());
748}
749
b7028f06
DM
750/* Handle the on_call_pre part of "strcpy" and "__builtin_strcpy_chk". */
751
752void
753region_model::impl_call_strcpy (const call_details &cd)
754{
755 const svalue *dest_sval = cd.get_arg_svalue (0);
756 const region *dest_reg = deref_rvalue (dest_sval, cd.get_arg_tree (0),
757 cd.get_ctxt ());
758
759 cd.maybe_set_lhs (dest_sval);
760
9faf8348 761 check_region_for_write (dest_reg, cd.get_ctxt ());
3175d40f 762
b7028f06 763 /* For now, just mark region's contents as unknown. */
3a66c289 764 mark_region_as_unknown (dest_reg, cd.get_uncertainty ());
b7028f06
DM
765}
766
b5081130 767/* Handle the on_call_pre part of "strlen". */
808f4dfe 768
b5081130 769void
808f4dfe
DM
770region_model::impl_call_strlen (const call_details &cd)
771{
772 region_model_context *ctxt = cd.get_ctxt ();
773 const svalue *arg_sval = cd.get_arg_svalue (0);
774 const region *buf_reg = deref_rvalue (arg_sval, cd.get_arg_tree (0), ctxt);
775 if (const string_region *str_reg
776 = buf_reg->dyn_cast_string_region ())
777 {
778 tree str_cst = str_reg->get_string_cst ();
779 /* TREE_STRING_LENGTH is sizeof, not strlen. */
780 int sizeof_cst = TREE_STRING_LENGTH (str_cst);
781 int strlen_cst = sizeof_cst - 1;
782 if (cd.get_lhs_type ())
783 {
784 tree t_cst = build_int_cst (cd.get_lhs_type (), strlen_cst);
785 const svalue *result_sval
786 = m_mgr->get_or_create_constant_svalue (t_cst);
787 cd.maybe_set_lhs (result_sval);
b5081130 788 return;
808f4dfe
DM
789 }
790 }
b5081130 791 /* Otherwise a conjured value. */
808f4dfe
DM
792}
793
c7e276b8
DM
794/* Handle calls to functions referenced by
795 __attribute__((malloc(FOO))). */
796
797void
798region_model::impl_deallocation_call (const call_details &cd)
799{
800 impl_call_free (cd);
801}
802
808f4dfe
DM
803} // namespace ana
804
805#endif /* #if ENABLE_ANALYZER */