d: Add test for PR d/108167 to the testsuite [PR108167]
[official-gcc.git] / gcc / analyzer / kf.cc
blobed5f70398e1d2930855217c11f972775b183433d
1 /* Handling for the known behavior of various specific functions.
2 Copyright (C) 2020-2023 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
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 "diagnostic-core.h"
30 #include "diagnostic-metadata.h"
31 #include "analyzer/analyzer.h"
32 #include "analyzer/analyzer-logging.h"
33 #include "diagnostic.h"
34 #include "analyzer/region-model.h"
35 #include "analyzer/call-details.h"
36 #include "analyzer/call-info.h"
37 #include "make-unique.h"
39 #if ENABLE_ANALYZER
41 namespace ana {
43 /* Implementations of specific functions. */
45 /* Handler for "alloca". */
47 class kf_alloca : public known_function
49 public:
50 bool matches_call_types_p (const call_details &cd) const final override
52 return cd.num_args () == 1;
54 void impl_call_pre (const call_details &cd) const final override;
57 void
58 kf_alloca::impl_call_pre (const call_details &cd) const
60 const svalue *size_sval = cd.get_arg_svalue (0);
62 region_model *model = cd.get_model ();
63 region_model_manager *mgr = cd.get_manager ();
65 const region *new_reg
66 = model->create_region_for_alloca (size_sval, cd.get_ctxt ());
67 const svalue *ptr_sval
68 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
69 cd.maybe_set_lhs (ptr_sval);
72 /* Handler for "__builtin_expect" etc. */
74 class kf_expect : public internal_known_function
76 public:
77 void impl_call_pre (const call_details &cd) const final override
79 /* __builtin_expect's return value is its initial argument. */
80 const svalue *sval = cd.get_arg_svalue (0);
81 cd.maybe_set_lhs (sval);
85 /* Handler for "calloc". */
87 class kf_calloc : public known_function
89 public:
90 bool matches_call_types_p (const call_details &cd) const final override
92 return (cd.num_args () == 2
93 && cd.arg_is_size_p (0)
94 && cd.arg_is_size_p (1));
96 void impl_call_pre (const call_details &cd) const final override;
99 void
100 kf_calloc::impl_call_pre (const call_details &cd) const
102 region_model *model = cd.get_model ();
103 region_model_manager *mgr = cd.get_manager ();
104 const svalue *nmemb_sval = cd.get_arg_svalue (0);
105 const svalue *size_sval = cd.get_arg_svalue (1);
106 /* TODO: check for overflow here? */
107 const svalue *prod_sval
108 = mgr->get_or_create_binop (size_type_node, MULT_EXPR,
109 nmemb_sval, size_sval);
110 const region *new_reg
111 = model->get_or_create_region_for_heap_alloc (prod_sval, cd.get_ctxt ());
112 const region *sized_reg
113 = mgr->get_sized_region (new_reg, NULL_TREE, prod_sval);
114 model->zero_fill_region (sized_reg);
115 if (cd.get_lhs_type ())
117 const svalue *ptr_sval
118 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
119 cd.maybe_set_lhs (ptr_sval);
123 /* Handler for glibc's "__errno_location". */
125 class kf_errno_location : public known_function
127 public:
128 bool matches_call_types_p (const call_details &cd) const final override
130 return cd.num_args () == 0;
133 void impl_call_pre (const call_details &cd) const final override
135 if (cd.get_lhs_region ())
137 region_model_manager *mgr = cd.get_manager ();
138 const region *errno_reg = mgr->get_errno_region ();
139 const svalue *errno_ptr = mgr->get_ptr_svalue (cd.get_lhs_type (),
140 errno_reg);
141 cd.maybe_set_lhs (errno_ptr);
146 /* Handler for "error" and "error_at_line" from GNU's non-standard <error.h>.
147 MIN_ARGS identifies the minimum number of expected arguments
148 to be consistent with such a call (3 and 5 respectively). */
150 class kf_error : public known_function
152 public:
153 kf_error (unsigned min_args) : m_min_args (min_args) {}
155 bool matches_call_types_p (const call_details &cd) const final override
157 return (cd.num_args () >= m_min_args
158 && cd.get_arg_type (0) == integer_type_node);
161 void impl_call_pre (const call_details &cd) const final override;
163 private:
164 unsigned m_min_args;
167 void
168 kf_error::impl_call_pre (const call_details &cd) const
170 /* The process exits if status != 0, so it only continues
171 for the case where status == 0.
172 Add that constraint, or terminate this analysis path. */
173 tree status = cd.get_arg_tree (0);
174 region_model_context *ctxt = cd.get_ctxt ();
175 region_model *model = cd.get_model ();
176 if (!model->add_constraint (status, EQ_EXPR, integer_zero_node, ctxt))
177 if (ctxt)
178 ctxt->terminate_path ();
181 /* Handler for "free", after sm-handling.
183 If the ptr points to an underlying heap region, delete the region,
184 poisoning pointers to it and regions within it.
186 We delay this until after sm-state has been updated so that the
187 sm-handling can transition all of the various casts of the pointer
188 to a "freed" state *before* we delete the related region here.
190 This has to be done here so that the sm-handling can use the fact
191 that they point to the same region to establish that they are equal
192 (in region_model::eval_condition), and thus transition
193 all pointers to the region to the "freed" state together, regardless
194 of casts. */
196 class kf_free : public known_function
198 public:
199 bool matches_call_types_p (const call_details &cd) const final override
201 return (cd.num_args () == 0 && cd.arg_is_pointer_p (0));
203 void impl_call_post (const call_details &cd) const final override;
206 void
207 kf_free::impl_call_post (const call_details &cd) const
209 const svalue *ptr_sval = cd.get_arg_svalue (0);
210 if (const region *freed_reg = ptr_sval->maybe_get_region ())
212 /* If the ptr points to an underlying heap region, delete it,
213 poisoning pointers. */
214 region_model *model = cd.get_model ();
215 model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
216 model->unset_dynamic_extents (freed_reg);
220 /* Handle the on_call_pre part of "malloc". */
222 class kf_malloc : public known_function
224 public:
225 bool matches_call_types_p (const call_details &cd) const final override
227 return (cd.num_args () == 1
228 && cd.arg_is_size_p (0));
230 void impl_call_pre (const call_details &cd) const final override;
233 void
234 kf_malloc::impl_call_pre (const call_details &cd) const
236 region_model *model = cd.get_model ();
237 region_model_manager *mgr = cd.get_manager ();
238 const svalue *size_sval = cd.get_arg_svalue (0);
239 const region *new_reg
240 = model->get_or_create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
241 if (cd.get_lhs_type ())
243 const svalue *ptr_sval
244 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
245 cd.maybe_set_lhs (ptr_sval);
249 /* Handler for "memcpy" and "__builtin_memcpy",
250 "memmove", and "__builtin_memmove". */
251 /* TODO: complain about overlapping src and dest for the memcpy
252 variants. */
254 class kf_memcpy_memmove : public known_function
256 public:
257 bool matches_call_types_p (const call_details &cd) const final override
259 return (cd.num_args () == 3
260 && cd.arg_is_pointer_p (0)
261 && cd.arg_is_pointer_p (1)
262 && cd.arg_is_size_p (2));
264 void impl_call_pre (const call_details &cd) const final override;
267 void
268 kf_memcpy_memmove::impl_call_pre (const call_details &cd) const
270 const svalue *dest_ptr_sval = cd.get_arg_svalue (0);
271 const svalue *src_ptr_sval = cd.get_arg_svalue (1);
272 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
274 region_model *model = cd.get_model ();
275 region_model_manager *mgr = cd.get_manager ();
277 const region *dest_reg
278 = model->deref_rvalue (dest_ptr_sval, cd.get_arg_tree (0), cd.get_ctxt ());
279 const region *src_reg
280 = model->deref_rvalue (src_ptr_sval, cd.get_arg_tree (1), cd.get_ctxt ());
282 cd.maybe_set_lhs (dest_ptr_sval);
284 const region *sized_src_reg
285 = mgr->get_sized_region (src_reg, NULL_TREE, num_bytes_sval);
286 const region *sized_dest_reg
287 = mgr->get_sized_region (dest_reg, NULL_TREE, num_bytes_sval);
288 const svalue *src_contents_sval
289 = model->get_store_value (sized_src_reg, cd.get_ctxt ());
290 model->check_for_poison (src_contents_sval, cd.get_arg_tree (1),
291 sized_src_reg, cd.get_ctxt ());
292 model->set_value (sized_dest_reg, src_contents_sval, cd.get_ctxt ());
295 /* Handler for "memset" and "__builtin_memset". */
297 class kf_memset : public known_function
299 public:
300 bool matches_call_types_p (const call_details &cd) const final override
302 return (cd.num_args () == 3 && cd.arg_is_pointer_p (0));
305 void impl_call_pre (const call_details &cd) const final override;
308 void
309 kf_memset::impl_call_pre (const call_details &cd) const
311 const svalue *dest_sval = cd.get_arg_svalue (0);
312 const svalue *fill_value_sval = cd.get_arg_svalue (1);
313 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
315 region_model *model = cd.get_model ();
316 region_model_manager *mgr = cd.get_manager ();
318 const region *dest_reg
319 = model->deref_rvalue (dest_sval, cd.get_arg_tree (0), cd.get_ctxt ());
321 const svalue *fill_value_u8
322 = mgr->get_or_create_cast (unsigned_char_type_node, fill_value_sval);
324 const region *sized_dest_reg = mgr->get_sized_region (dest_reg,
325 NULL_TREE,
326 num_bytes_sval);
327 model->check_region_for_write (sized_dest_reg, cd.get_ctxt ());
328 model->fill_region (sized_dest_reg, fill_value_u8);
331 /* A subclass of pending_diagnostic for complaining about 'putenv'
332 called on an auto var. */
334 class putenv_of_auto_var
335 : public pending_diagnostic_subclass<putenv_of_auto_var>
337 public:
338 putenv_of_auto_var (tree fndecl, const region *reg)
339 : m_fndecl (fndecl), m_reg (reg),
340 m_var_decl (reg->get_base_region ()->maybe_get_decl ())
344 const char *get_kind () const final override
346 return "putenv_of_auto_var";
349 bool operator== (const putenv_of_auto_var &other) const
351 return (m_fndecl == other.m_fndecl
352 && m_reg == other.m_reg
353 && same_tree_p (m_var_decl, other.m_var_decl));
356 int get_controlling_option () const final override
358 return OPT_Wanalyzer_putenv_of_auto_var;
361 bool emit (rich_location *rich_loc) final override
363 auto_diagnostic_group d;
364 diagnostic_metadata m;
366 /* SEI CERT C Coding Standard: "POS34-C. Do not call putenv() with a
367 pointer to an automatic variable as the argument". */
368 diagnostic_metadata::precanned_rule
369 rule ("POS34-C", "https://wiki.sei.cmu.edu/confluence/x/6NYxBQ");
370 m.add_rule (rule);
372 bool warned;
373 if (m_var_decl)
374 warned = warning_meta (rich_loc, m, get_controlling_option (),
375 "%qE on a pointer to automatic variable %qE",
376 m_fndecl, m_var_decl);
377 else
378 warned = warning_meta (rich_loc, m, get_controlling_option (),
379 "%qE on a pointer to an on-stack buffer",
380 m_fndecl);
381 if (warned)
383 if (m_var_decl)
384 inform (DECL_SOURCE_LOCATION (m_var_decl),
385 "%qE declared on stack here", m_var_decl);
386 inform (rich_loc->get_loc (), "perhaps use %qs rather than %qE",
387 "setenv", m_fndecl);
390 return warned;
393 label_text describe_final_event (const evdesc::final_event &ev) final override
395 if (m_var_decl)
396 return ev.formatted_print ("%qE on a pointer to automatic variable %qE",
397 m_fndecl, m_var_decl);
398 else
399 return ev.formatted_print ("%qE on a pointer to an on-stack buffer",
400 m_fndecl);
403 void mark_interesting_stuff (interesting_t *interest) final override
405 if (!m_var_decl)
406 interest->add_region_creation (m_reg->get_base_region ());
409 private:
410 tree m_fndecl; // non-NULL
411 const region *m_reg; // non-NULL
412 tree m_var_decl; // could be NULL
415 /* Handler for calls to "putenv".
417 In theory we could try to model the state of the environment variables
418 for the process; for now we merely complain about putenv of regions
419 on the stack. */
421 class kf_putenv : public known_function
423 public:
424 bool matches_call_types_p (const call_details &cd) const final override
426 return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
429 void impl_call_pre (const call_details &cd) const final override
431 tree fndecl = cd.get_fndecl_for_call ();
432 gcc_assert (fndecl);
433 region_model_context *ctxt = cd.get_ctxt ();
434 region_model *model = cd.get_model ();
435 const svalue *ptr_sval = cd.get_arg_svalue (0);
436 const region *reg
437 = model->deref_rvalue (ptr_sval, cd.get_arg_tree (0), ctxt);
438 model->get_store ()->mark_as_escaped (reg);
439 enum memory_space mem_space = reg->get_memory_space ();
440 switch (mem_space)
442 default:
443 gcc_unreachable ();
444 case MEMSPACE_UNKNOWN:
445 case MEMSPACE_CODE:
446 case MEMSPACE_GLOBALS:
447 case MEMSPACE_HEAP:
448 case MEMSPACE_READONLY_DATA:
449 break;
450 case MEMSPACE_STACK:
451 if (ctxt)
452 ctxt->warn (make_unique<putenv_of_auto_var> (fndecl, reg));
453 break;
458 /* Handler for "realloc":
460 void *realloc(void *ptr, size_t size);
462 realloc(3) is awkward, since it has various different outcomes
463 that are best modelled as separate exploded nodes/edges.
465 We first check for sm-state, in
466 malloc_state_machine::on_realloc_call, so that we
467 can complain about issues such as realloc of a non-heap
468 pointer, and terminate the path for such cases (and issue
469 the complaints at the call's exploded node).
471 Assuming that these checks pass, we split the path here into
472 three special cases (and terminate the "standard" path):
473 (A) failure, returning NULL
474 (B) success, growing the buffer in-place without moving it
475 (C) success, allocating a new buffer, copying the content
476 of the old buffer to it, and freeing the old buffer.
478 Each of these has a custom_edge_info subclass, which updates
479 the region_model and sm-state of the destination state. */
481 class kf_realloc : public known_function
483 public:
484 bool matches_call_types_p (const call_details &cd) const final override
486 return (cd.num_args () == 2
487 && cd.arg_is_pointer_p (0)
488 && cd.arg_is_size_p (1));
490 void impl_call_post (const call_details &cd) const final override;
493 void
494 kf_realloc::impl_call_post (const call_details &cd) const
496 /* Three custom subclasses of custom_edge_info, for handling the various
497 outcomes of "realloc". */
499 /* Concrete custom_edge_info: a realloc call that fails, returning NULL. */
500 class failure : public failed_call_info
502 public:
503 failure (const call_details &cd)
504 : failed_call_info (cd)
508 bool update_model (region_model *model,
509 const exploded_edge *,
510 region_model_context *ctxt) const final override
512 /* Return NULL; everything else is unchanged. */
513 const call_details cd (get_call_details (model, ctxt));
514 region_model_manager *mgr = cd.get_manager ();
515 if (cd.get_lhs_type ())
517 const svalue *zero
518 = mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
519 model->set_value (cd.get_lhs_region (),
520 zero,
521 cd.get_ctxt ());
523 return true;
527 /* Concrete custom_edge_info: a realloc call that succeeds, growing
528 the existing buffer without moving it. */
529 class success_no_move : public call_info
531 public:
532 success_no_move (const call_details &cd)
533 : call_info (cd)
537 label_text get_desc (bool can_colorize) const final override
539 return make_label_text (can_colorize,
540 "when %qE succeeds, without moving buffer",
541 get_fndecl ());
544 bool update_model (region_model *model,
545 const exploded_edge *,
546 region_model_context *ctxt) const final override
548 /* Update size of buffer and return the ptr unchanged. */
549 const call_details cd (get_call_details (model, ctxt));
550 region_model_manager *mgr = cd.get_manager ();
551 const svalue *ptr_sval = cd.get_arg_svalue (0);
552 const svalue *size_sval = cd.get_arg_svalue (1);
554 /* We can only grow in place with a non-NULL pointer. */
556 const svalue *null_ptr
557 = mgr->get_or_create_int_cst (ptr_sval->get_type (), 0);
558 if (!model->add_constraint (ptr_sval, NE_EXPR, null_ptr,
559 cd.get_ctxt ()))
560 return false;
563 if (const region *buffer_reg = model->deref_rvalue (ptr_sval, NULL_TREE,
564 ctxt))
565 if (compat_types_p (size_sval->get_type (), size_type_node))
566 model->set_dynamic_extents (buffer_reg, size_sval, ctxt);
567 if (cd.get_lhs_region ())
569 model->set_value (cd.get_lhs_region (), ptr_sval, cd.get_ctxt ());
570 const svalue *zero
571 = mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
572 return model->add_constraint (ptr_sval, NE_EXPR, zero, ctxt);
574 else
575 return true;
579 /* Concrete custom_edge_info: a realloc call that succeeds, freeing
580 the existing buffer and moving the content to a freshly allocated
581 buffer. */
582 class success_with_move : public call_info
584 public:
585 success_with_move (const call_details &cd)
586 : call_info (cd)
590 label_text get_desc (bool can_colorize) const final override
592 return make_label_text (can_colorize,
593 "when %qE succeeds, moving buffer",
594 get_fndecl ());
596 bool update_model (region_model *model,
597 const exploded_edge *,
598 region_model_context *ctxt) const final override
600 const call_details cd (get_call_details (model, ctxt));
601 region_model_manager *mgr = cd.get_manager ();
602 const svalue *old_ptr_sval = cd.get_arg_svalue (0);
603 const svalue *new_size_sval = cd.get_arg_svalue (1);
605 /* Create the new region. */
606 const region *new_reg
607 = model->get_or_create_region_for_heap_alloc (new_size_sval, ctxt);
608 const svalue *new_ptr_sval
609 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
610 if (!model->add_constraint (new_ptr_sval, NE_EXPR, old_ptr_sval,
611 cd.get_ctxt ()))
612 return false;
614 if (cd.get_lhs_type ())
615 cd.maybe_set_lhs (new_ptr_sval);
617 if (const region *freed_reg = model->deref_rvalue (old_ptr_sval,
618 NULL_TREE, ctxt))
620 /* Copy the data. */
621 const svalue *old_size_sval = model->get_dynamic_extents (freed_reg);
622 if (old_size_sval)
624 const svalue *copied_size_sval
625 = get_copied_size (model, old_size_sval, new_size_sval);
626 const region *copied_old_reg
627 = mgr->get_sized_region (freed_reg, NULL, copied_size_sval);
628 const svalue *buffer_content_sval
629 = model->get_store_value (copied_old_reg, cd.get_ctxt ());
630 const region *copied_new_reg
631 = mgr->get_sized_region (new_reg, NULL, copied_size_sval);
632 model->set_value (copied_new_reg, buffer_content_sval,
633 cd.get_ctxt ());
635 else
637 /* We don't know how big the old region was;
638 mark the new region as having been touched to avoid uninit
639 issues. */
640 model->mark_region_as_unknown (new_reg, cd.get_uncertainty ());
643 /* Free the old region, so that pointers to the old buffer become
644 invalid. */
646 /* If the ptr points to an underlying heap region, delete it,
647 poisoning pointers. */
648 model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
649 model->unset_dynamic_extents (freed_reg);
652 /* Update the sm-state: mark the old_ptr_sval as "freed",
653 and the new_ptr_sval as "nonnull". */
654 model->on_realloc_with_move (cd, old_ptr_sval, new_ptr_sval);
656 if (cd.get_lhs_type ())
658 const svalue *zero
659 = mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
660 return model->add_constraint (new_ptr_sval, NE_EXPR, zero,
661 cd.get_ctxt ());
663 else
664 return true;
667 private:
668 /* Return the lesser of OLD_SIZE_SVAL and NEW_SIZE_SVAL.
669 If unknown, OLD_SIZE_SVAL is returned. */
670 const svalue *get_copied_size (region_model *model,
671 const svalue *old_size_sval,
672 const svalue *new_size_sval) const
674 tristate res
675 = model->eval_condition (old_size_sval, GT_EXPR, new_size_sval);
676 switch (res.get_value ())
678 case tristate::TS_TRUE:
679 return new_size_sval;
680 case tristate::TS_FALSE:
681 case tristate::TS_UNKNOWN:
682 return old_size_sval;
683 default:
684 gcc_unreachable ();
689 /* Body of kf_realloc::impl_call_post. */
691 if (cd.get_ctxt ())
693 cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
694 cd.get_ctxt ()->bifurcate (make_unique<success_no_move> (cd));
695 cd.get_ctxt ()->bifurcate (make_unique<success_with_move> (cd));
696 cd.get_ctxt ()->terminate_path ();
700 /* Handler for "strchr" and "__builtin_strchr". */
702 class kf_strchr : public known_function
704 public:
705 bool matches_call_types_p (const call_details &cd) const final override
707 return (cd.num_args () == 2 && cd.arg_is_pointer_p (0));
709 void impl_call_post (const call_details &cd) const final override;
712 void
713 kf_strchr::impl_call_post (const call_details &cd) const
715 class strchr_call_info : public call_info
717 public:
718 strchr_call_info (const call_details &cd, bool found)
719 : call_info (cd), m_found (found)
723 label_text get_desc (bool can_colorize) const final override
725 if (m_found)
726 return make_label_text (can_colorize,
727 "when %qE returns non-NULL",
728 get_fndecl ());
729 else
730 return make_label_text (can_colorize,
731 "when %qE returns NULL",
732 get_fndecl ());
735 bool update_model (region_model *model,
736 const exploded_edge *,
737 region_model_context *ctxt) const final override
739 const call_details cd (get_call_details (model, ctxt));
740 if (tree lhs_type = cd.get_lhs_type ())
742 region_model_manager *mgr = model->get_manager ();
743 const svalue *result;
744 if (m_found)
746 const svalue *str_sval = cd.get_arg_svalue (0);
747 const region *str_reg
748 = model->deref_rvalue (str_sval, cd.get_arg_tree (0),
749 cd.get_ctxt ());
750 /* We want str_sval + OFFSET for some unknown OFFSET.
751 Use a conjured_svalue to represent the offset,
752 using the str_reg as the id of the conjured_svalue. */
753 const svalue *offset
754 = mgr->get_or_create_conjured_svalue (size_type_node,
755 cd.get_call_stmt (),
756 str_reg,
757 conjured_purge (model,
758 ctxt));
759 result = mgr->get_or_create_binop (lhs_type, POINTER_PLUS_EXPR,
760 str_sval, offset);
762 else
763 result = mgr->get_or_create_int_cst (lhs_type, 0);
764 cd.maybe_set_lhs (result);
766 return true;
768 private:
769 bool m_found;
772 /* Body of kf_strchr::impl_call_post. */
773 if (cd.get_ctxt ())
775 cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, false));
776 cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, true));
777 cd.get_ctxt ()->terminate_path ();
781 /* Handler for "__builtin_stack_restore". */
783 class kf_stack_restore : public known_function
785 public:
786 bool matches_call_types_p (const call_details &) const final override
788 return true;
791 /* Currently a no-op. */
794 /* Handler for "__builtin_stack_save". */
796 class kf_stack_save : public known_function
798 public:
799 bool matches_call_types_p (const call_details &) const final override
801 return true;
804 /* Currently a no-op. */
807 /* Handler for "strcpy" and "__builtin_strcpy_chk". */
809 class kf_strcpy : public known_function
811 public:
812 kf_strcpy (unsigned int num_args) : m_num_args (num_args) {}
813 bool matches_call_types_p (const call_details &cd) const final override
815 return (cd.num_args () == m_num_args
816 && cd.arg_is_pointer_p (0)
817 && cd.arg_is_pointer_p (1));
820 void impl_call_pre (const call_details &cd) const final override;
822 private:
823 unsigned int m_num_args;
826 void
827 kf_strcpy::impl_call_pre (const call_details &cd) const
829 region_model *model = cd.get_model ();
830 region_model_manager *mgr = cd.get_manager ();
832 const svalue *dest_sval = cd.get_arg_svalue (0);
833 const region *dest_reg = model->deref_rvalue (dest_sval, cd.get_arg_tree (0),
834 cd.get_ctxt ());
835 const svalue *src_sval = cd.get_arg_svalue (1);
836 const region *src_reg = model->deref_rvalue (src_sval, cd.get_arg_tree (1),
837 cd.get_ctxt ());
838 const svalue *src_contents_sval = model->get_store_value (src_reg,
839 cd.get_ctxt ());
841 cd.maybe_set_lhs (dest_sval);
843 /* Try to get the string size if SRC_REG is a string_region. */
844 const svalue *copied_bytes_sval = model->get_string_size (src_reg);
845 /* Otherwise, check if the contents of SRC_REG is a string. */
846 if (copied_bytes_sval->get_kind () == SK_UNKNOWN)
847 copied_bytes_sval = model->get_string_size (src_contents_sval);
849 const region *sized_dest_reg
850 = mgr->get_sized_region (dest_reg, NULL_TREE, copied_bytes_sval);
851 model->set_value (sized_dest_reg, src_contents_sval, cd.get_ctxt ());
854 /* Handler for "strdup" and "__builtin_strdup". */
856 class kf_strdup : public known_function
858 public:
859 bool matches_call_types_p (const call_details &cd) const final override
861 return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
863 void impl_call_pre (const call_details &cd) const final override
865 region_model *model = cd.get_model ();
866 region_model_manager *mgr = cd.get_manager ();
867 /* Ideally we'd get the size here, and simulate copying the bytes. */
868 const region *new_reg
869 = model->get_or_create_region_for_heap_alloc (NULL, cd.get_ctxt ());
870 model->mark_region_as_unknown (new_reg, NULL);
871 if (cd.get_lhs_type ())
873 const svalue *ptr_sval
874 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
875 cd.maybe_set_lhs (ptr_sval);
880 /* Handle the on_call_pre part of "strlen". */
882 class kf_strlen : public known_function
884 public:
885 bool matches_call_types_p (const call_details &cd) const final override
887 return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
889 void impl_call_pre (const call_details &cd) const final override;
892 void
893 kf_strlen::impl_call_pre (const call_details &cd) const
895 region_model_context *ctxt = cd.get_ctxt ();
896 region_model *model = cd.get_model ();
897 region_model_manager *mgr = cd.get_manager ();
899 const svalue *arg_sval = cd.get_arg_svalue (0);
900 const region *buf_reg
901 = model->deref_rvalue (arg_sval, cd.get_arg_tree (0), ctxt);
902 if (const string_region *str_reg
903 = buf_reg->dyn_cast_string_region ())
905 tree str_cst = str_reg->get_string_cst ();
906 /* TREE_STRING_LENGTH is sizeof, not strlen. */
907 int sizeof_cst = TREE_STRING_LENGTH (str_cst);
908 int strlen_cst = sizeof_cst - 1;
909 if (cd.get_lhs_type ())
911 tree t_cst = build_int_cst (cd.get_lhs_type (), strlen_cst);
912 const svalue *result_sval
913 = mgr->get_or_create_constant_svalue (t_cst);
914 cd.maybe_set_lhs (result_sval);
915 return;
918 /* Otherwise a conjured value. */
921 /* Handler for "strndup" and "__builtin_strndup". */
923 class kf_strndup : public known_function
925 public:
926 bool matches_call_types_p (const call_details &cd) const final override
928 return (cd.num_args () == 2 && cd.arg_is_pointer_p (0));
930 void impl_call_pre (const call_details &cd) const final override
932 region_model *model = cd.get_model ();
933 region_model_manager *mgr = cd.get_manager ();
934 /* Ideally we'd get the size here, and simulate copying the bytes. */
935 const region *new_reg
936 = model->get_or_create_region_for_heap_alloc (NULL, cd.get_ctxt ());
937 model->mark_region_as_unknown (new_reg, NULL);
938 if (cd.get_lhs_type ())
940 const svalue *ptr_sval
941 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
942 cd.maybe_set_lhs (ptr_sval);
947 class kf_ubsan_bounds : public internal_known_function
949 /* Empty. */
952 /* Handle calls to functions referenced by
953 __attribute__((malloc(FOO))). */
955 void
956 region_model::impl_deallocation_call (const call_details &cd)
958 kf_free kf;
959 kf.impl_call_post (cd);
962 /* Populate KFM with instances of known functions supported by the core of the
963 analyzer (as opposed to plugins). */
965 void
966 register_known_functions (known_function_manager &kfm)
968 /* Debugging/test support functions, all with a "__analyzer_" prefix. */
969 register_known_analyzer_functions (kfm);
971 /* Internal fns the analyzer has known_functions for. */
973 kfm.add (IFN_BUILTIN_EXPECT, make_unique<kf_expect> ());
974 kfm.add (IFN_UBSAN_BOUNDS, make_unique<kf_ubsan_bounds> ());
977 /* Built-ins the analyzer has known_functions for. */
979 kfm.add (BUILT_IN_ALLOCA, make_unique<kf_alloca> ());
980 kfm.add (BUILT_IN_ALLOCA_WITH_ALIGN, make_unique<kf_alloca> ());
981 kfm.add (BUILT_IN_CALLOC, make_unique<kf_calloc> ());
982 kfm.add (BUILT_IN_EXPECT, make_unique<kf_expect> ());
983 kfm.add (BUILT_IN_EXPECT_WITH_PROBABILITY, make_unique<kf_expect> ());
984 kfm.add (BUILT_IN_FREE, make_unique<kf_free> ());
985 kfm.add (BUILT_IN_MALLOC, make_unique<kf_malloc> ());
986 kfm.add (BUILT_IN_MEMCPY, make_unique<kf_memcpy_memmove> ());
987 kfm.add (BUILT_IN_MEMCPY_CHK, make_unique<kf_memcpy_memmove> ());
988 kfm.add (BUILT_IN_MEMMOVE, make_unique<kf_memcpy_memmove> ());
989 kfm.add (BUILT_IN_MEMMOVE_CHK, make_unique<kf_memcpy_memmove> ());
990 kfm.add (BUILT_IN_MEMSET, make_unique<kf_memset> ());
991 kfm.add (BUILT_IN_MEMSET_CHK, make_unique<kf_memset> ());
992 kfm.add (BUILT_IN_REALLOC, make_unique<kf_realloc> ());
993 kfm.add (BUILT_IN_STACK_RESTORE, make_unique<kf_stack_restore> ());
994 kfm.add (BUILT_IN_STACK_SAVE, make_unique<kf_stack_save> ());
995 kfm.add (BUILT_IN_STRCHR, make_unique<kf_strchr> ());
996 kfm.add (BUILT_IN_STRCPY, make_unique<kf_strcpy> (2));
997 kfm.add (BUILT_IN_STRCPY_CHK, make_unique<kf_strcpy> (3));
998 kfm.add (BUILT_IN_STRDUP, make_unique<kf_strdup> ());
999 kfm.add (BUILT_IN_STRNDUP, make_unique<kf_strndup> ());
1000 kfm.add (BUILT_IN_STRLEN, make_unique<kf_strlen> ());
1002 register_varargs_builtins (kfm);
1005 /* Known builtins and C standard library functions. */
1007 kfm.add ("memset", make_unique<kf_memset> ());
1008 kfm.add ("strdup", make_unique<kf_strdup> ());
1009 kfm.add ("strndup", make_unique<kf_strndup> ());
1012 /* Known POSIX functions, and some non-standard extensions. */
1014 kfm.add ("putenv", make_unique<kf_putenv> ());
1016 register_known_fd_functions (kfm);
1017 register_known_file_functions (kfm);
1020 /* glibc functions. */
1022 kfm.add ("__errno_location", make_unique<kf_errno_location> ());
1023 kfm.add ("error", make_unique<kf_error> (3));
1024 kfm.add ("error_at_line", make_unique<kf_error> (5));
1027 /* Other implementations of C standard library. */
1029 /* According to PR 107807 comment #2, Solaris implements "errno"
1030 like this:
1031 extern int *___errno(void) __attribute__((__const__));
1032 #define errno (*(___errno()))
1033 and OS X like this:
1034 extern int * __error(void);
1035 #define errno (*__error())
1036 and similarly __errno for newlib.
1037 Add these as synonyms for "__errno_location". */
1038 kfm.add ("___errno", make_unique<kf_errno_location> ());
1039 kfm.add ("__error", make_unique<kf_errno_location> ());
1040 kfm.add ("__errno", make_unique<kf_errno_location> ());
1043 /* Language-specific support functions. */
1044 register_known_functions_lang_cp (kfm);
1047 } // namespace ana
1049 #endif /* #if ENABLE_ANALYZER */