analyzer: implement kf_strstr [PR105899]
[official-gcc.git] / gcc / analyzer / kf.cc
blob92959891fe440d2c9562c2b208c93a83caea9169
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 /* class pure_known_function_with_default_return : public known_function. */
45 void
46 pure_known_function_with_default_return::
47 impl_call_pre (const call_details &cd) const
49 cd.set_any_lhs_with_defaults ();
52 /* Implementations of specific functions. */
54 /* Handler for "alloca". */
56 class kf_alloca : public builtin_known_function
58 public:
59 bool matches_call_types_p (const call_details &cd) const final override
61 return cd.num_args () == 1;
63 enum built_in_function builtin_code () const final override
65 return BUILT_IN_ALLOCA;
67 void impl_call_pre (const call_details &cd) const final override;
70 void
71 kf_alloca::impl_call_pre (const call_details &cd) const
73 const svalue *size_sval = cd.get_arg_svalue (0);
75 region_model *model = cd.get_model ();
76 region_model_manager *mgr = cd.get_manager ();
78 const region *new_reg
79 = model->create_region_for_alloca (size_sval, cd.get_ctxt ());
80 const svalue *ptr_sval
81 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
82 cd.maybe_set_lhs (ptr_sval);
85 /* Handler for:
86 void __atomic_exchange (type *ptr, type *val, type *ret, int memorder). */
88 class kf_atomic_exchange : public internal_known_function
90 public:
91 /* This is effectively:
92 *RET = *PTR;
93 *PTR = *VAL;
95 void impl_call_pre (const call_details &cd) const final override
97 const svalue *ptr_ptr_sval = cd.get_arg_svalue (0);
98 tree ptr_ptr_tree = cd.get_arg_tree (0);
99 const svalue *val_ptr_sval = cd.get_arg_svalue (1);
100 tree val_ptr_tree = cd.get_arg_tree (1);
101 const svalue *ret_ptr_sval = cd.get_arg_svalue (2);
102 tree ret_ptr_tree = cd.get_arg_tree (2);
103 /* Ignore the memorder param. */
105 region_model *model = cd.get_model ();
106 region_model_context *ctxt = cd.get_ctxt ();
108 const region *val_region
109 = model->deref_rvalue (val_ptr_sval, val_ptr_tree, ctxt);
110 const svalue *star_val_sval = model->get_store_value (val_region, ctxt);
111 const region *ptr_region
112 = model->deref_rvalue (ptr_ptr_sval, ptr_ptr_tree, ctxt);
113 const svalue *star_ptr_sval = model->get_store_value (ptr_region, ctxt);
114 const region *ret_region
115 = model->deref_rvalue (ret_ptr_sval, ret_ptr_tree, ctxt);
116 model->set_value (ptr_region, star_val_sval, ctxt);
117 model->set_value (ret_region, star_ptr_sval, ctxt);
121 /* Handler for:
122 __atomic_exchange_n (type *ptr, type val, int memorder). */
124 class kf_atomic_exchange_n : public internal_known_function
126 public:
127 /* This is effectively:
128 RET = *PTR;
129 *PTR = VAL;
130 return RET;
132 void impl_call_pre (const call_details &cd) const final override
134 const svalue *ptr_sval = cd.get_arg_svalue (0);
135 tree ptr_tree = cd.get_arg_tree (0);
136 const svalue *set_sval = cd.get_arg_svalue (1);
137 /* Ignore the memorder param. */
139 region_model *model = cd.get_model ();
140 region_model_context *ctxt = cd.get_ctxt ();
142 const region *dst_region = model->deref_rvalue (ptr_sval, ptr_tree, ctxt);
143 const svalue *ret_sval = model->get_store_value (dst_region, ctxt);
144 model->set_value (dst_region, set_sval, ctxt);
145 cd.maybe_set_lhs (ret_sval);
149 /* Handler for:
150 type __atomic_fetch_add (type *ptr, type val, int memorder);
151 type __atomic_fetch_sub (type *ptr, type val, int memorder);
152 type __atomic_fetch_and (type *ptr, type val, int memorder);
153 type __atomic_fetch_xor (type *ptr, type val, int memorder);
154 type __atomic_fetch_or (type *ptr, type val, int memorder);
157 class kf_atomic_fetch_op : public internal_known_function
159 public:
160 kf_atomic_fetch_op (enum tree_code op): m_op (op) {}
162 /* This is effectively:
163 RET = *PTR;
164 *PTR = RET OP VAL;
165 return RET;
167 void impl_call_pre (const call_details &cd) const final override
169 const svalue *ptr_sval = cd.get_arg_svalue (0);
170 tree ptr_tree = cd.get_arg_tree (0);
171 const svalue *val_sval = cd.get_arg_svalue (1);
172 /* Ignore the memorder param. */
174 region_model *model = cd.get_model ();
175 region_model_manager *mgr = cd.get_manager ();
176 region_model_context *ctxt = cd.get_ctxt ();
178 const region *star_ptr_region
179 = model->deref_rvalue (ptr_sval, ptr_tree, ctxt);
180 const svalue *old_sval = model->get_store_value (star_ptr_region, ctxt);
181 const svalue *new_sval = mgr->get_or_create_binop (old_sval->get_type (),
182 m_op,
183 old_sval, val_sval);
184 model->set_value (star_ptr_region, new_sval, ctxt);
185 cd.maybe_set_lhs (old_sval);
188 private:
189 enum tree_code m_op;
192 /* Handler for:
193 type __atomic_add_fetch (type *ptr, type val, int memorder);
194 type __atomic_sub_fetch (type *ptr, type val, int memorder);
195 type __atomic_and_fetch (type *ptr, type val, int memorder);
196 type __atomic_xor_fetch (type *ptr, type val, int memorder);
197 type __atomic_or_fetch (type *ptr, type val, int memorder);
200 class kf_atomic_op_fetch : public internal_known_function
202 public:
203 kf_atomic_op_fetch (enum tree_code op): m_op (op) {}
205 /* This is effectively:
206 *PTR = RET OP VAL;
207 return *PTR;
209 void impl_call_pre (const call_details &cd) const final override
211 const svalue *ptr_sval = cd.get_arg_svalue (0);
212 tree ptr_tree = cd.get_arg_tree (0);
213 const svalue *val_sval = cd.get_arg_svalue (1);
214 /* Ignore the memorder param. */
216 region_model *model = cd.get_model ();
217 region_model_manager *mgr = cd.get_manager ();
218 region_model_context *ctxt = cd.get_ctxt ();
220 const region *star_ptr_region
221 = model->deref_rvalue (ptr_sval, ptr_tree, ctxt);
222 const svalue *old_sval = model->get_store_value (star_ptr_region, ctxt);
223 const svalue *new_sval = mgr->get_or_create_binop (old_sval->get_type (),
224 m_op,
225 old_sval, val_sval);
226 model->set_value (star_ptr_region, new_sval, ctxt);
227 cd.maybe_set_lhs (new_sval);
230 private:
231 enum tree_code m_op;
234 /* Handler for:
235 void __atomic_load (type *ptr, type *ret, int memorder). */
237 class kf_atomic_load : public internal_known_function
239 public:
240 /* This is effectively:
241 *RET = *PTR;
243 void impl_call_pre (const call_details &cd) const final override
245 const svalue *ptr_ptr_sval = cd.get_arg_svalue (0);
246 tree ptr_ptr_tree = cd.get_arg_tree (0);
247 const svalue *ret_ptr_sval = cd.get_arg_svalue (1);
248 tree ret_ptr_tree = cd.get_arg_tree (1);
249 /* Ignore the memorder param. */
251 region_model *model = cd.get_model ();
252 region_model_context *ctxt = cd.get_ctxt ();
254 const region *ptr_region
255 = model->deref_rvalue (ptr_ptr_sval, ptr_ptr_tree, ctxt);
256 const svalue *star_ptr_sval = model->get_store_value (ptr_region, ctxt);
257 const region *ret_region
258 = model->deref_rvalue (ret_ptr_sval, ret_ptr_tree, ctxt);
259 model->set_value (ret_region, star_ptr_sval, ctxt);
263 /* Handler for:
264 type __atomic_load_n (type *ptr, int memorder) */
266 class kf_atomic_load_n : public internal_known_function
268 public:
269 /* This is effectively:
270 RET = *PTR;
271 return RET;
273 void impl_call_pre (const call_details &cd) const final override
275 const svalue *ptr_ptr_sval = cd.get_arg_svalue (0);
276 tree ptr_ptr_tree = cd.get_arg_tree (0);
277 /* Ignore the memorder param. */
279 region_model *model = cd.get_model ();
280 region_model_context *ctxt = cd.get_ctxt ();
282 const region *ptr_region
283 = model->deref_rvalue (ptr_ptr_sval, ptr_ptr_tree, ctxt);
284 const svalue *star_ptr_sval = model->get_store_value (ptr_region, ctxt);
285 cd.maybe_set_lhs (star_ptr_sval);
289 /* Handler for:
290 void __atomic_store_n (type *ptr, type val, int memorder) */
292 class kf_atomic_store_n : public internal_known_function
294 public:
295 /* This is effectively:
296 *PTR = VAL;
298 void impl_call_pre (const call_details &cd) const final override
300 const svalue *ptr_sval = cd.get_arg_svalue (0);
301 tree ptr_tree = cd.get_arg_tree (0);
302 const svalue *new_sval = cd.get_arg_svalue (1);
303 /* Ignore the memorder param. */
305 region_model *model = cd.get_model ();
306 region_model_context *ctxt = cd.get_ctxt ();
308 const region *star_ptr_region
309 = model->deref_rvalue (ptr_sval, ptr_tree, ctxt);
310 model->set_value (star_ptr_region, new_sval, ctxt);
314 /* Handler for "__builtin_expect" etc. */
316 class kf_expect : public internal_known_function
318 public:
319 void impl_call_pre (const call_details &cd) const final override
321 /* __builtin_expect's return value is its initial argument. */
322 const svalue *sval = cd.get_arg_svalue (0);
323 cd.maybe_set_lhs (sval);
327 /* Handler for "calloc". */
329 class kf_calloc : public builtin_known_function
331 public:
332 bool matches_call_types_p (const call_details &cd) const final override
334 return (cd.num_args () == 2
335 && cd.arg_is_size_p (0)
336 && cd.arg_is_size_p (1));
338 enum built_in_function builtin_code () const final override
340 return BUILT_IN_CALLOC;
343 void impl_call_pre (const call_details &cd) const final override;
346 void
347 kf_calloc::impl_call_pre (const call_details &cd) const
349 region_model *model = cd.get_model ();
350 region_model_manager *mgr = cd.get_manager ();
351 const svalue *nmemb_sval = cd.get_arg_svalue (0);
352 const svalue *size_sval = cd.get_arg_svalue (1);
353 /* TODO: check for overflow here? */
354 const svalue *prod_sval
355 = mgr->get_or_create_binop (size_type_node, MULT_EXPR,
356 nmemb_sval, size_sval);
357 const region *new_reg
358 = model->get_or_create_region_for_heap_alloc (prod_sval, cd.get_ctxt ());
359 const region *sized_reg
360 = mgr->get_sized_region (new_reg, NULL_TREE, prod_sval);
361 model->zero_fill_region (sized_reg, cd.get_ctxt ());
362 if (cd.get_lhs_type ())
364 const svalue *ptr_sval
365 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
366 cd.maybe_set_lhs (ptr_sval);
370 /* Handler for glibc's "__errno_location". */
372 class kf_errno_location : public known_function
374 public:
375 bool matches_call_types_p (const call_details &cd) const final override
377 return cd.num_args () == 0;
380 void impl_call_pre (const call_details &cd) const final override
382 if (cd.get_lhs_region ())
384 region_model_manager *mgr = cd.get_manager ();
385 const region *errno_reg = mgr->get_errno_region ();
386 const svalue *errno_ptr = mgr->get_ptr_svalue (cd.get_lhs_type (),
387 errno_reg);
388 cd.maybe_set_lhs (errno_ptr);
393 /* Handler for "error" and "error_at_line" from GNU's non-standard <error.h>.
394 MIN_ARGS identifies the minimum number of expected arguments
395 to be consistent with such a call (3 and 5 respectively). */
397 class kf_error : public known_function
399 public:
400 kf_error (unsigned min_args) : m_min_args (min_args) {}
402 bool matches_call_types_p (const call_details &cd) const final override
404 return (cd.num_args () >= m_min_args
405 && cd.get_arg_type (0) == integer_type_node);
408 void impl_call_pre (const call_details &cd) const final override;
410 private:
411 unsigned m_min_args;
414 void
415 kf_error::impl_call_pre (const call_details &cd) const
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 region_model_context *ctxt = cd.get_ctxt ();
422 region_model *model = cd.get_model ();
423 if (!model->add_constraint (status, EQ_EXPR, integer_zero_node, ctxt))
424 if (ctxt)
425 ctxt->terminate_path ();
427 /* Check "format" arg. */
428 const int fmt_arg_idx = (m_min_args == 3) ? 2 : 4;
429 model->check_for_null_terminated_string_arg (cd, fmt_arg_idx);
432 /* Handler for fopen.
433 FILE *fopen (const char *filename, const char *mode);
434 See e.g. https://en.cppreference.com/w/c/io/fopen
435 https://www.man7.org/linux/man-pages/man3/fopen.3.html
436 https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfopen?view=msvc-170 */
438 class kf_fopen : public known_function
440 public:
441 bool matches_call_types_p (const call_details &cd) const final override
443 return (cd.num_args () == 2
444 && cd.arg_is_pointer_p (0)
445 && cd.arg_is_pointer_p (1));
448 void impl_call_pre (const call_details &cd) const final override
450 cd.check_for_null_terminated_string_arg (0);
451 cd.check_for_null_terminated_string_arg (1);
452 cd.set_any_lhs_with_defaults ();
454 /* fopen's mode param is effectively a mini-DSL, but there are various
455 non-standard extensions, so we don't bother to check it. */
459 /* Handler for "free", after sm-handling.
461 If the ptr points to an underlying heap region, delete the region,
462 poisoning pointers to it and regions within it.
464 We delay this until after sm-state has been updated so that the
465 sm-handling can transition all of the various casts of the pointer
466 to a "freed" state *before* we delete the related region here.
468 This has to be done here so that the sm-handling can use the fact
469 that they point to the same region to establish that they are equal
470 (in region_model::eval_condition), and thus transition
471 all pointers to the region to the "freed" state together, regardless
472 of casts. */
474 class kf_free : public builtin_known_function
476 public:
477 bool matches_call_types_p (const call_details &cd) const final override
479 return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
481 enum built_in_function builtin_code () const final override
483 return BUILT_IN_FREE;
485 void impl_call_post (const call_details &cd) const final override;
488 void
489 kf_free::impl_call_post (const call_details &cd) const
491 const svalue *ptr_sval = cd.get_arg_svalue (0);
492 if (const region *freed_reg = ptr_sval->maybe_get_region ())
494 /* If the ptr points to an underlying heap region, delete it,
495 poisoning pointers. */
496 region_model *model = cd.get_model ();
497 model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
498 model->unset_dynamic_extents (freed_reg);
502 /* Handle the on_call_pre part of "malloc". */
504 class kf_malloc : public builtin_known_function
506 public:
507 bool matches_call_types_p (const call_details &cd) const final override
509 return (cd.num_args () == 1
510 && cd.arg_is_size_p (0));
512 enum built_in_function builtin_code () const final override
514 return BUILT_IN_MALLOC;
516 void impl_call_pre (const call_details &cd) const final override;
519 void
520 kf_malloc::impl_call_pre (const call_details &cd) const
522 region_model *model = cd.get_model ();
523 region_model_manager *mgr = cd.get_manager ();
524 const svalue *size_sval = cd.get_arg_svalue (0);
525 const region *new_reg
526 = model->get_or_create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
527 if (cd.get_lhs_type ())
529 const svalue *ptr_sval
530 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
531 cd.maybe_set_lhs (ptr_sval);
535 /* Handler for "memcpy" and "__builtin_memcpy",
536 "memmove", and "__builtin_memmove". */
538 class kf_memcpy_memmove : public builtin_known_function
540 public:
541 enum kf_memcpy_memmove_variant
543 KF_MEMCPY,
544 KF_MEMCPY_CHK,
545 KF_MEMMOVE,
546 KF_MEMMOVE_CHK,
548 kf_memcpy_memmove (enum kf_memcpy_memmove_variant variant)
549 : m_variant (variant) {};
550 bool matches_call_types_p (const call_details &cd) const final override
552 return (cd.num_args () == 3
553 && cd.arg_is_pointer_p (0)
554 && cd.arg_is_pointer_p (1)
555 && cd.arg_is_size_p (2));
557 enum built_in_function builtin_code () const final override
559 switch (m_variant)
561 case KF_MEMCPY:
562 return BUILT_IN_MEMCPY;
563 case KF_MEMCPY_CHK:
564 return BUILT_IN_MEMCPY_CHK;
565 case KF_MEMMOVE:
566 return BUILT_IN_MEMMOVE;
567 case KF_MEMMOVE_CHK:
568 return BUILT_IN_MEMMOVE_CHK;
569 default:
570 gcc_unreachable ();
573 void impl_call_pre (const call_details &cd) const final override;
574 private:
575 const enum kf_memcpy_memmove_variant m_variant;
578 void
579 kf_memcpy_memmove::impl_call_pre (const call_details &cd) const
581 const svalue *dest_ptr_sval = cd.get_arg_svalue (0);
582 const svalue *src_ptr_sval = cd.get_arg_svalue (1);
583 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
585 region_model *model = cd.get_model ();
587 const region *dest_reg
588 = model->deref_rvalue (dest_ptr_sval, cd.get_arg_tree (0), cd.get_ctxt ());
589 const region *src_reg
590 = model->deref_rvalue (src_ptr_sval, cd.get_arg_tree (1), cd.get_ctxt ());
592 cd.maybe_set_lhs (dest_ptr_sval);
593 /* Check for overlap. */
594 switch (m_variant)
596 case KF_MEMCPY:
597 case KF_MEMCPY_CHK:
598 cd.complain_about_overlap (0, 1, num_bytes_sval);
599 break;
601 case KF_MEMMOVE:
602 case KF_MEMMOVE_CHK:
603 /* It's OK for memmove's arguments to overlap. */
604 break;
606 default:
607 gcc_unreachable ();
609 model->copy_bytes (dest_reg,
610 src_reg, cd.get_arg_tree (1),
611 num_bytes_sval,
612 cd.get_ctxt ());
615 /* Handler for "memset" and "__builtin_memset". */
617 class kf_memset : public builtin_known_function
619 public:
620 kf_memset (bool chk_variant) : m_chk_variant (chk_variant) {}
621 bool matches_call_types_p (const call_details &cd) const final override
623 return (cd.num_args () == 3 && cd.arg_is_pointer_p (0));
625 enum built_in_function builtin_code () const final override
627 return m_chk_variant ? BUILT_IN_MEMSET_CHK : BUILT_IN_MEMSET;
629 void impl_call_pre (const call_details &cd) const final override;
630 private:
631 const bool m_chk_variant;
634 void
635 kf_memset::impl_call_pre (const call_details &cd) const
637 const svalue *dest_sval = cd.get_arg_svalue (0);
638 const svalue *fill_value_sval = cd.get_arg_svalue (1);
639 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
641 region_model *model = cd.get_model ();
642 region_model_manager *mgr = cd.get_manager ();
644 const region *dest_reg
645 = model->deref_rvalue (dest_sval, cd.get_arg_tree (0), cd.get_ctxt ());
647 const svalue *fill_value_u8
648 = mgr->get_or_create_cast (unsigned_char_type_node, fill_value_sval);
650 const region *sized_dest_reg = mgr->get_sized_region (dest_reg,
651 NULL_TREE,
652 num_bytes_sval);
653 model->fill_region (sized_dest_reg, fill_value_u8, cd.get_ctxt ());
655 cd.maybe_set_lhs (dest_sval);
658 /* A subclass of pending_diagnostic for complaining about 'putenv'
659 called on an auto var. */
661 class putenv_of_auto_var
662 : public pending_diagnostic_subclass<putenv_of_auto_var>
664 public:
665 putenv_of_auto_var (tree fndecl, const region *reg)
666 : m_fndecl (fndecl), m_reg (reg),
667 m_var_decl (reg->get_base_region ()->maybe_get_decl ())
671 const char *get_kind () const final override
673 return "putenv_of_auto_var";
676 bool operator== (const putenv_of_auto_var &other) const
678 return (m_fndecl == other.m_fndecl
679 && m_reg == other.m_reg
680 && same_tree_p (m_var_decl, other.m_var_decl));
683 int get_controlling_option () const final override
685 return OPT_Wanalyzer_putenv_of_auto_var;
688 bool emit (rich_location *rich_loc, logger *) final override
690 auto_diagnostic_group d;
691 diagnostic_metadata m;
693 /* SEI CERT C Coding Standard: "POS34-C. Do not call putenv() with a
694 pointer to an automatic variable as the argument". */
695 diagnostic_metadata::precanned_rule
696 rule ("POS34-C", "https://wiki.sei.cmu.edu/confluence/x/6NYxBQ");
697 m.add_rule (rule);
699 bool warned;
700 if (m_var_decl)
701 warned = warning_meta (rich_loc, m, get_controlling_option (),
702 "%qE on a pointer to automatic variable %qE",
703 m_fndecl, m_var_decl);
704 else
705 warned = warning_meta (rich_loc, m, get_controlling_option (),
706 "%qE on a pointer to an on-stack buffer",
707 m_fndecl);
708 if (warned)
710 if (m_var_decl)
711 inform (DECL_SOURCE_LOCATION (m_var_decl),
712 "%qE declared on stack here", m_var_decl);
713 inform (rich_loc->get_loc (), "perhaps use %qs rather than %qE",
714 "setenv", m_fndecl);
717 return warned;
720 label_text describe_final_event (const evdesc::final_event &ev) final override
722 if (m_var_decl)
723 return ev.formatted_print ("%qE on a pointer to automatic variable %qE",
724 m_fndecl, m_var_decl);
725 else
726 return ev.formatted_print ("%qE on a pointer to an on-stack buffer",
727 m_fndecl);
730 void mark_interesting_stuff (interesting_t *interest) final override
732 if (!m_var_decl)
733 interest->add_region_creation (m_reg->get_base_region ());
736 private:
737 tree m_fndecl; // non-NULL
738 const region *m_reg; // non-NULL
739 tree m_var_decl; // could be NULL
742 /* Handler for calls to "putenv".
744 In theory we could try to model the state of the environment variables
745 for the process; for now we merely complain about putenv of regions
746 on the stack. */
748 class kf_putenv : public known_function
750 public:
751 bool matches_call_types_p (const call_details &cd) const final override
753 return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
756 void impl_call_pre (const call_details &cd) const final override
758 tree fndecl = cd.get_fndecl_for_call ();
759 gcc_assert (fndecl);
760 region_model_context *ctxt = cd.get_ctxt ();
761 region_model *model = cd.get_model ();
762 model->check_for_null_terminated_string_arg (cd, 0);
763 const svalue *ptr_sval = cd.get_arg_svalue (0);
764 const region *reg
765 = model->deref_rvalue (ptr_sval, cd.get_arg_tree (0), ctxt);
766 model->get_store ()->mark_as_escaped (reg);
767 enum memory_space mem_space = reg->get_memory_space ();
768 switch (mem_space)
770 default:
771 gcc_unreachable ();
772 case MEMSPACE_UNKNOWN:
773 case MEMSPACE_CODE:
774 case MEMSPACE_GLOBALS:
775 case MEMSPACE_HEAP:
776 case MEMSPACE_READONLY_DATA:
777 break;
778 case MEMSPACE_STACK:
779 if (ctxt)
780 ctxt->warn (make_unique<putenv_of_auto_var> (fndecl, reg));
781 break;
783 cd.set_any_lhs_with_defaults ();
787 /* Handler for "realloc":
789 void *realloc(void *ptr, size_t size);
791 realloc(3) is awkward, since it has various different outcomes
792 that are best modelled as separate exploded nodes/edges.
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).
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.
807 Each of these has a custom_edge_info subclass, which updates
808 the region_model and sm-state of the destination state. */
810 class kf_realloc : public builtin_known_function
812 public:
813 bool matches_call_types_p (const call_details &cd) const final override
815 return (cd.num_args () == 2
816 && cd.arg_is_pointer_p (0)
817 && cd.arg_is_size_p (1));
820 enum built_in_function builtin_code () const final override
822 return BUILT_IN_REALLOC;
825 void impl_call_post (const call_details &cd) const final override;
828 void
829 kf_realloc::impl_call_post (const call_details &cd) const
831 /* Three custom subclasses of custom_edge_info, for handling the various
832 outcomes of "realloc". */
834 /* Concrete custom_edge_info: a realloc call that fails, returning NULL. */
835 class failure : public failed_call_info
837 public:
838 failure (const call_details &cd)
839 : failed_call_info (cd)
843 bool update_model (region_model *model,
844 const exploded_edge *,
845 region_model_context *ctxt) const final override
847 /* Return NULL; everything else is unchanged. */
848 const call_details cd (get_call_details (model, ctxt));
849 region_model_manager *mgr = cd.get_manager ();
850 if (cd.get_lhs_type ())
852 const svalue *zero
853 = mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
854 model->set_value (cd.get_lhs_region (),
855 zero,
856 cd.get_ctxt ());
858 return true;
862 /* Concrete custom_edge_info: a realloc call that succeeds, growing
863 the existing buffer without moving it. */
864 class success_no_move : public call_info
866 public:
867 success_no_move (const call_details &cd)
868 : call_info (cd)
872 label_text get_desc (bool can_colorize) const final override
874 return make_label_text (can_colorize,
875 "when %qE succeeds, without moving buffer",
876 get_fndecl ());
879 bool update_model (region_model *model,
880 const exploded_edge *,
881 region_model_context *ctxt) const final override
883 /* Update size of buffer and return the ptr unchanged. */
884 const call_details cd (get_call_details (model, ctxt));
885 region_model_manager *mgr = cd.get_manager ();
886 const svalue *ptr_sval = cd.get_arg_svalue (0);
887 const svalue *size_sval = cd.get_arg_svalue (1);
889 /* We can only grow in place with a non-NULL pointer. */
891 const svalue *null_ptr
892 = mgr->get_or_create_int_cst (ptr_sval->get_type (), 0);
893 if (!model->add_constraint (ptr_sval, NE_EXPR, null_ptr,
894 cd.get_ctxt ()))
895 return false;
898 if (const region *buffer_reg = model->deref_rvalue (ptr_sval, NULL_TREE,
899 ctxt))
900 if (compat_types_p (size_sval->get_type (), size_type_node))
901 model->set_dynamic_extents (buffer_reg, size_sval, ctxt);
902 if (cd.get_lhs_region ())
904 model->set_value (cd.get_lhs_region (), ptr_sval, cd.get_ctxt ());
905 const svalue *zero
906 = mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
907 return model->add_constraint (ptr_sval, NE_EXPR, zero, ctxt);
909 else
910 return true;
914 /* Concrete custom_edge_info: a realloc call that succeeds, freeing
915 the existing buffer and moving the content to a freshly allocated
916 buffer. */
917 class success_with_move : public call_info
919 public:
920 success_with_move (const call_details &cd)
921 : call_info (cd)
925 label_text get_desc (bool can_colorize) const final override
927 return make_label_text (can_colorize,
928 "when %qE succeeds, moving buffer",
929 get_fndecl ());
931 bool update_model (region_model *model,
932 const exploded_edge *,
933 region_model_context *ctxt) const final override
935 const call_details cd (get_call_details (model, ctxt));
936 region_model_manager *mgr = cd.get_manager ();
937 const svalue *old_ptr_sval = cd.get_arg_svalue (0);
938 const svalue *new_size_sval = cd.get_arg_svalue (1);
940 /* Create the new region. */
941 const region *new_reg
942 = model->get_or_create_region_for_heap_alloc (new_size_sval, ctxt);
943 const svalue *new_ptr_sval
944 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
945 if (!model->add_constraint (new_ptr_sval, NE_EXPR, old_ptr_sval,
946 cd.get_ctxt ()))
947 return false;
949 if (cd.get_lhs_type ())
950 cd.maybe_set_lhs (new_ptr_sval);
952 if (const region *freed_reg = model->deref_rvalue (old_ptr_sval,
953 NULL_TREE, ctxt))
955 /* Copy the data. */
956 const svalue *old_size_sval = model->get_dynamic_extents (freed_reg);
957 if (old_size_sval)
959 const svalue *copied_size_sval
960 = get_copied_size (model, old_size_sval, new_size_sval);
961 const region *copied_old_reg
962 = mgr->get_sized_region (freed_reg, NULL, copied_size_sval);
963 const svalue *buffer_content_sval
964 = model->get_store_value (copied_old_reg, cd.get_ctxt ());
965 const region *copied_new_reg
966 = mgr->get_sized_region (new_reg, NULL, copied_size_sval);
967 model->set_value (copied_new_reg, buffer_content_sval,
968 cd.get_ctxt ());
970 else
972 /* We don't know how big the old region was;
973 mark the new region as having been touched to avoid uninit
974 issues. */
975 model->mark_region_as_unknown (new_reg, cd.get_uncertainty ());
978 /* Free the old region, so that pointers to the old buffer become
979 invalid. */
981 /* If the ptr points to an underlying heap region, delete it,
982 poisoning pointers. */
983 model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
984 model->unset_dynamic_extents (freed_reg);
987 /* Update the sm-state: mark the old_ptr_sval as "freed",
988 and the new_ptr_sval as "nonnull". */
989 model->on_realloc_with_move (cd, old_ptr_sval, new_ptr_sval);
991 if (cd.get_lhs_type ())
993 const svalue *zero
994 = mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
995 return model->add_constraint (new_ptr_sval, NE_EXPR, zero,
996 cd.get_ctxt ());
998 else
999 return true;
1002 private:
1003 /* Return the lesser of OLD_SIZE_SVAL and NEW_SIZE_SVAL.
1004 If unknown, OLD_SIZE_SVAL is returned. */
1005 const svalue *get_copied_size (region_model *model,
1006 const svalue *old_size_sval,
1007 const svalue *new_size_sval) const
1009 tristate res
1010 = model->eval_condition (old_size_sval, GT_EXPR, new_size_sval);
1011 switch (res.get_value ())
1013 case tristate::TS_TRUE:
1014 return new_size_sval;
1015 case tristate::TS_FALSE:
1016 case tristate::TS_UNKNOWN:
1017 return old_size_sval;
1018 default:
1019 gcc_unreachable ();
1024 /* Body of kf_realloc::impl_call_post. */
1026 if (cd.get_ctxt ())
1028 cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
1029 cd.get_ctxt ()->bifurcate (make_unique<success_no_move> (cd));
1030 cd.get_ctxt ()->bifurcate (make_unique<success_with_move> (cd));
1031 cd.get_ctxt ()->terminate_path ();
1035 /* Handler for "strchr" and "__builtin_strchr". */
1037 class kf_strchr : public builtin_known_function
1039 public:
1040 bool matches_call_types_p (const call_details &cd) const final override
1042 return (cd.num_args () == 2 && cd.arg_is_pointer_p (0));
1044 void impl_call_pre (const call_details &cd) const final override
1046 cd.check_for_null_terminated_string_arg (0);
1049 enum built_in_function builtin_code () const final override
1051 return BUILT_IN_STRCHR;
1053 void impl_call_post (const call_details &cd) const final override;
1056 void
1057 kf_strchr::impl_call_post (const call_details &cd) const
1059 class strchr_call_info : public call_info
1061 public:
1062 strchr_call_info (const call_details &cd, bool found)
1063 : call_info (cd), m_found (found)
1067 label_text get_desc (bool can_colorize) const final override
1069 if (m_found)
1070 return make_label_text (can_colorize,
1071 "when %qE returns non-NULL",
1072 get_fndecl ());
1073 else
1074 return make_label_text (can_colorize,
1075 "when %qE returns NULL",
1076 get_fndecl ());
1079 bool update_model (region_model *model,
1080 const exploded_edge *,
1081 region_model_context *ctxt) const final override
1083 const call_details cd (get_call_details (model, ctxt));
1084 if (tree lhs_type = cd.get_lhs_type ())
1086 region_model_manager *mgr = model->get_manager ();
1087 const svalue *result;
1088 if (m_found)
1090 const svalue *str_sval = cd.get_arg_svalue (0);
1091 const region *str_reg
1092 = model->deref_rvalue (str_sval, cd.get_arg_tree (0),
1093 cd.get_ctxt ());
1094 /* We want str_sval + OFFSET for some unknown OFFSET.
1095 Use a conjured_svalue to represent the offset,
1096 using the str_reg as the id of the conjured_svalue. */
1097 const svalue *offset
1098 = mgr->get_or_create_conjured_svalue (size_type_node,
1099 cd.get_call_stmt (),
1100 str_reg,
1101 conjured_purge (model,
1102 ctxt));
1103 result = mgr->get_or_create_binop (lhs_type, POINTER_PLUS_EXPR,
1104 str_sval, offset);
1106 else
1107 result = mgr->get_or_create_int_cst (lhs_type, 0);
1108 cd.maybe_set_lhs (result);
1110 return true;
1112 private:
1113 bool m_found;
1116 /* Body of kf_strchr::impl_call_post. */
1117 if (cd.get_ctxt ())
1119 cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, false));
1120 cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, true));
1121 cd.get_ctxt ()->terminate_path ();
1125 /* Handler for "sprintf".
1126 int sprintf(char *str, const char *format, ...);
1129 class kf_sprintf : public builtin_known_function
1131 public:
1132 bool matches_call_types_p (const call_details &cd) const final override
1134 return (cd.num_args () >= 2
1135 && cd.arg_is_pointer_p (0)
1136 && cd.arg_is_pointer_p (1));
1139 enum built_in_function builtin_code () const final override
1141 return BUILT_IN_SPRINTF;
1144 void impl_call_pre (const call_details &cd) const final override
1146 /* For now, merely assume that the destination buffer gets set to a
1147 new svalue. */
1148 region_model *model = cd.get_model ();
1149 region_model_context *ctxt = cd.get_ctxt ();
1150 const svalue *dst_ptr = cd.get_arg_svalue (0);
1151 const region *dst_reg
1152 = model->deref_rvalue (dst_ptr, cd.get_arg_tree (0), ctxt);
1153 const svalue *content = cd.get_or_create_conjured_svalue (dst_reg);
1154 model->set_value (dst_reg, content, ctxt);
1155 cd.set_any_lhs_with_defaults ();
1159 /* Handler for "__builtin_stack_restore". */
1161 class kf_stack_restore : public pure_known_function_with_default_return
1163 public:
1164 bool matches_call_types_p (const call_details &) const final override
1166 return true;
1169 /* Currently a no-op. */
1172 /* Handler for "__builtin_stack_save". */
1174 class kf_stack_save : public pure_known_function_with_default_return
1176 public:
1177 bool matches_call_types_p (const call_details &) const final override
1179 return true;
1182 /* Currently a no-op. */
1185 /* Handler for "strcat" and "__builtin_strcat_chk". */
1187 class kf_strcat : public builtin_known_function
1189 public:
1190 kf_strcat (unsigned int num_args, bool chk_variant)
1191 : m_num_args (num_args),
1192 m_chk_variant (chk_variant) {}
1193 bool matches_call_types_p (const call_details &cd) const final override
1195 return (cd.num_args () == m_num_args
1196 && cd.arg_is_pointer_p (0)
1197 && cd.arg_is_pointer_p (1));
1200 enum built_in_function builtin_code () const final override
1202 return m_chk_variant ? BUILT_IN_STRCAT_CHK : BUILT_IN_STRCAT;
1205 void impl_call_pre (const call_details &cd) const final override
1207 region_model *model = cd.get_model ();
1208 region_model_manager *mgr = cd.get_manager ();
1210 const svalue *dest_sval = cd.get_arg_svalue (0);
1211 const region *dest_reg = model->deref_rvalue (dest_sval, cd.get_arg_tree (0),
1212 cd.get_ctxt ());
1214 const svalue *dst_strlen_sval
1215 = cd.check_for_null_terminated_string_arg (0, false, nullptr);
1216 if (!dst_strlen_sval)
1218 if (cd.get_ctxt ())
1219 cd.get_ctxt ()->terminate_path ();
1220 return;
1223 const svalue *bytes_to_copy;
1224 const svalue *num_src_bytes_read_sval
1225 = cd.check_for_null_terminated_string_arg (1, true, &bytes_to_copy);
1226 if (!num_src_bytes_read_sval)
1228 if (cd.get_ctxt ())
1229 cd.get_ctxt ()->terminate_path ();
1230 return;
1233 cd.maybe_set_lhs (dest_sval);
1234 cd.complain_about_overlap (0, 1, num_src_bytes_read_sval);
1236 const region *offset_reg
1237 = mgr->get_offset_region (dest_reg, NULL_TREE, dst_strlen_sval);
1238 model->write_bytes (offset_reg,
1239 num_src_bytes_read_sval,
1240 bytes_to_copy,
1241 cd.get_ctxt ());
1244 private:
1245 unsigned int m_num_args;
1246 const bool m_chk_variant;
1249 /* Handler for "strcpy" and "__builtin_strcpy_chk". */
1251 class kf_strcpy : public builtin_known_function
1253 public:
1254 kf_strcpy (unsigned int num_args, bool chk_variant)
1255 : m_num_args (num_args),
1256 m_chk_variant (chk_variant) {}
1257 bool matches_call_types_p (const call_details &cd) const final override
1259 return (cd.num_args () == m_num_args
1260 && cd.arg_is_pointer_p (0)
1261 && cd.arg_is_pointer_p (1));
1263 enum built_in_function builtin_code () const final override
1265 return m_chk_variant ? BUILT_IN_STRCPY_CHK : BUILT_IN_STRCPY;
1267 void impl_call_pre (const call_details &cd) const final override;
1269 private:
1270 unsigned int m_num_args;
1271 const bool m_chk_variant;
1274 void
1275 kf_strcpy::impl_call_pre (const call_details &cd) const
1277 region_model *model = cd.get_model ();
1278 region_model_context *ctxt = cd.get_ctxt ();
1280 const svalue *dest_sval = cd.get_arg_svalue (0);
1281 const region *dest_reg = model->deref_rvalue (dest_sval, cd.get_arg_tree (0),
1282 ctxt);
1283 /* strcpy returns the initial param. */
1284 cd.maybe_set_lhs (dest_sval);
1286 const svalue *bytes_to_copy;
1287 if (const svalue *num_bytes_read_sval
1288 = cd.check_for_null_terminated_string_arg (1, true, &bytes_to_copy))
1290 cd.complain_about_overlap (0, 1, num_bytes_read_sval);
1291 model->write_bytes (dest_reg, num_bytes_read_sval, bytes_to_copy, ctxt);
1293 else
1295 if (cd.get_ctxt ())
1296 cd.get_ctxt ()->terminate_path ();
1300 /* Handler for "strdup" and "__builtin_strdup". */
1302 class kf_strdup : public builtin_known_function
1304 public:
1305 bool matches_call_types_p (const call_details &cd) const final override
1307 return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
1309 enum built_in_function builtin_code () const final override
1311 return BUILT_IN_STRDUP;
1313 void impl_call_pre (const call_details &cd) const final override
1315 region_model *model = cd.get_model ();
1316 region_model_context *ctxt = cd.get_ctxt ();
1317 region_model_manager *mgr = cd.get_manager ();
1318 const svalue *bytes_to_copy;
1319 if (const svalue *num_bytes_read_sval
1320 = cd.check_for_null_terminated_string_arg (0, true, &bytes_to_copy))
1322 const region *new_reg
1323 = model->get_or_create_region_for_heap_alloc (num_bytes_read_sval,
1324 ctxt);
1325 model->write_bytes (new_reg, num_bytes_read_sval, bytes_to_copy, ctxt);
1326 if (cd.get_lhs_type ())
1328 const svalue *ptr_sval
1329 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
1330 cd.maybe_set_lhs (ptr_sval);
1333 else
1335 if (ctxt)
1336 ctxt->terminate_path ();
1341 /* Handler for "strlen" and for "__analyzer_get_strlen". */
1343 class kf_strlen : public builtin_known_function
1345 public:
1346 bool matches_call_types_p (const call_details &cd) const final override
1348 return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
1350 enum built_in_function builtin_code () const final override
1352 return BUILT_IN_STRLEN;
1355 void impl_call_pre (const call_details &cd) const final override
1357 if (const svalue *strlen_sval
1358 = cd.check_for_null_terminated_string_arg (0, false, nullptr))
1359 if (strlen_sval->get_kind () != SK_UNKNOWN)
1361 cd.maybe_set_lhs (strlen_sval);
1362 return;
1365 /* Use a conjured svalue. */
1366 cd.set_any_lhs_with_defaults ();
1370 /* Factory function, so that kf-analyzer.cc can use this class. */
1372 std::unique_ptr<known_function>
1373 make_kf_strlen ()
1375 return make_unique<kf_strlen> ();
1378 /* Handler for "strncpy" and "__builtin_strncpy".
1379 See e.g. https://en.cppreference.com/w/c/string/byte/strncpy
1381 extern char *strncpy (char *dst, const char *src, size_t count);
1383 Handle this by splitting into two outcomes:
1384 (a) truncated read from "src" of "count" bytes,
1385 writing "count" bytes to "dst"
1386 (b) read from "src" of up to (and including) the null terminator,
1387 where the number of bytes read < "count" bytes,
1388 writing those bytes to "dst", and zero-filling the rest,
1389 up to "count". */
1391 class kf_strncpy : public builtin_known_function
1393 public:
1394 bool matches_call_types_p (const call_details &cd) const final override
1396 return (cd.num_args () == 3
1397 && cd.arg_is_pointer_p (0)
1398 && cd.arg_is_pointer_p (1)
1399 && cd.arg_is_integral_p (2));
1401 enum built_in_function builtin_code () const final override
1403 return BUILT_IN_STRNCPY;
1405 void impl_call_post (const call_details &cd) const final override;
1408 void
1409 kf_strncpy::impl_call_post (const call_details &cd) const
1411 class strncpy_call_info : public call_info
1413 public:
1414 strncpy_call_info (const call_details &cd,
1415 const svalue *num_bytes_with_terminator_sval,
1416 bool truncated_read)
1417 : call_info (cd),
1418 m_num_bytes_with_terminator_sval (num_bytes_with_terminator_sval),
1419 m_truncated_read (truncated_read)
1423 label_text get_desc (bool can_colorize) const final override
1425 if (m_truncated_read)
1426 return make_label_text (can_colorize,
1427 "when %qE truncates the source string",
1428 get_fndecl ());
1429 else
1430 return make_label_text (can_colorize,
1431 "when %qE copies the full source string",
1432 get_fndecl ());
1435 bool update_model (region_model *model,
1436 const exploded_edge *,
1437 region_model_context *ctxt) const final override
1439 const call_details cd (get_call_details (model, ctxt));
1441 const svalue *dest_sval = cd.get_arg_svalue (0);
1442 const region *dest_reg
1443 = model->deref_rvalue (dest_sval, cd.get_arg_tree (0), ctxt);
1445 const svalue *src_sval = cd.get_arg_svalue (1);
1446 const region *src_reg
1447 = model->deref_rvalue (src_sval, cd.get_arg_tree (1), ctxt);
1449 const svalue *count_sval = cd.get_arg_svalue (2);
1451 /* strncpy returns the initial param. */
1452 cd.maybe_set_lhs (dest_sval);
1454 const svalue *num_bytes_read_sval;
1455 if (m_truncated_read)
1457 /* Truncated read. */
1458 num_bytes_read_sval = count_sval;
1460 if (m_num_bytes_with_terminator_sval)
1462 /* The terminator is after the limit. */
1463 if (!model->add_constraint (m_num_bytes_with_terminator_sval,
1464 GT_EXPR,
1465 count_sval,
1466 ctxt))
1467 return false;
1469 else
1471 /* We don't know where the terminator is, or if there is one.
1472 In theory we know that the first COUNT bytes are non-zero,
1473 but we don't have a way to record that constraint. */
1476 else
1478 /* Full read of the src string before reaching the limit,
1479 so there must be a terminator and it must be at or before
1480 the limit. */
1481 if (m_num_bytes_with_terminator_sval)
1483 if (!model->add_constraint (m_num_bytes_with_terminator_sval,
1484 LE_EXPR,
1485 count_sval,
1486 ctxt))
1487 return false;
1488 num_bytes_read_sval = m_num_bytes_with_terminator_sval;
1490 /* First, zero-fill the dest buffer.
1491 We don't need to do this for the truncation case, as
1492 this fully populates the dest buffer. */
1493 const region *sized_dest_reg
1494 = model->get_manager ()->get_sized_region (dest_reg,
1495 NULL_TREE,
1496 count_sval);
1497 model->zero_fill_region (sized_dest_reg, ctxt);
1499 else
1501 /* Don't analyze this case; the other case will
1502 assume a "truncated" read up to the limit. */
1503 return false;
1507 gcc_assert (num_bytes_read_sval);
1509 const svalue *bytes_to_copy
1510 = model->read_bytes (src_reg,
1511 cd.get_arg_tree (1),
1512 num_bytes_read_sval,
1513 ctxt);
1514 cd.complain_about_overlap (0, 1, num_bytes_read_sval);
1515 model->write_bytes (dest_reg,
1516 num_bytes_read_sval,
1517 bytes_to_copy,
1518 ctxt);
1520 return true;
1522 private:
1523 /* (strlen + 1) of the source string if it has a terminator,
1524 or NULL for the case where UB would happen before
1525 finding any terminator. */
1526 const svalue *m_num_bytes_with_terminator_sval;
1528 /* true: if this is the outcome where the limit was reached before
1529 the null terminator
1530 false: if the null terminator was reached before the limit. */
1531 bool m_truncated_read;
1534 /* Body of kf_strncpy::impl_call_post. */
1535 if (cd.get_ctxt ())
1537 /* First, scan for a null terminator as if there were no limit,
1538 with a null ctxt so no errors are reported. */
1539 const region_model *model = cd.get_model ();
1540 const svalue *ptr_arg_sval = cd.get_arg_svalue (1);
1541 const region *buf_reg
1542 = model->deref_rvalue (ptr_arg_sval, cd.get_arg_tree (1), nullptr);
1543 const svalue *num_bytes_with_terminator_sval
1544 = model->scan_for_null_terminator (buf_reg,
1545 cd.get_arg_tree (1),
1546 nullptr,
1547 nullptr);
1548 cd.get_ctxt ()->bifurcate
1549 (make_unique<strncpy_call_info> (cd, num_bytes_with_terminator_sval,
1550 false));
1551 cd.get_ctxt ()->bifurcate
1552 (make_unique<strncpy_call_info> (cd, num_bytes_with_terminator_sval,
1553 true));
1554 cd.get_ctxt ()->terminate_path ();
1558 /* Handler for "strndup" and "__builtin_strndup". */
1560 class kf_strndup : public builtin_known_function
1562 public:
1563 bool matches_call_types_p (const call_details &cd) const final override
1565 return (cd.num_args () == 2 && cd.arg_is_pointer_p (0));
1567 enum built_in_function builtin_code () const final override
1569 return BUILT_IN_STRNDUP;
1571 void impl_call_pre (const call_details &cd) const final override
1573 region_model *model = cd.get_model ();
1574 region_model_manager *mgr = cd.get_manager ();
1575 /* Ideally we'd get the size here, and simulate copying the bytes. */
1576 const region *new_reg
1577 = model->get_or_create_region_for_heap_alloc (NULL, cd.get_ctxt ());
1578 model->mark_region_as_unknown (new_reg, NULL);
1579 if (cd.get_lhs_type ())
1581 const svalue *ptr_sval
1582 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
1583 cd.maybe_set_lhs (ptr_sval);
1588 /* Handler for "strstr" and "__builtin_strstr".
1589 extern char *strstr (const char* str, const char* substr);
1590 See e.g. https://en.cppreference.com/w/c/string/byte/strstr */
1592 class kf_strstr : public builtin_known_function
1594 public:
1595 bool matches_call_types_p (const call_details &cd) const final override
1597 return (cd.num_args () == 2
1598 && cd.arg_is_pointer_p (0)
1599 && cd.arg_is_pointer_p (1));
1601 enum built_in_function builtin_code () const final override
1603 return BUILT_IN_STRSTR;
1605 void impl_call_pre (const call_details &cd) const final override
1607 cd.check_for_null_terminated_string_arg (0);
1608 cd.check_for_null_terminated_string_arg (1);
1610 void impl_call_post (const call_details &cd) const final override;
1613 void
1614 kf_strstr::impl_call_post (const call_details &cd) const
1616 class strstr_call_info : public call_info
1618 public:
1619 strstr_call_info (const call_details &cd, bool found)
1620 : call_info (cd), m_found (found)
1624 label_text get_desc (bool can_colorize) const final override
1626 if (m_found)
1627 return make_label_text (can_colorize,
1628 "when %qE returns non-NULL",
1629 get_fndecl ());
1630 else
1631 return make_label_text (can_colorize,
1632 "when %qE returns NULL",
1633 get_fndecl ());
1636 bool update_model (region_model *model,
1637 const exploded_edge *,
1638 region_model_context *ctxt) const final override
1640 const call_details cd (get_call_details (model, ctxt));
1641 if (tree lhs_type = cd.get_lhs_type ())
1643 region_model_manager *mgr = model->get_manager ();
1644 const svalue *result;
1645 if (m_found)
1647 const svalue *str_sval = cd.get_arg_svalue (0);
1648 const region *str_reg
1649 = model->deref_rvalue (str_sval, cd.get_arg_tree (0),
1650 cd.get_ctxt ());
1651 /* We want str_sval + OFFSET for some unknown OFFSET.
1652 Use a conjured_svalue to represent the offset,
1653 using the str_reg as the id of the conjured_svalue. */
1654 const svalue *offset
1655 = mgr->get_or_create_conjured_svalue (size_type_node,
1656 cd.get_call_stmt (),
1657 str_reg,
1658 conjured_purge (model,
1659 ctxt));
1660 result = mgr->get_or_create_binop (lhs_type, POINTER_PLUS_EXPR,
1661 str_sval, offset);
1663 else
1664 result = mgr->get_or_create_int_cst (lhs_type, 0);
1665 cd.maybe_set_lhs (result);
1667 return true;
1669 private:
1670 bool m_found;
1673 /* Body of kf_strstr::impl_call_post. */
1674 if (cd.get_ctxt ())
1676 cd.get_ctxt ()->bifurcate (make_unique<strstr_call_info> (cd, false));
1677 cd.get_ctxt ()->bifurcate (make_unique<strstr_call_info> (cd, true));
1678 cd.get_ctxt ()->terminate_path ();
1682 class kf_ubsan_bounds : public internal_known_function
1684 /* Empty. */
1687 /* Handle calls to functions referenced by
1688 __attribute__((malloc(FOO))). */
1690 void
1691 region_model::impl_deallocation_call (const call_details &cd)
1693 kf_free kf;
1694 kf.impl_call_post (cd);
1697 static void
1698 register_atomic_builtins (known_function_manager &kfm)
1700 kfm.add (BUILT_IN_ATOMIC_EXCHANGE, make_unique<kf_atomic_exchange> ());
1701 kfm.add (BUILT_IN_ATOMIC_EXCHANGE_N, make_unique<kf_atomic_exchange_n> ());
1702 kfm.add (BUILT_IN_ATOMIC_EXCHANGE_1, make_unique<kf_atomic_exchange_n> ());
1703 kfm.add (BUILT_IN_ATOMIC_EXCHANGE_2, make_unique<kf_atomic_exchange_n> ());
1704 kfm.add (BUILT_IN_ATOMIC_EXCHANGE_4, make_unique<kf_atomic_exchange_n> ());
1705 kfm.add (BUILT_IN_ATOMIC_EXCHANGE_8, make_unique<kf_atomic_exchange_n> ());
1706 kfm.add (BUILT_IN_ATOMIC_EXCHANGE_16, make_unique<kf_atomic_exchange_n> ());
1707 kfm.add (BUILT_IN_ATOMIC_LOAD, make_unique<kf_atomic_load> ());
1708 kfm.add (BUILT_IN_ATOMIC_LOAD_N, make_unique<kf_atomic_load_n> ());
1709 kfm.add (BUILT_IN_ATOMIC_LOAD_1, make_unique<kf_atomic_load_n> ());
1710 kfm.add (BUILT_IN_ATOMIC_LOAD_2, make_unique<kf_atomic_load_n> ());
1711 kfm.add (BUILT_IN_ATOMIC_LOAD_4, make_unique<kf_atomic_load_n> ());
1712 kfm.add (BUILT_IN_ATOMIC_LOAD_8, make_unique<kf_atomic_load_n> ());
1713 kfm.add (BUILT_IN_ATOMIC_LOAD_16, make_unique<kf_atomic_load_n> ());
1714 kfm.add (BUILT_IN_ATOMIC_STORE_N, make_unique<kf_atomic_store_n> ());
1715 kfm.add (BUILT_IN_ATOMIC_STORE_1, make_unique<kf_atomic_store_n> ());
1716 kfm.add (BUILT_IN_ATOMIC_STORE_2, make_unique<kf_atomic_store_n> ());
1717 kfm.add (BUILT_IN_ATOMIC_STORE_4, make_unique<kf_atomic_store_n> ());
1718 kfm.add (BUILT_IN_ATOMIC_STORE_8, make_unique<kf_atomic_store_n> ());
1719 kfm.add (BUILT_IN_ATOMIC_STORE_16, make_unique<kf_atomic_store_n> ());
1720 kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_1,
1721 make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
1722 kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_2,
1723 make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
1724 kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_4,
1725 make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
1726 kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_8,
1727 make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
1728 kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_16,
1729 make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
1730 kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_1,
1731 make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
1732 kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_2,
1733 make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
1734 kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_4,
1735 make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
1736 kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_8,
1737 make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
1738 kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_16,
1739 make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
1740 kfm.add (BUILT_IN_ATOMIC_AND_FETCH_1,
1741 make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
1742 kfm.add (BUILT_IN_ATOMIC_AND_FETCH_2,
1743 make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
1744 kfm.add (BUILT_IN_ATOMIC_AND_FETCH_4,
1745 make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
1746 kfm.add (BUILT_IN_ATOMIC_AND_FETCH_8,
1747 make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
1748 kfm.add (BUILT_IN_ATOMIC_AND_FETCH_16,
1749 make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
1750 kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_1,
1751 make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
1752 kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_2,
1753 make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
1754 kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_4,
1755 make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
1756 kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_8,
1757 make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
1758 kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_16,
1759 make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
1760 kfm.add (BUILT_IN_ATOMIC_OR_FETCH_1,
1761 make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
1762 kfm.add (BUILT_IN_ATOMIC_OR_FETCH_2,
1763 make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
1764 kfm.add (BUILT_IN_ATOMIC_OR_FETCH_4,
1765 make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
1766 kfm.add (BUILT_IN_ATOMIC_OR_FETCH_8,
1767 make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
1768 kfm.add (BUILT_IN_ATOMIC_OR_FETCH_16,
1769 make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
1770 kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_1,
1771 make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
1772 kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_2,
1773 make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
1774 kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_4,
1775 make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
1776 kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_8,
1777 make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
1778 kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_16,
1779 make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
1780 kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_1,
1781 make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
1782 kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_2,
1783 make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
1784 kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_4,
1785 make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
1786 kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_8,
1787 make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
1788 kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_16,
1789 make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
1790 kfm.add (BUILT_IN_ATOMIC_FETCH_AND_1,
1791 make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
1792 kfm.add (BUILT_IN_ATOMIC_FETCH_AND_2,
1793 make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
1794 kfm.add (BUILT_IN_ATOMIC_FETCH_AND_4,
1795 make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
1796 kfm.add (BUILT_IN_ATOMIC_FETCH_AND_8,
1797 make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
1798 kfm.add (BUILT_IN_ATOMIC_FETCH_AND_16,
1799 make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
1800 kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_1,
1801 make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
1802 kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_2,
1803 make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
1804 kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_4,
1805 make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
1806 kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_8,
1807 make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
1808 kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_16,
1809 make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
1810 kfm.add (BUILT_IN_ATOMIC_FETCH_OR_1,
1811 make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
1812 kfm.add (BUILT_IN_ATOMIC_FETCH_OR_2,
1813 make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
1814 kfm.add (BUILT_IN_ATOMIC_FETCH_OR_4,
1815 make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
1816 kfm.add (BUILT_IN_ATOMIC_FETCH_OR_8,
1817 make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
1818 kfm.add (BUILT_IN_ATOMIC_FETCH_OR_16,
1819 make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
1822 /* Populate KFM with instances of known functions supported by the core of the
1823 analyzer (as opposed to plugins). */
1825 void
1826 register_known_functions (known_function_manager &kfm)
1828 /* Debugging/test support functions, all with a "__analyzer_" prefix. */
1829 register_known_analyzer_functions (kfm);
1831 /* Internal fns the analyzer has known_functions for. */
1833 kfm.add (IFN_BUILTIN_EXPECT, make_unique<kf_expect> ());
1834 kfm.add (IFN_UBSAN_BOUNDS, make_unique<kf_ubsan_bounds> ());
1837 /* GCC built-ins that do not correspond to a function
1838 in the standard library. */
1840 kfm.add (BUILT_IN_EXPECT, make_unique<kf_expect> ());
1841 kfm.add (BUILT_IN_EXPECT_WITH_PROBABILITY, make_unique<kf_expect> ());
1842 kfm.add (BUILT_IN_ALLOCA_WITH_ALIGN, make_unique<kf_alloca> ());
1843 kfm.add (BUILT_IN_STACK_RESTORE, make_unique<kf_stack_restore> ());
1844 kfm.add (BUILT_IN_STACK_SAVE, make_unique<kf_stack_save> ());
1846 register_atomic_builtins (kfm);
1847 register_varargs_builtins (kfm);
1850 /* Known builtins and C standard library functions
1851 the analyzer has known functions for. */
1853 kfm.add ("alloca", make_unique<kf_alloca> ());
1854 kfm.add ("__builtin_alloca", make_unique<kf_alloca> ());
1855 kfm.add ("calloc", make_unique<kf_calloc> ());
1856 kfm.add ("__builtin_calloc", make_unique<kf_calloc> ());
1857 kfm.add ("free", make_unique<kf_free> ());
1858 kfm.add ("__builtin_free", make_unique<kf_free> ());
1859 kfm.add ("malloc", make_unique<kf_malloc> ());
1860 kfm.add ("__builtin_malloc", make_unique<kf_malloc> ());
1861 kfm.add ("memcpy",
1862 make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
1863 kfm.add ("__builtin_memcpy",
1864 make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
1865 kfm.add ("__memcpy_chk", make_unique<kf_memcpy_memmove>
1866 (kf_memcpy_memmove::KF_MEMCPY_CHK));
1867 kfm.add ("__builtin___memcpy_chk", make_unique<kf_memcpy_memmove>
1868 (kf_memcpy_memmove::KF_MEMCPY_CHK));
1869 kfm.add ("memmove",
1870 make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
1871 kfm.add ("__builtin_memmove",
1872 make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
1873 kfm.add ("__memmove_chk", make_unique<kf_memcpy_memmove>
1874 (kf_memcpy_memmove::KF_MEMMOVE_CHK));
1875 kfm.add ("__builtin___memmove_chk", make_unique<kf_memcpy_memmove>
1876 (kf_memcpy_memmove::KF_MEMMOVE_CHK));
1877 kfm.add ("memset", make_unique<kf_memset> (false));
1878 kfm.add ("__builtin_memset", make_unique<kf_memset> (false));
1879 kfm.add ("__memset_chk", make_unique<kf_memset> (true));
1880 kfm.add ("__builtin___memset_chk", make_unique<kf_memset> (true));
1881 kfm.add ("realloc", make_unique<kf_realloc> ());
1882 kfm.add ("__builtin_realloc", make_unique<kf_realloc> ());
1883 kfm.add ("sprintf", make_unique<kf_sprintf> ());
1884 kfm.add ("__builtin_sprintf", make_unique<kf_sprintf> ());
1885 kfm.add ("strchr", make_unique<kf_strchr> ());
1886 kfm.add ("__builtin_strchr", make_unique<kf_strchr> ());
1887 kfm.add ("strcpy", make_unique<kf_strcpy> (2, false));
1888 kfm.add ("__builtin_strcpy", make_unique<kf_strcpy> (2, false));
1889 kfm.add ("__strcpy_chk", make_unique<kf_strcpy> (3, true));
1890 kfm.add ("__builtin___strcpy_chk", make_unique<kf_strcpy> (3, true));
1891 kfm.add ("strcat", make_unique<kf_strcat> (2, false));
1892 kfm.add ("__builtin_strcat", make_unique<kf_strcat> (2, false));
1893 kfm.add ("__strcat_chk", make_unique<kf_strcat> (3, true));
1894 kfm.add ("__builtin___strcat_chk", make_unique<kf_strcat> (3, true));
1895 kfm.add ("strdup", make_unique<kf_strdup> ());
1896 kfm.add ("__builtin_strdup", make_unique<kf_strdup> ());
1897 kfm.add ("strncpy", make_unique<kf_strncpy> ());
1898 kfm.add ("__builtin_strncpy", make_unique<kf_strncpy> ());
1899 kfm.add ("strndup", make_unique<kf_strndup> ());
1900 kfm.add ("__builtin_strndup", make_unique<kf_strndup> ());
1901 kfm.add ("strlen", make_unique<kf_strlen> ());
1902 kfm.add ("__builtin_strlen", make_unique<kf_strlen> ());
1903 kfm.add ("strstr", make_unique<kf_strstr> ());
1904 kfm.add ("__builtin_strstr", make_unique<kf_strstr> ());
1906 register_atomic_builtins (kfm);
1907 register_varargs_builtins (kfm);
1910 /* Known POSIX functions, and some non-standard extensions. */
1912 kfm.add ("fopen", make_unique<kf_fopen> ());
1913 kfm.add ("putenv", make_unique<kf_putenv> ());
1915 register_known_fd_functions (kfm);
1916 register_known_file_functions (kfm);
1919 /* glibc functions. */
1921 kfm.add ("__errno_location", make_unique<kf_errno_location> ());
1922 kfm.add ("error", make_unique<kf_error> (3));
1923 kfm.add ("error_at_line", make_unique<kf_error> (5));
1926 /* Other implementations of C standard library. */
1928 /* According to PR 107807 comment #2, Solaris implements "errno"
1929 like this:
1930 extern int *___errno(void) __attribute__((__const__));
1931 #define errno (*(___errno()))
1932 and macOS like this:
1933 extern int * __error(void);
1934 #define errno (*__error())
1935 and similarly __errno for newlib.
1936 Add these as synonyms for "__errno_location". */
1937 kfm.add ("___errno", make_unique<kf_errno_location> ());
1938 kfm.add ("__error", make_unique<kf_errno_location> ());
1939 kfm.add ("__errno", make_unique<kf_errno_location> ());
1942 /* Language-specific support functions. */
1943 register_known_functions_lang_cp (kfm);
1946 } // namespace ana
1948 #endif /* #if ENABLE_ANALYZER */