PR modula2/116048 ICE when encountering wrong kind of qualident
[official-gcc.git] / gcc / analyzer / kf.cc
blob5c3a71fbb49c9e8285a0e9f8d385f24ead9d364e
1 /* Handling for the known behavior of various specific functions.
2 Copyright (C) 2020-2024 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 #define INCLUDE_VECTOR
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tree.h"
27 #include "function.h"
28 #include "basic-block.h"
29 #include "gimple.h"
30 #include "diagnostic-core.h"
31 #include "diagnostic-metadata.h"
32 #include "analyzer/analyzer.h"
33 #include "analyzer/analyzer-logging.h"
34 #include "diagnostic.h"
35 #include "analyzer/region-model.h"
36 #include "analyzer/call-details.h"
37 #include "analyzer/call-info.h"
38 #include "make-unique.h"
40 #if ENABLE_ANALYZER
42 namespace ana {
44 /* Abstract subclass for describing undefined behavior of an API. */
46 class undefined_function_behavior
47 : public pending_diagnostic_subclass<undefined_function_behavior>
49 public:
50 undefined_function_behavior (const call_details &cd)
51 : m_call_stmt (cd.get_call_stmt ()),
52 m_callee_fndecl (cd.get_fndecl_for_call ())
54 gcc_assert (m_call_stmt);
55 gcc_assert (m_callee_fndecl);
58 const char *get_kind () const final override
60 return "undefined_behavior";
63 bool operator== (const undefined_function_behavior &other) const
65 return (m_call_stmt == other.m_call_stmt
66 && m_callee_fndecl == other.m_callee_fndecl);
69 bool terminate_path_p () const final override { return true; }
71 tree get_callee_fndecl () const { return m_callee_fndecl; }
73 private:
74 const gimple *m_call_stmt;
75 tree m_callee_fndecl;
78 /* class pure_known_function_with_default_return : public known_function. */
80 void
81 pure_known_function_with_default_return::
82 impl_call_pre (const call_details &cd) const
84 cd.set_any_lhs_with_defaults ();
87 /* Implementations of specific functions. */
89 /* Handler for "alloca". */
91 class kf_alloca : public builtin_known_function
93 public:
94 bool matches_call_types_p (const call_details &cd) const final override
96 return cd.num_args () == 1;
98 enum built_in_function builtin_code () const final override
100 return BUILT_IN_ALLOCA;
102 void impl_call_pre (const call_details &cd) const final override;
105 void
106 kf_alloca::impl_call_pre (const call_details &cd) const
108 const svalue *size_sval = cd.get_arg_svalue (0);
110 region_model *model = cd.get_model ();
111 region_model_manager *mgr = cd.get_manager ();
113 const region *new_reg
114 = model->create_region_for_alloca (size_sval, cd.get_ctxt ());
115 const svalue *ptr_sval
116 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
117 cd.maybe_set_lhs (ptr_sval);
120 /* Handler for __atomic_exchange.
121 Although the user-facing documentation specifies it as having this
122 signature:
123 void __atomic_exchange (type *ptr, type *val, type *ret, int memorder)
125 by the time the C/C++ frontends have acted on it, any calls that
126 can't be mapped to a _N variation end up with this signature:
128 void
129 __atomic_exchange (size_t sz, void *ptr, void *val, void *ret,
130 int memorder)
132 as seen in the gimple seen by the analyzer, and as specified
133 in sync-builtins.def. */
135 class kf_atomic_exchange : public internal_known_function
137 public:
138 /* This is effectively:
139 tmpA = *PTR;
140 tmpB = *VAL;
141 *PTR = tmpB;
142 *RET = tmpA;
144 void impl_call_pre (const call_details &cd) const final override
146 const svalue *num_bytes_sval = cd.get_arg_svalue (0);
147 const svalue *ptr_sval = cd.get_arg_svalue (1);
148 tree ptr_tree = cd.get_arg_tree (1);
149 const svalue *val_sval = cd.get_arg_svalue (2);
150 tree val_tree = cd.get_arg_tree (2);
151 const svalue *ret_sval = cd.get_arg_svalue (3);
152 tree ret_tree = cd.get_arg_tree (3);
153 /* Ignore the memorder param. */
155 region_model *model = cd.get_model ();
156 region_model_context *ctxt = cd.get_ctxt ();
158 const region *ptr_reg = model->deref_rvalue (ptr_sval, ptr_tree, ctxt);
159 const region *val_reg = model->deref_rvalue (val_sval, val_tree, ctxt);
160 const region *ret_reg = model->deref_rvalue (ret_sval, ret_tree, ctxt);
162 const svalue *tmp_a_sval
163 = model->read_bytes (ptr_reg, ptr_tree, num_bytes_sval, ctxt);
164 const svalue *tmp_b_sval
165 = model->read_bytes (val_reg, val_tree, num_bytes_sval, ctxt);
166 model->write_bytes (ptr_reg, num_bytes_sval, tmp_b_sval, ctxt);
167 model->write_bytes (ret_reg, num_bytes_sval, tmp_a_sval, ctxt);
171 /* Handler for:
172 __atomic_exchange_n (type *ptr, type val, int memorder). */
174 class kf_atomic_exchange_n : public internal_known_function
176 public:
177 /* This is effectively:
178 RET = *PTR;
179 *PTR = VAL;
180 return RET;
182 void impl_call_pre (const call_details &cd) const final override
184 const svalue *ptr_sval = cd.get_arg_svalue (0);
185 tree ptr_tree = cd.get_arg_tree (0);
186 const svalue *set_sval = cd.get_arg_svalue (1);
187 /* Ignore the memorder param. */
189 region_model *model = cd.get_model ();
190 region_model_context *ctxt = cd.get_ctxt ();
192 const region *dst_region = model->deref_rvalue (ptr_sval, ptr_tree, ctxt);
193 const svalue *ret_sval = model->get_store_value (dst_region, ctxt);
194 model->set_value (dst_region, set_sval, ctxt);
195 cd.maybe_set_lhs (ret_sval);
199 /* Handler for:
200 type __atomic_fetch_add (type *ptr, type val, int memorder);
201 type __atomic_fetch_sub (type *ptr, type val, int memorder);
202 type __atomic_fetch_and (type *ptr, type val, int memorder);
203 type __atomic_fetch_xor (type *ptr, type val, int memorder);
204 type __atomic_fetch_or (type *ptr, type val, int memorder);
207 class kf_atomic_fetch_op : public internal_known_function
209 public:
210 kf_atomic_fetch_op (enum tree_code op): m_op (op) {}
212 /* This is effectively:
213 RET = *PTR;
214 *PTR = RET OP VAL;
215 return RET;
217 void impl_call_pre (const call_details &cd) const final override
219 const svalue *ptr_sval = cd.get_arg_svalue (0);
220 tree ptr_tree = cd.get_arg_tree (0);
221 const svalue *val_sval = cd.get_arg_svalue (1);
222 /* Ignore the memorder param. */
224 region_model *model = cd.get_model ();
225 region_model_manager *mgr = cd.get_manager ();
226 region_model_context *ctxt = cd.get_ctxt ();
228 const region *star_ptr_region
229 = model->deref_rvalue (ptr_sval, ptr_tree, ctxt);
230 const svalue *old_sval = model->get_store_value (star_ptr_region, ctxt);
231 const svalue *new_sval = mgr->get_or_create_binop (old_sval->get_type (),
232 m_op,
233 old_sval, val_sval);
234 model->set_value (star_ptr_region, new_sval, ctxt);
235 cd.maybe_set_lhs (old_sval);
238 private:
239 enum tree_code m_op;
242 /* Handler for:
243 type __atomic_add_fetch (type *ptr, type val, int memorder);
244 type __atomic_sub_fetch (type *ptr, type val, int memorder);
245 type __atomic_and_fetch (type *ptr, type val, int memorder);
246 type __atomic_xor_fetch (type *ptr, type val, int memorder);
247 type __atomic_or_fetch (type *ptr, type val, int memorder);
250 class kf_atomic_op_fetch : public internal_known_function
252 public:
253 kf_atomic_op_fetch (enum tree_code op): m_op (op) {}
255 /* This is effectively:
256 *PTR = RET OP VAL;
257 return *PTR;
259 void impl_call_pre (const call_details &cd) const final override
261 const svalue *ptr_sval = cd.get_arg_svalue (0);
262 tree ptr_tree = cd.get_arg_tree (0);
263 const svalue *val_sval = cd.get_arg_svalue (1);
264 /* Ignore the memorder param. */
266 region_model *model = cd.get_model ();
267 region_model_manager *mgr = cd.get_manager ();
268 region_model_context *ctxt = cd.get_ctxt ();
270 const region *star_ptr_region
271 = model->deref_rvalue (ptr_sval, ptr_tree, ctxt);
272 const svalue *old_sval = model->get_store_value (star_ptr_region, ctxt);
273 const svalue *new_sval = mgr->get_or_create_binop (old_sval->get_type (),
274 m_op,
275 old_sval, val_sval);
276 model->set_value (star_ptr_region, new_sval, ctxt);
277 cd.maybe_set_lhs (new_sval);
280 private:
281 enum tree_code m_op;
284 /* Handler for __atomic_load.
285 Although the user-facing documentation specifies it as having this
286 signature:
288 void __atomic_load (type *ptr, type *ret, int memorder)
290 by the time the C/C++ frontends have acted on it, any calls that
291 can't be mapped to a _N variation end up with this signature:
293 void __atomic_load (size_t sz, const void *src, void *dst, int memorder);
295 as seen in the gimple seen by the analyzer, and as specified
296 in sync-builtins.def. */
298 class kf_atomic_load : public internal_known_function
300 public:
301 /* This is effectively:
302 memmove (dst, src, sz);
304 void impl_call_pre (const call_details &cd) const final override
306 const svalue *num_bytes_sval = cd.get_arg_svalue (0);
307 const svalue *src_sval = cd.get_arg_svalue (1);
308 tree src_tree = cd.get_arg_tree (1);
309 const svalue *dst_sval = cd.get_arg_svalue (2);
310 tree dst_tree = cd.get_arg_tree (2);
311 /* Ignore the memorder param. */
313 region_model *model = cd.get_model ();
314 region_model_context *ctxt = cd.get_ctxt ();
316 const region *dst_reg = model->deref_rvalue (dst_sval, dst_tree, ctxt);
317 const region *src_reg = model->deref_rvalue (src_sval, src_tree, ctxt);
319 const svalue *data_sval
320 = model->read_bytes (src_reg, src_tree, num_bytes_sval, ctxt);
321 model->write_bytes (dst_reg, num_bytes_sval, data_sval, ctxt);
325 /* Handler for __atomic_store.
326 Although the user-facing documentation specifies it as having this
327 signature:
329 void __atomic_store (type *ptr, type *val, int memorder)
331 by the time the C/C++ frontends have acted on it, any calls that
332 can't be mapped to a _N variation end up with this signature:
334 void __atomic_store (size_t sz, type *dst, type *src, int memorder)
336 as seen in the gimple seen by the analyzer, and as specified
337 in sync-builtins.def. */
339 class kf_atomic_store : public internal_known_function
341 public:
342 /* This is effectively:
343 memmove (dst, src, sz);
345 void impl_call_pre (const call_details &cd) const final override
347 const svalue *num_bytes_sval = cd.get_arg_svalue (0);
348 const svalue *dst_sval = cd.get_arg_svalue (1);
349 tree dst_tree = cd.get_arg_tree (1);
350 const svalue *src_sval = cd.get_arg_svalue (2);
351 tree src_tree = cd.get_arg_tree (2);
352 /* Ignore the memorder param. */
354 region_model *model = cd.get_model ();
355 region_model_context *ctxt = cd.get_ctxt ();
357 const region *dst_reg = model->deref_rvalue (dst_sval, dst_tree, ctxt);
358 const region *src_reg = model->deref_rvalue (src_sval, src_tree, ctxt);
360 const svalue *data_sval
361 = model->read_bytes (src_reg, src_tree, num_bytes_sval, ctxt);
362 model->write_bytes (dst_reg, num_bytes_sval, data_sval, ctxt);
366 /* Handler for:
367 type __atomic_load_n (type *ptr, int memorder) */
369 class kf_atomic_load_n : public internal_known_function
371 public:
372 /* This is effectively:
373 RET = *PTR;
374 return RET;
376 void impl_call_pre (const call_details &cd) const final override
378 const svalue *ptr_ptr_sval = cd.get_arg_svalue (0);
379 tree ptr_ptr_tree = cd.get_arg_tree (0);
380 /* Ignore the memorder param. */
382 region_model *model = cd.get_model ();
383 region_model_context *ctxt = cd.get_ctxt ();
385 const region *ptr_region
386 = model->deref_rvalue (ptr_ptr_sval, ptr_ptr_tree, ctxt);
387 const svalue *star_ptr_sval = model->get_store_value (ptr_region, ctxt);
388 cd.maybe_set_lhs (star_ptr_sval);
392 /* Handler for:
393 void __atomic_store_n (type *ptr, type val, int memorder) */
395 class kf_atomic_store_n : public internal_known_function
397 public:
398 /* This is effectively:
399 *PTR = VAL;
401 void impl_call_pre (const call_details &cd) const final override
403 const svalue *ptr_sval = cd.get_arg_svalue (0);
404 tree ptr_tree = cd.get_arg_tree (0);
405 const svalue *new_sval = cd.get_arg_svalue (1);
406 /* Ignore the memorder param. */
408 region_model *model = cd.get_model ();
409 region_model_context *ctxt = cd.get_ctxt ();
411 const region *star_ptr_region
412 = model->deref_rvalue (ptr_sval, ptr_tree, ctxt);
413 model->set_value (star_ptr_region, new_sval, ctxt);
417 /* Handler for "__builtin_expect" etc. */
419 class kf_expect : public internal_known_function
421 public:
422 void impl_call_pre (const call_details &cd) const final override
424 /* __builtin_expect's return value is its initial argument. */
425 const svalue *sval = cd.get_arg_svalue (0);
426 cd.maybe_set_lhs (sval);
430 /* Handler for "calloc". */
432 class kf_calloc : public builtin_known_function
434 public:
435 bool matches_call_types_p (const call_details &cd) const final override
437 return (cd.num_args () == 2
438 && cd.arg_is_size_p (0)
439 && cd.arg_is_size_p (1));
441 enum built_in_function builtin_code () const final override
443 return BUILT_IN_CALLOC;
446 void impl_call_pre (const call_details &cd) const final override;
449 void
450 kf_calloc::impl_call_pre (const call_details &cd) const
452 region_model *model = cd.get_model ();
453 region_model_manager *mgr = cd.get_manager ();
454 const svalue *nmemb_sval = cd.get_arg_svalue (0);
455 const svalue *size_sval = cd.get_arg_svalue (1);
456 /* TODO: check for overflow here? */
457 const svalue *prod_sval
458 = mgr->get_or_create_binop (size_type_node, MULT_EXPR,
459 nmemb_sval, size_sval);
460 const region *new_reg
461 = model->get_or_create_region_for_heap_alloc (prod_sval, cd.get_ctxt ());
462 const region *sized_reg
463 = mgr->get_sized_region (new_reg, NULL_TREE, prod_sval);
464 model->zero_fill_region (sized_reg, cd.get_ctxt ());
465 if (cd.get_lhs_type ())
467 const svalue *ptr_sval
468 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
469 cd.maybe_set_lhs (ptr_sval);
473 /* Handler for glibc's "__errno_location". */
475 class kf_errno_location : public known_function
477 public:
478 bool matches_call_types_p (const call_details &cd) const final override
480 return cd.num_args () == 0;
483 void impl_call_pre (const call_details &cd) const final override
485 if (cd.get_lhs_region ())
487 region_model_manager *mgr = cd.get_manager ();
488 const region *errno_reg = mgr->get_errno_region ();
489 const svalue *errno_ptr = mgr->get_ptr_svalue (cd.get_lhs_type (),
490 errno_reg);
491 cd.maybe_set_lhs (errno_ptr);
496 /* Handler for "error" and "error_at_line" from GNU's non-standard <error.h>.
497 MIN_ARGS identifies the minimum number of expected arguments
498 to be consistent with such a call (3 and 5 respectively). */
500 class kf_error : public known_function
502 public:
503 kf_error (unsigned min_args) : m_min_args (min_args) {}
505 bool matches_call_types_p (const call_details &cd) const final override
507 return (cd.num_args () >= m_min_args
508 && cd.get_arg_type (0) == integer_type_node);
511 void impl_call_pre (const call_details &cd) const final override;
513 private:
514 unsigned m_min_args;
517 void
518 kf_error::impl_call_pre (const call_details &cd) const
520 /* The process exits if status != 0, so it only continues
521 for the case where status == 0.
522 Add that constraint, or terminate this analysis path. */
523 tree status = cd.get_arg_tree (0);
524 region_model_context *ctxt = cd.get_ctxt ();
525 region_model *model = cd.get_model ();
526 if (!model->add_constraint (status, EQ_EXPR, integer_zero_node, ctxt))
527 if (ctxt)
528 ctxt->terminate_path ();
530 /* Check "format" arg. */
531 const int fmt_arg_idx = (m_min_args == 3) ? 2 : 4;
532 model->check_for_null_terminated_string_arg (cd, fmt_arg_idx);
535 /* Handler for fopen.
536 FILE *fopen (const char *filename, const char *mode);
537 See e.g. https://en.cppreference.com/w/c/io/fopen
538 https://www.man7.org/linux/man-pages/man3/fopen.3.html
539 https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfopen?view=msvc-170 */
541 class kf_fopen : public known_function
543 public:
544 bool matches_call_types_p (const call_details &cd) const final override
546 return (cd.num_args () == 2
547 && cd.arg_is_pointer_p (0)
548 && cd.arg_is_pointer_p (1));
551 void impl_call_pre (const call_details &cd) const final override
553 cd.check_for_null_terminated_string_arg (0);
554 cd.check_for_null_terminated_string_arg (1);
555 cd.set_any_lhs_with_defaults ();
557 /* fopen's mode param is effectively a mini-DSL, but there are various
558 non-standard extensions, so we don't bother to check it. */
562 /* Handler for "free", after sm-handling.
564 If the ptr points to an underlying heap region, delete the region,
565 poisoning pointers to it and regions within it.
567 We delay this until after sm-state has been updated so that the
568 sm-handling can transition all of the various casts of the pointer
569 to a "freed" state *before* we delete the related region here.
571 This has to be done here so that the sm-handling can use the fact
572 that they point to the same region to establish that they are equal
573 (in region_model::eval_condition), and thus transition
574 all pointers to the region to the "freed" state together, regardless
575 of casts. */
577 class kf_free : public builtin_known_function
579 public:
580 bool matches_call_types_p (const call_details &cd) const final override
582 return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
584 enum built_in_function builtin_code () const final override
586 return BUILT_IN_FREE;
588 void impl_call_post (const call_details &cd) const final override;
591 void
592 kf_free::impl_call_post (const call_details &cd) const
594 const svalue *ptr_sval = cd.get_arg_svalue (0);
595 if (const region *freed_reg = ptr_sval->maybe_get_region ())
597 /* If the ptr points to an underlying heap region, delete it,
598 poisoning pointers. */
599 region_model *model = cd.get_model ();
600 model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
601 model->unset_dynamic_extents (freed_reg);
605 /* Handle the on_call_pre part of "malloc". */
607 class kf_malloc : public builtin_known_function
609 public:
610 bool matches_call_types_p (const call_details &cd) const final override
612 return (cd.num_args () == 1
613 && cd.arg_is_size_p (0));
615 enum built_in_function builtin_code () const final override
617 return BUILT_IN_MALLOC;
619 void impl_call_pre (const call_details &cd) const final override;
622 void
623 kf_malloc::impl_call_pre (const call_details &cd) const
625 region_model *model = cd.get_model ();
626 region_model_manager *mgr = cd.get_manager ();
627 const svalue *size_sval = cd.get_arg_svalue (0);
628 const region *new_reg
629 = model->get_or_create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
630 if (cd.get_lhs_type ())
632 const svalue *ptr_sval
633 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
634 cd.maybe_set_lhs (ptr_sval);
638 /* Handler for "memcpy" and "__builtin_memcpy",
639 "memmove", and "__builtin_memmove". */
641 class kf_memcpy_memmove : public builtin_known_function
643 public:
644 enum kf_memcpy_memmove_variant
646 KF_MEMCPY,
647 KF_MEMCPY_CHK,
648 KF_MEMMOVE,
649 KF_MEMMOVE_CHK,
651 kf_memcpy_memmove (enum kf_memcpy_memmove_variant variant)
652 : m_variant (variant) {};
653 bool matches_call_types_p (const call_details &cd) const final override
655 return (cd.num_args () == 3
656 && cd.arg_is_pointer_p (0)
657 && cd.arg_is_pointer_p (1)
658 && cd.arg_is_size_p (2));
660 enum built_in_function builtin_code () const final override
662 switch (m_variant)
664 case KF_MEMCPY:
665 return BUILT_IN_MEMCPY;
666 case KF_MEMCPY_CHK:
667 return BUILT_IN_MEMCPY_CHK;
668 case KF_MEMMOVE:
669 return BUILT_IN_MEMMOVE;
670 case KF_MEMMOVE_CHK:
671 return BUILT_IN_MEMMOVE_CHK;
672 default:
673 gcc_unreachable ();
676 void impl_call_pre (const call_details &cd) const final override;
677 private:
678 const enum kf_memcpy_memmove_variant m_variant;
681 void
682 kf_memcpy_memmove::impl_call_pre (const call_details &cd) const
684 const svalue *dest_ptr_sval = cd.get_arg_svalue (0);
685 const svalue *src_ptr_sval = cd.get_arg_svalue (1);
686 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
688 region_model *model = cd.get_model ();
690 const region *dest_reg
691 = model->deref_rvalue (dest_ptr_sval, cd.get_arg_tree (0), cd.get_ctxt ());
692 const region *src_reg
693 = model->deref_rvalue (src_ptr_sval, cd.get_arg_tree (1), cd.get_ctxt ());
695 cd.maybe_set_lhs (dest_ptr_sval);
696 /* Check for overlap. */
697 switch (m_variant)
699 case KF_MEMCPY:
700 case KF_MEMCPY_CHK:
701 cd.complain_about_overlap (0, 1, num_bytes_sval);
702 break;
704 case KF_MEMMOVE:
705 case KF_MEMMOVE_CHK:
706 /* It's OK for memmove's arguments to overlap. */
707 break;
709 default:
710 gcc_unreachable ();
712 model->copy_bytes (dest_reg,
713 src_reg, cd.get_arg_tree (1),
714 num_bytes_sval,
715 cd.get_ctxt ());
718 /* Handler for "memset" and "__builtin_memset". */
720 class kf_memset : public builtin_known_function
722 public:
723 kf_memset (bool chk_variant) : m_chk_variant (chk_variant) {}
724 bool matches_call_types_p (const call_details &cd) const final override
726 return (cd.num_args () == 3 && cd.arg_is_pointer_p (0));
728 enum built_in_function builtin_code () const final override
730 return m_chk_variant ? BUILT_IN_MEMSET_CHK : BUILT_IN_MEMSET;
732 void impl_call_pre (const call_details &cd) const final override;
733 private:
734 const bool m_chk_variant;
737 void
738 kf_memset::impl_call_pre (const call_details &cd) const
740 const svalue *dest_sval = cd.get_arg_svalue (0);
741 const svalue *fill_value_sval = cd.get_arg_svalue (1);
742 const svalue *num_bytes_sval = cd.get_arg_svalue (2);
744 region_model *model = cd.get_model ();
745 region_model_manager *mgr = cd.get_manager ();
747 const region *dest_reg
748 = model->deref_rvalue (dest_sval, cd.get_arg_tree (0), cd.get_ctxt ());
750 const svalue *fill_value_u8
751 = mgr->get_or_create_cast (unsigned_char_type_node, fill_value_sval);
753 const region *sized_dest_reg = mgr->get_sized_region (dest_reg,
754 NULL_TREE,
755 num_bytes_sval);
756 model->fill_region (sized_dest_reg, fill_value_u8, cd.get_ctxt ());
758 cd.maybe_set_lhs (dest_sval);
761 /* A subclass of pending_diagnostic for complaining about 'putenv'
762 called on an auto var. */
764 class putenv_of_auto_var
765 : public pending_diagnostic_subclass<putenv_of_auto_var>
767 public:
768 putenv_of_auto_var (tree fndecl, const region *reg)
769 : m_fndecl (fndecl), m_reg (reg),
770 m_var_decl (reg->get_base_region ()->maybe_get_decl ())
774 const char *get_kind () const final override
776 return "putenv_of_auto_var";
779 bool operator== (const putenv_of_auto_var &other) const
781 return (m_fndecl == other.m_fndecl
782 && m_reg == other.m_reg
783 && same_tree_p (m_var_decl, other.m_var_decl));
786 int get_controlling_option () const final override
788 return OPT_Wanalyzer_putenv_of_auto_var;
791 bool emit (diagnostic_emission_context &ctxt) final override
793 auto_diagnostic_group d;
795 /* SEI CERT C Coding Standard: "POS34-C. Do not call putenv() with a
796 pointer to an automatic variable as the argument". */
797 diagnostic_metadata::precanned_rule
798 rule ("POS34-C", "https://wiki.sei.cmu.edu/confluence/x/6NYxBQ");
799 ctxt.add_rule (rule);
801 bool warned;
802 if (m_var_decl)
803 warned = ctxt.warn ("%qE on a pointer to automatic variable %qE",
804 m_fndecl, m_var_decl);
805 else
806 warned = ctxt.warn ("%qE on a pointer to an on-stack buffer",
807 m_fndecl);
808 if (warned)
810 if (m_var_decl)
811 inform (DECL_SOURCE_LOCATION (m_var_decl),
812 "%qE declared on stack here", m_var_decl);
813 inform (ctxt.get_location (), "perhaps use %qs rather than %qE",
814 "setenv", m_fndecl);
817 return warned;
820 label_text describe_final_event (const evdesc::final_event &ev) final override
822 if (m_var_decl)
823 return ev.formatted_print ("%qE on a pointer to automatic variable %qE",
824 m_fndecl, m_var_decl);
825 else
826 return ev.formatted_print ("%qE on a pointer to an on-stack buffer",
827 m_fndecl);
830 void mark_interesting_stuff (interesting_t *interest) final override
832 if (!m_var_decl)
833 interest->add_region_creation (m_reg->get_base_region ());
836 private:
837 tree m_fndecl; // non-NULL
838 const region *m_reg; // non-NULL
839 tree m_var_decl; // could be NULL
842 /* Handler for calls to "putenv".
844 In theory we could try to model the state of the environment variables
845 for the process; for now we merely complain about putenv of regions
846 on the stack. */
848 class kf_putenv : public known_function
850 public:
851 bool matches_call_types_p (const call_details &cd) const final override
853 return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
856 void impl_call_pre (const call_details &cd) const final override
858 tree fndecl = cd.get_fndecl_for_call ();
859 gcc_assert (fndecl);
860 region_model_context *ctxt = cd.get_ctxt ();
861 region_model *model = cd.get_model ();
862 model->check_for_null_terminated_string_arg (cd, 0);
863 const svalue *ptr_sval = cd.get_arg_svalue (0);
864 const region *reg
865 = model->deref_rvalue (ptr_sval, cd.get_arg_tree (0), ctxt);
866 model->get_store ()->mark_as_escaped (reg);
867 enum memory_space mem_space = reg->get_memory_space ();
868 switch (mem_space)
870 default:
871 gcc_unreachable ();
872 case MEMSPACE_UNKNOWN:
873 case MEMSPACE_CODE:
874 case MEMSPACE_GLOBALS:
875 case MEMSPACE_HEAP:
876 case MEMSPACE_READONLY_DATA:
877 break;
878 case MEMSPACE_STACK:
879 if (ctxt)
880 ctxt->warn (make_unique<putenv_of_auto_var> (fndecl, reg));
881 break;
883 cd.set_any_lhs_with_defaults ();
887 /* Handler for "realloc":
889 void *realloc(void *ptr, size_t size);
891 realloc(3) is awkward, since it has various different outcomes
892 that are best modelled as separate exploded nodes/edges.
894 We first check for sm-state, in
895 malloc_state_machine::on_realloc_call, so that we
896 can complain about issues such as realloc of a non-heap
897 pointer, and terminate the path for such cases (and issue
898 the complaints at the call's exploded node).
900 Assuming that these checks pass, we split the path here into
901 three special cases (and terminate the "standard" path):
902 (A) failure, returning NULL
903 (B) success, growing the buffer in-place without moving it
904 (C) success, allocating a new buffer, copying the content
905 of the old buffer to it, and freeing the old buffer.
907 Each of these has a custom_edge_info subclass, which updates
908 the region_model and sm-state of the destination state. */
910 class kf_realloc : public builtin_known_function
912 public:
913 bool matches_call_types_p (const call_details &cd) const final override
915 return (cd.num_args () == 2
916 && cd.arg_is_pointer_p (0)
917 && cd.arg_is_size_p (1));
920 enum built_in_function builtin_code () const final override
922 return BUILT_IN_REALLOC;
925 void impl_call_post (const call_details &cd) const final override;
928 void
929 kf_realloc::impl_call_post (const call_details &cd) const
931 /* Three custom subclasses of custom_edge_info, for handling the various
932 outcomes of "realloc". */
934 /* Concrete custom_edge_info: a realloc call that fails, returning NULL. */
935 class failure : public failed_call_info
937 public:
938 failure (const call_details &cd)
939 : failed_call_info (cd)
943 bool update_model (region_model *model,
944 const exploded_edge *,
945 region_model_context *ctxt) const final override
947 /* Return NULL; everything else is unchanged. */
948 const call_details cd (get_call_details (model, ctxt));
949 region_model_manager *mgr = cd.get_manager ();
950 if (cd.get_lhs_type ())
952 const svalue *zero
953 = mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
954 model->set_value (cd.get_lhs_region (),
955 zero,
956 cd.get_ctxt ());
958 return true;
962 /* Concrete custom_edge_info: a realloc call that succeeds, growing
963 the existing buffer without moving it. */
964 class success_no_move : public call_info
966 public:
967 success_no_move (const call_details &cd)
968 : call_info (cd)
972 label_text get_desc (bool can_colorize) const final override
974 return make_label_text (can_colorize,
975 "when %qE succeeds, without moving buffer",
976 get_fndecl ());
979 bool update_model (region_model *model,
980 const exploded_edge *,
981 region_model_context *ctxt) const final override
983 /* Update size of buffer and return the ptr unchanged. */
984 const call_details cd (get_call_details (model, ctxt));
985 region_model_manager *mgr = cd.get_manager ();
986 const svalue *ptr_sval = cd.get_arg_svalue (0);
987 const svalue *size_sval = cd.get_arg_svalue (1);
989 /* We can only grow in place with a non-NULL pointer. */
991 const svalue *null_ptr
992 = mgr->get_or_create_int_cst (ptr_sval->get_type (), 0);
993 if (!model->add_constraint (ptr_sval, NE_EXPR, null_ptr,
994 cd.get_ctxt ()))
995 return false;
998 if (const region *buffer_reg = model->deref_rvalue (ptr_sval, NULL_TREE,
999 ctxt))
1000 if (compat_types_p (size_sval->get_type (), size_type_node))
1001 model->set_dynamic_extents (buffer_reg, size_sval, ctxt);
1002 if (cd.get_lhs_region ())
1004 model->set_value (cd.get_lhs_region (), ptr_sval, cd.get_ctxt ());
1005 const svalue *zero
1006 = mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
1007 return model->add_constraint (ptr_sval, NE_EXPR, zero, ctxt);
1009 else
1010 return true;
1014 /* Concrete custom_edge_info: a realloc call that succeeds, freeing
1015 the existing buffer and moving the content to a freshly allocated
1016 buffer. */
1017 class success_with_move : public call_info
1019 public:
1020 success_with_move (const call_details &cd)
1021 : call_info (cd)
1025 label_text get_desc (bool can_colorize) const final override
1027 return make_label_text (can_colorize,
1028 "when %qE succeeds, moving buffer",
1029 get_fndecl ());
1031 bool update_model (region_model *model,
1032 const exploded_edge *,
1033 region_model_context *ctxt) const final override
1035 const call_details cd (get_call_details (model, ctxt));
1036 region_model_manager *mgr = cd.get_manager ();
1037 const svalue *old_ptr_sval = cd.get_arg_svalue (0);
1038 const svalue *new_size_sval = cd.get_arg_svalue (1);
1040 /* Create the new region. */
1041 const region *new_reg
1042 = model->get_or_create_region_for_heap_alloc (new_size_sval, ctxt);
1043 const svalue *new_ptr_sval
1044 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
1045 if (!model->add_constraint (new_ptr_sval, NE_EXPR, old_ptr_sval,
1046 cd.get_ctxt ()))
1047 return false;
1049 if (cd.get_lhs_type ())
1050 cd.maybe_set_lhs (new_ptr_sval);
1052 if (const region *freed_reg = model->deref_rvalue (old_ptr_sval,
1053 NULL_TREE, ctxt))
1055 /* Copy the data. */
1056 const svalue *old_size_sval = model->get_dynamic_extents (freed_reg);
1057 if (old_size_sval)
1059 const svalue *copied_size_sval
1060 = get_copied_size (model, old_size_sval, new_size_sval);
1061 const region *copied_old_reg
1062 = mgr->get_sized_region (freed_reg, NULL, copied_size_sval);
1063 const svalue *buffer_content_sval
1064 = model->get_store_value (copied_old_reg, cd.get_ctxt ());
1065 const region *copied_new_reg
1066 = mgr->get_sized_region (new_reg, NULL, copied_size_sval);
1067 model->set_value (copied_new_reg, buffer_content_sval,
1068 cd.get_ctxt ());
1070 else
1072 /* We don't know how big the old region was;
1073 mark the new region as having been touched to avoid uninit
1074 issues. */
1075 model->mark_region_as_unknown (new_reg, cd.get_uncertainty ());
1078 /* Free the old region, so that pointers to the old buffer become
1079 invalid. */
1081 /* If the ptr points to an underlying heap region, delete it,
1082 poisoning pointers. */
1083 model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
1084 model->unset_dynamic_extents (freed_reg);
1087 /* Update the sm-state: mark the old_ptr_sval as "freed",
1088 and the new_ptr_sval as "nonnull". */
1089 model->on_realloc_with_move (cd, old_ptr_sval, new_ptr_sval);
1091 if (cd.get_lhs_type ())
1093 const svalue *zero
1094 = mgr->get_or_create_int_cst (cd.get_lhs_type (), 0);
1095 return model->add_constraint (new_ptr_sval, NE_EXPR, zero,
1096 cd.get_ctxt ());
1098 else
1099 return true;
1102 private:
1103 /* Return the lesser of OLD_SIZE_SVAL and NEW_SIZE_SVAL.
1104 If unknown, OLD_SIZE_SVAL is returned. */
1105 const svalue *get_copied_size (region_model *model,
1106 const svalue *old_size_sval,
1107 const svalue *new_size_sval) const
1109 tristate res
1110 = model->eval_condition (old_size_sval, GT_EXPR, new_size_sval);
1111 switch (res.get_value ())
1113 case tristate::TS_TRUE:
1114 return new_size_sval;
1115 case tristate::TS_FALSE:
1116 case tristate::TS_UNKNOWN:
1117 return old_size_sval;
1118 default:
1119 gcc_unreachable ();
1124 /* Body of kf_realloc::impl_call_post. */
1126 if (cd.get_ctxt ())
1128 cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
1129 cd.get_ctxt ()->bifurcate (make_unique<success_no_move> (cd));
1130 cd.get_ctxt ()->bifurcate (make_unique<success_with_move> (cd));
1131 cd.get_ctxt ()->terminate_path ();
1135 /* Handler for "strchr" and "__builtin_strchr". */
1137 class kf_strchr : public builtin_known_function
1139 public:
1140 bool matches_call_types_p (const call_details &cd) const final override
1142 return (cd.num_args () == 2 && cd.arg_is_pointer_p (0));
1144 void impl_call_pre (const call_details &cd) const final override
1146 cd.check_for_null_terminated_string_arg (0);
1149 enum built_in_function builtin_code () const final override
1151 return BUILT_IN_STRCHR;
1153 void impl_call_post (const call_details &cd) const final override;
1156 void
1157 kf_strchr::impl_call_post (const call_details &cd) const
1159 class strchr_call_info : public call_info
1161 public:
1162 strchr_call_info (const call_details &cd, bool found)
1163 : call_info (cd), m_found (found)
1167 label_text get_desc (bool can_colorize) const final override
1169 if (m_found)
1170 return make_label_text (can_colorize,
1171 "when %qE returns non-NULL",
1172 get_fndecl ());
1173 else
1174 return make_label_text (can_colorize,
1175 "when %qE returns NULL",
1176 get_fndecl ());
1179 bool update_model (region_model *model,
1180 const exploded_edge *,
1181 region_model_context *ctxt) const final override
1183 const call_details cd (get_call_details (model, ctxt));
1184 if (tree lhs_type = cd.get_lhs_type ())
1186 region_model_manager *mgr = model->get_manager ();
1187 const svalue *result;
1188 if (m_found)
1190 const svalue *str_sval = cd.get_arg_svalue (0);
1191 const region *str_reg
1192 = model->deref_rvalue (str_sval, cd.get_arg_tree (0),
1193 cd.get_ctxt ());
1194 /* We want str_sval + OFFSET for some unknown OFFSET.
1195 Use a conjured_svalue to represent the offset,
1196 using the str_reg as the id of the conjured_svalue. */
1197 const svalue *offset
1198 = mgr->get_or_create_conjured_svalue (size_type_node,
1199 cd.get_call_stmt (),
1200 str_reg,
1201 conjured_purge (model,
1202 ctxt));
1203 result = mgr->get_or_create_binop (lhs_type, POINTER_PLUS_EXPR,
1204 str_sval, offset);
1206 else
1207 result = mgr->get_or_create_int_cst (lhs_type, 0);
1208 cd.maybe_set_lhs (result);
1210 return true;
1212 private:
1213 bool m_found;
1216 /* Body of kf_strchr::impl_call_post. */
1217 if (cd.get_ctxt ())
1219 cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, false));
1220 cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, true));
1221 cd.get_ctxt ()->terminate_path ();
1225 /* Handler for "sprintf".
1226 int sprintf(char *str, const char *format, ...);
1229 class kf_sprintf : public builtin_known_function
1231 public:
1232 bool matches_call_types_p (const call_details &cd) const final override
1234 return (cd.num_args () >= 2
1235 && cd.arg_is_pointer_p (0)
1236 && cd.arg_is_pointer_p (1));
1239 enum built_in_function builtin_code () const final override
1241 return BUILT_IN_SPRINTF;
1244 void impl_call_pre (const call_details &cd) const final override
1246 /* For now, merely assume that the destination buffer gets set to a
1247 new svalue. */
1248 region_model *model = cd.get_model ();
1249 region_model_context *ctxt = cd.get_ctxt ();
1250 const svalue *dst_ptr = cd.get_arg_svalue (0);
1251 const region *dst_reg
1252 = model->deref_rvalue (dst_ptr, cd.get_arg_tree (0), ctxt);
1253 const svalue *content = cd.get_or_create_conjured_svalue (dst_reg);
1254 model->set_value (dst_reg, content, ctxt);
1255 cd.set_any_lhs_with_defaults ();
1259 /* Handler for "__builtin_stack_restore". */
1261 class kf_stack_restore : public pure_known_function_with_default_return
1263 public:
1264 bool matches_call_types_p (const call_details &) const final override
1266 return true;
1269 /* Currently a no-op. */
1272 /* Handler for "__builtin_stack_save". */
1274 class kf_stack_save : public pure_known_function_with_default_return
1276 public:
1277 bool matches_call_types_p (const call_details &) const final override
1279 return true;
1282 /* Currently a no-op. */
1285 /* Handler for "strcat" and "__builtin_strcat_chk". */
1287 class kf_strcat : public builtin_known_function
1289 public:
1290 kf_strcat (unsigned int num_args, bool chk_variant)
1291 : m_num_args (num_args),
1292 m_chk_variant (chk_variant) {}
1293 bool matches_call_types_p (const call_details &cd) const final override
1295 return (cd.num_args () == m_num_args
1296 && cd.arg_is_pointer_p (0)
1297 && cd.arg_is_pointer_p (1));
1300 enum built_in_function builtin_code () const final override
1302 return m_chk_variant ? BUILT_IN_STRCAT_CHK : BUILT_IN_STRCAT;
1305 void impl_call_pre (const call_details &cd) const final override
1307 region_model *model = cd.get_model ();
1308 region_model_manager *mgr = cd.get_manager ();
1310 const svalue *dest_sval = cd.get_arg_svalue (0);
1311 const region *dest_reg = model->deref_rvalue (dest_sval, cd.get_arg_tree (0),
1312 cd.get_ctxt ());
1314 const svalue *dst_strlen_sval
1315 = cd.check_for_null_terminated_string_arg (0, false, nullptr);
1316 if (!dst_strlen_sval)
1318 if (cd.get_ctxt ())
1319 cd.get_ctxt ()->terminate_path ();
1320 return;
1323 const svalue *bytes_to_copy;
1324 const svalue *num_src_bytes_read_sval
1325 = cd.check_for_null_terminated_string_arg (1, true, &bytes_to_copy);
1326 if (!num_src_bytes_read_sval)
1328 if (cd.get_ctxt ())
1329 cd.get_ctxt ()->terminate_path ();
1330 return;
1333 cd.maybe_set_lhs (dest_sval);
1334 cd.complain_about_overlap (0, 1, num_src_bytes_read_sval);
1336 const region *offset_reg
1337 = mgr->get_offset_region (dest_reg, NULL_TREE, dst_strlen_sval);
1338 model->write_bytes (offset_reg,
1339 num_src_bytes_read_sval,
1340 bytes_to_copy,
1341 cd.get_ctxt ());
1344 private:
1345 unsigned int m_num_args;
1346 const bool m_chk_variant;
1349 /* Handler for "strcpy" and "__builtin_strcpy_chk". */
1351 class kf_strcpy : public builtin_known_function
1353 public:
1354 kf_strcpy (unsigned int num_args, bool chk_variant)
1355 : m_num_args (num_args),
1356 m_chk_variant (chk_variant) {}
1357 bool matches_call_types_p (const call_details &cd) const final override
1359 return (cd.num_args () == m_num_args
1360 && cd.arg_is_pointer_p (0)
1361 && cd.arg_is_pointer_p (1));
1363 enum built_in_function builtin_code () const final override
1365 return m_chk_variant ? BUILT_IN_STRCPY_CHK : BUILT_IN_STRCPY;
1367 void impl_call_pre (const call_details &cd) const final override;
1369 private:
1370 unsigned int m_num_args;
1371 const bool m_chk_variant;
1374 void
1375 kf_strcpy::impl_call_pre (const call_details &cd) const
1377 region_model *model = cd.get_model ();
1378 region_model_context *ctxt = cd.get_ctxt ();
1380 const svalue *dest_sval = cd.get_arg_svalue (0);
1381 const region *dest_reg = model->deref_rvalue (dest_sval, cd.get_arg_tree (0),
1382 ctxt);
1383 /* strcpy returns the initial param. */
1384 cd.maybe_set_lhs (dest_sval);
1386 const svalue *bytes_to_copy;
1387 if (const svalue *num_bytes_read_sval
1388 = cd.check_for_null_terminated_string_arg (1, true, &bytes_to_copy))
1390 cd.complain_about_overlap (0, 1, num_bytes_read_sval);
1391 model->write_bytes (dest_reg, num_bytes_read_sval, bytes_to_copy, ctxt);
1393 else
1395 if (cd.get_ctxt ())
1396 cd.get_ctxt ()->terminate_path ();
1400 /* Handler for "strdup" and "__builtin_strdup". */
1402 class kf_strdup : public builtin_known_function
1404 public:
1405 bool matches_call_types_p (const call_details &cd) const final override
1407 return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
1409 enum built_in_function builtin_code () const final override
1411 return BUILT_IN_STRDUP;
1413 void impl_call_pre (const call_details &cd) const final override
1415 region_model *model = cd.get_model ();
1416 region_model_context *ctxt = cd.get_ctxt ();
1417 region_model_manager *mgr = cd.get_manager ();
1418 const svalue *bytes_to_copy;
1419 if (const svalue *num_bytes_read_sval
1420 = cd.check_for_null_terminated_string_arg (0, true, &bytes_to_copy))
1422 const region *new_reg
1423 = model->get_or_create_region_for_heap_alloc (num_bytes_read_sval,
1424 ctxt);
1425 model->write_bytes (new_reg, num_bytes_read_sval, bytes_to_copy, ctxt);
1426 if (cd.get_lhs_type ())
1428 const svalue *ptr_sval
1429 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
1430 cd.maybe_set_lhs (ptr_sval);
1433 else
1435 if (ctxt)
1436 ctxt->terminate_path ();
1441 /* Handler for "strlen" and for "__analyzer_get_strlen". */
1443 class kf_strlen : public builtin_known_function
1445 public:
1446 bool matches_call_types_p (const call_details &cd) const final override
1448 return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
1450 enum built_in_function builtin_code () const final override
1452 return BUILT_IN_STRLEN;
1455 void impl_call_pre (const call_details &cd) const final override
1457 if (const svalue *strlen_sval
1458 = cd.check_for_null_terminated_string_arg (0, false, nullptr))
1459 if (strlen_sval->get_kind () != SK_UNKNOWN)
1461 cd.maybe_set_lhs (strlen_sval);
1462 return;
1465 /* Use a conjured svalue. */
1466 cd.set_any_lhs_with_defaults ();
1470 /* Factory function, so that kf-analyzer.cc can use this class. */
1472 std::unique_ptr<known_function>
1473 make_kf_strlen ()
1475 return make_unique<kf_strlen> ();
1478 /* Handler for "strncpy" and "__builtin_strncpy".
1479 See e.g. https://en.cppreference.com/w/c/string/byte/strncpy
1481 extern char *strncpy (char *dst, const char *src, size_t count);
1483 Handle this by splitting into two outcomes:
1484 (a) truncated read from "src" of "count" bytes,
1485 writing "count" bytes to "dst"
1486 (b) read from "src" of up to (and including) the null terminator,
1487 where the number of bytes read < "count" bytes,
1488 writing those bytes to "dst", and zero-filling the rest,
1489 up to "count". */
1491 class kf_strncpy : public builtin_known_function
1493 public:
1494 bool matches_call_types_p (const call_details &cd) const final override
1496 return (cd.num_args () == 3
1497 && cd.arg_is_pointer_p (0)
1498 && cd.arg_is_pointer_p (1)
1499 && cd.arg_is_integral_p (2));
1501 enum built_in_function builtin_code () const final override
1503 return BUILT_IN_STRNCPY;
1505 void impl_call_post (const call_details &cd) const final override;
1508 void
1509 kf_strncpy::impl_call_post (const call_details &cd) const
1511 class strncpy_call_info : public call_info
1513 public:
1514 strncpy_call_info (const call_details &cd,
1515 const svalue *num_bytes_with_terminator_sval,
1516 bool truncated_read)
1517 : call_info (cd),
1518 m_num_bytes_with_terminator_sval (num_bytes_with_terminator_sval),
1519 m_truncated_read (truncated_read)
1523 label_text get_desc (bool can_colorize) const final override
1525 if (m_truncated_read)
1526 return make_label_text (can_colorize,
1527 "when %qE truncates the source string",
1528 get_fndecl ());
1529 else
1530 return make_label_text (can_colorize,
1531 "when %qE copies the full source string",
1532 get_fndecl ());
1535 bool update_model (region_model *model,
1536 const exploded_edge *,
1537 region_model_context *ctxt) const final override
1539 const call_details cd (get_call_details (model, ctxt));
1541 const svalue *dest_sval = cd.get_arg_svalue (0);
1542 const region *dest_reg
1543 = model->deref_rvalue (dest_sval, cd.get_arg_tree (0), ctxt);
1545 const svalue *src_sval = cd.get_arg_svalue (1);
1546 const region *src_reg
1547 = model->deref_rvalue (src_sval, cd.get_arg_tree (1), ctxt);
1549 const svalue *count_sval = cd.get_arg_svalue (2);
1551 /* strncpy returns the initial param. */
1552 cd.maybe_set_lhs (dest_sval);
1554 const svalue *num_bytes_read_sval;
1555 if (m_truncated_read)
1557 /* Truncated read. */
1558 num_bytes_read_sval = count_sval;
1560 if (m_num_bytes_with_terminator_sval)
1562 /* The terminator is after the limit. */
1563 if (!model->add_constraint (m_num_bytes_with_terminator_sval,
1564 GT_EXPR,
1565 count_sval,
1566 ctxt))
1567 return false;
1569 else
1571 /* We don't know where the terminator is, or if there is one.
1572 In theory we know that the first COUNT bytes are non-zero,
1573 but we don't have a way to record that constraint. */
1576 else
1578 /* Full read of the src string before reaching the limit,
1579 so there must be a terminator and it must be at or before
1580 the limit. */
1581 if (m_num_bytes_with_terminator_sval)
1583 if (!model->add_constraint (m_num_bytes_with_terminator_sval,
1584 LE_EXPR,
1585 count_sval,
1586 ctxt))
1587 return false;
1588 num_bytes_read_sval = m_num_bytes_with_terminator_sval;
1590 /* First, zero-fill the dest buffer.
1591 We don't need to do this for the truncation case, as
1592 this fully populates the dest buffer. */
1593 const region *sized_dest_reg
1594 = model->get_manager ()->get_sized_region (dest_reg,
1595 NULL_TREE,
1596 count_sval);
1597 model->zero_fill_region (sized_dest_reg, ctxt);
1599 else
1601 /* Don't analyze this case; the other case will
1602 assume a "truncated" read up to the limit. */
1603 return false;
1607 gcc_assert (num_bytes_read_sval);
1609 const svalue *bytes_to_copy
1610 = model->read_bytes (src_reg,
1611 cd.get_arg_tree (1),
1612 num_bytes_read_sval,
1613 ctxt);
1614 cd.complain_about_overlap (0, 1, num_bytes_read_sval);
1615 model->write_bytes (dest_reg,
1616 num_bytes_read_sval,
1617 bytes_to_copy,
1618 ctxt);
1620 return true;
1622 private:
1623 /* (strlen + 1) of the source string if it has a terminator,
1624 or NULL for the case where UB would happen before
1625 finding any terminator. */
1626 const svalue *m_num_bytes_with_terminator_sval;
1628 /* true: if this is the outcome where the limit was reached before
1629 the null terminator
1630 false: if the null terminator was reached before the limit. */
1631 bool m_truncated_read;
1634 /* Body of kf_strncpy::impl_call_post. */
1635 if (cd.get_ctxt ())
1637 /* First, scan for a null terminator as if there were no limit,
1638 with a null ctxt so no errors are reported. */
1639 const region_model *model = cd.get_model ();
1640 const svalue *ptr_arg_sval = cd.get_arg_svalue (1);
1641 const region *buf_reg
1642 = model->deref_rvalue (ptr_arg_sval, cd.get_arg_tree (1), nullptr);
1643 const svalue *num_bytes_with_terminator_sval
1644 = model->scan_for_null_terminator (buf_reg,
1645 cd.get_arg_tree (1),
1646 nullptr,
1647 nullptr);
1648 cd.get_ctxt ()->bifurcate
1649 (make_unique<strncpy_call_info> (cd, num_bytes_with_terminator_sval,
1650 false));
1651 cd.get_ctxt ()->bifurcate
1652 (make_unique<strncpy_call_info> (cd, num_bytes_with_terminator_sval,
1653 true));
1654 cd.get_ctxt ()->terminate_path ();
1658 /* Handler for "strndup" and "__builtin_strndup". */
1660 class kf_strndup : public builtin_known_function
1662 public:
1663 bool matches_call_types_p (const call_details &cd) const final override
1665 return (cd.num_args () == 2 && cd.arg_is_pointer_p (0));
1667 enum built_in_function builtin_code () const final override
1669 return BUILT_IN_STRNDUP;
1671 void impl_call_pre (const call_details &cd) const final override
1673 region_model *model = cd.get_model ();
1674 region_model_manager *mgr = cd.get_manager ();
1675 /* Ideally we'd get the size here, and simulate copying the bytes. */
1676 const region *new_reg
1677 = model->get_or_create_region_for_heap_alloc (NULL, cd.get_ctxt ());
1678 model->mark_region_as_unknown (new_reg, NULL);
1679 if (cd.get_lhs_type ())
1681 const svalue *ptr_sval
1682 = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
1683 cd.maybe_set_lhs (ptr_sval);
1688 /* Handler for "strstr" and "__builtin_strstr".
1689 extern char *strstr (const char* str, const char* substr);
1690 See e.g. https://en.cppreference.com/w/c/string/byte/strstr */
1692 class kf_strstr : public builtin_known_function
1694 public:
1695 bool matches_call_types_p (const call_details &cd) const final override
1697 return (cd.num_args () == 2
1698 && cd.arg_is_pointer_p (0)
1699 && cd.arg_is_pointer_p (1));
1701 enum built_in_function builtin_code () const final override
1703 return BUILT_IN_STRSTR;
1705 void impl_call_pre (const call_details &cd) const final override
1707 cd.check_for_null_terminated_string_arg (0);
1708 cd.check_for_null_terminated_string_arg (1);
1710 void impl_call_post (const call_details &cd) const final override;
1713 void
1714 kf_strstr::impl_call_post (const call_details &cd) const
1716 class strstr_call_info : public call_info
1718 public:
1719 strstr_call_info (const call_details &cd, bool found)
1720 : call_info (cd), m_found (found)
1724 label_text get_desc (bool can_colorize) const final override
1726 if (m_found)
1727 return make_label_text (can_colorize,
1728 "when %qE returns non-NULL",
1729 get_fndecl ());
1730 else
1731 return make_label_text (can_colorize,
1732 "when %qE returns NULL",
1733 get_fndecl ());
1736 bool update_model (region_model *model,
1737 const exploded_edge *,
1738 region_model_context *ctxt) const final override
1740 const call_details cd (get_call_details (model, ctxt));
1741 if (tree lhs_type = cd.get_lhs_type ())
1743 region_model_manager *mgr = model->get_manager ();
1744 const svalue *result;
1745 if (m_found)
1747 const svalue *str_sval = cd.get_arg_svalue (0);
1748 const region *str_reg
1749 = model->deref_rvalue (str_sval, cd.get_arg_tree (0),
1750 cd.get_ctxt ());
1751 /* We want str_sval + OFFSET for some unknown OFFSET.
1752 Use a conjured_svalue to represent the offset,
1753 using the str_reg as the id of the conjured_svalue. */
1754 const svalue *offset
1755 = mgr->get_or_create_conjured_svalue (size_type_node,
1756 cd.get_call_stmt (),
1757 str_reg,
1758 conjured_purge (model,
1759 ctxt));
1760 result = mgr->get_or_create_binop (lhs_type, POINTER_PLUS_EXPR,
1761 str_sval, offset);
1763 else
1764 result = mgr->get_or_create_int_cst (lhs_type, 0);
1765 cd.maybe_set_lhs (result);
1767 return true;
1769 private:
1770 bool m_found;
1773 /* Body of kf_strstr::impl_call_post. */
1774 if (cd.get_ctxt ())
1776 cd.get_ctxt ()->bifurcate (make_unique<strstr_call_info> (cd, false));
1777 cd.get_ctxt ()->bifurcate (make_unique<strstr_call_info> (cd, true));
1778 cd.get_ctxt ()->terminate_path ();
1782 /* Handle calls to "strtok".
1783 See e.g.
1784 https://en.cppreference.com/w/c/string/byte/strtok
1785 https://man7.org/linux/man-pages/man3/strtok.3.html */
1787 class kf_strtok : public known_function
1789 public:
1790 class undefined_behavior : public undefined_function_behavior
1792 public:
1793 undefined_behavior (const call_details &cd)
1794 : undefined_function_behavior (cd)
1797 int get_controlling_option () const final override
1799 return OPT_Wanalyzer_undefined_behavior_strtok;
1802 bool emit (diagnostic_emission_context &ctxt) final override
1804 /* CWE-476: NULL Pointer Dereference. */
1805 ctxt.add_cwe (476);
1806 if (ctxt.warn ("calling %qD for first time with NULL as argument 1"
1807 " has undefined behavior",
1808 get_callee_fndecl ()))
1810 inform (ctxt.get_location (),
1811 "some implementations of %qD may crash on such input",
1812 get_callee_fndecl ());
1813 return true;
1815 return false;
1818 label_text describe_final_event (const evdesc::final_event &ev)
1819 final override
1821 return ev.formatted_print
1822 ("calling %qD for first time with NULL as argument 1"
1823 " has undefined behavior",
1824 get_callee_fndecl ());
1828 /* An outcome of a "strtok" call.
1829 We have a four-way bifurcation of the analysis via the
1830 4 combinations of two flags:
1831 - m_nonnull_str covers whether the "str" param was null or non-null
1832 - m_found covers whether the result is null or non-null
1834 class strtok_call_info : public call_info
1836 public:
1837 strtok_call_info (const call_details &cd,
1838 const private_region &private_reg,
1839 bool nonnull_str,
1840 bool found)
1841 : call_info (cd),
1842 m_private_reg (private_reg),
1843 m_nonnull_str (nonnull_str),
1844 m_found (found)
1848 label_text get_desc (bool can_colorize) const final override
1850 if (m_nonnull_str)
1852 if (m_found)
1853 return make_label_text
1854 (can_colorize,
1855 "when %qE on non-NULL string returns non-NULL",
1856 get_fndecl ());
1857 else
1858 return make_label_text
1859 (can_colorize,
1860 "when %qE on non-NULL string returns NULL",
1861 get_fndecl ());
1863 else
1865 if (m_found)
1866 return make_label_text
1867 (can_colorize,
1868 "when %qE with NULL string (using prior) returns non-NULL",
1869 get_fndecl ());
1870 else
1871 return make_label_text
1872 (can_colorize,
1873 "when %qE with NULL string (using prior) returns NULL",
1874 get_fndecl ());
1878 bool update_model (region_model *model,
1879 const exploded_edge *,
1880 region_model_context *ctxt) const final override
1882 region_model_manager *mgr = model->get_manager ();
1883 const call_details cd (get_call_details (model, ctxt));
1884 const svalue *str_sval = cd.get_arg_svalue (0);
1885 /* const svalue *delim_sval = cd.get_arg_svalue (1); */
1887 cd.check_for_null_terminated_string_arg (1);
1888 /* We check that either arg 0 or the private region is null
1889 terminated below. */
1891 const svalue *null_ptr_sval
1892 = mgr->get_or_create_null_ptr (cd.get_arg_type (0));;
1893 if (!model->add_constraint (str_sval,
1894 m_nonnull_str ? NE_EXPR : EQ_EXPR,
1895 null_ptr_sval,
1896 cd.get_ctxt ()))
1897 return false;
1899 if (m_nonnull_str)
1901 /* Update internal buffer. */
1902 model->set_value (&m_private_reg,
1903 mgr->get_or_create_unmergeable (str_sval),
1904 ctxt);
1906 else
1908 /* Read from internal buffer. */
1909 str_sval = model->get_store_value (&m_private_reg, ctxt);
1911 /* The initial value of the private region is NULL when we're
1912 on a path from main. */
1913 if (const initial_svalue *initial_sval
1914 = str_sval->dyn_cast_initial_svalue ())
1915 if (initial_sval->get_region () == &m_private_reg
1916 && model->called_from_main_p ())
1918 /* Implementations of strtok do not necessarily check for NULL
1919 here, and may crash; see PR analyzer/107573.
1920 Warn for this, if we were definitely passed NULL. */
1921 if (cd.get_arg_svalue (0)->all_zeroes_p ())
1923 if (ctxt)
1924 ctxt->warn (::make_unique<undefined_behavior> (cd));
1927 /* Assume that "str" was actually non-null; terminate
1928 this path. */
1929 return false;
1932 /* Now assume str_sval is non-null. */
1933 if (!model->add_constraint (str_sval,
1934 NE_EXPR,
1935 null_ptr_sval,
1936 cd.get_ctxt ()))
1937 return false;
1940 const region *buf_reg = model->deref_rvalue (str_sval, NULL_TREE, ctxt);
1941 model->scan_for_null_terminator (buf_reg,
1942 NULL_TREE,
1943 nullptr,
1944 ctxt);
1946 if (m_found)
1948 const region *str_reg
1949 = model->deref_rvalue (str_sval, cd.get_arg_tree (0),
1950 cd.get_ctxt ());
1951 /* We want to figure out the start and nul terminator
1952 for the token.
1953 For each, we want str_sval + OFFSET for some unknown OFFSET.
1954 Use a conjured_svalue to represent the offset,
1955 using the str_reg as the id of the conjured_svalue. */
1956 const svalue *start_offset
1957 = mgr->get_or_create_conjured_svalue (size_type_node,
1958 cd.get_call_stmt (),
1959 str_reg,
1960 conjured_purge (model,
1961 ctxt),
1963 const svalue *nul_offset
1964 = mgr->get_or_create_conjured_svalue (size_type_node,
1965 cd.get_call_stmt (),
1966 str_reg,
1967 conjured_purge (model,
1968 ctxt),
1971 tree char_ptr_type = build_pointer_type (char_type_node);
1972 const svalue *result
1973 = mgr->get_or_create_binop (char_ptr_type, POINTER_PLUS_EXPR,
1974 str_sval, start_offset);
1975 cd.maybe_set_lhs (result);
1977 /* nul_offset + 1; the offset to use for the next call. */
1978 const svalue *next_offset
1979 = mgr->get_or_create_binop (size_type_node, PLUS_EXPR,
1980 nul_offset,
1981 mgr->get_or_create_int_cst
1982 (char_type_node, 1));
1984 /* Write '\0' to str_sval[nul_offset]. */
1985 const svalue *ptr_to_term
1986 = mgr->get_or_create_binop (char_ptr_type, POINTER_PLUS_EXPR,
1987 str_sval, nul_offset);
1988 const region *terminator_reg
1989 = model->deref_rvalue (ptr_to_term, NULL_TREE, cd.get_ctxt ());
1990 model->set_value (terminator_reg,
1991 mgr->get_or_create_unmergeable
1992 (mgr->get_or_create_int_cst (char_type_node,
1993 0)),
1994 cd.get_ctxt ());
1996 /* Update saved ptr to be at [nul_offset + 1]. */
1997 const svalue *ptr_to_next
1998 = mgr->get_or_create_binop (cd.get_lhs_type (), POINTER_PLUS_EXPR,
1999 str_sval, next_offset);
2000 model->set_value (&m_private_reg, ptr_to_next, ctxt);
2002 else
2003 if (tree lhs_type = cd.get_lhs_type ())
2005 const svalue *result
2006 = mgr->get_or_create_int_cst (lhs_type, 0);
2007 cd.maybe_set_lhs (result);
2009 return true;
2011 private:
2012 const private_region &m_private_reg;
2013 bool m_nonnull_str;
2014 bool m_found;
2015 }; // class strtok_call_info
2017 kf_strtok (region_model_manager &mgr)
2018 : m_private_reg (mgr.alloc_symbol_id (),
2019 mgr.get_root_region (),
2020 get_region_type (),
2021 "strtok buffer")
2025 bool matches_call_types_p (const call_details &cd) const final override
2027 return (cd.num_args () == 2
2028 && POINTER_TYPE_P (cd.get_arg_type (0))
2029 && POINTER_TYPE_P (cd.get_arg_type (1)));
2032 void impl_call_post (const call_details &cd) const final override
2034 if (cd.get_ctxt ())
2036 /* Four-way bifurcation, based on whether:
2037 - the str is non-null
2038 - the result is non-null
2039 Typically the str is either null or non-null at a particular site,
2040 so hopefully this will generally just lead to two out-edges. */
2041 cd.get_ctxt ()->bifurcate
2042 (make_unique<strtok_call_info> (cd, m_private_reg, false, false));
2043 cd.get_ctxt ()->bifurcate
2044 (make_unique<strtok_call_info> (cd, m_private_reg, false, true));
2045 cd.get_ctxt ()->bifurcate
2046 (make_unique<strtok_call_info> (cd, m_private_reg, true, false));
2047 cd.get_ctxt ()->bifurcate
2048 (make_unique<strtok_call_info> (cd, m_private_reg, true, true));
2049 cd.get_ctxt ()->terminate_path ();
2053 private:
2054 static tree get_region_type ()
2056 return build_pointer_type (char_type_node);
2058 const private_region m_private_reg;
2061 class kf_ubsan_bounds : public internal_known_function
2063 /* Empty. */
2066 /* Handle calls to functions referenced by
2067 __attribute__((malloc(FOO))). */
2069 void
2070 region_model::impl_deallocation_call (const call_details &cd)
2072 kf_free kf;
2073 kf.impl_call_post (cd);
2076 static void
2077 register_atomic_builtins (known_function_manager &kfm)
2079 kfm.add (BUILT_IN_ATOMIC_EXCHANGE, make_unique<kf_atomic_exchange> ());
2080 kfm.add (BUILT_IN_ATOMIC_EXCHANGE_N, make_unique<kf_atomic_exchange_n> ());
2081 kfm.add (BUILT_IN_ATOMIC_EXCHANGE_1, make_unique<kf_atomic_exchange_n> ());
2082 kfm.add (BUILT_IN_ATOMIC_EXCHANGE_2, make_unique<kf_atomic_exchange_n> ());
2083 kfm.add (BUILT_IN_ATOMIC_EXCHANGE_4, make_unique<kf_atomic_exchange_n> ());
2084 kfm.add (BUILT_IN_ATOMIC_EXCHANGE_8, make_unique<kf_atomic_exchange_n> ());
2085 kfm.add (BUILT_IN_ATOMIC_EXCHANGE_16, make_unique<kf_atomic_exchange_n> ());
2086 kfm.add (BUILT_IN_ATOMIC_LOAD, make_unique<kf_atomic_load> ());
2087 kfm.add (BUILT_IN_ATOMIC_LOAD_N, make_unique<kf_atomic_load_n> ());
2088 kfm.add (BUILT_IN_ATOMIC_LOAD_1, make_unique<kf_atomic_load_n> ());
2089 kfm.add (BUILT_IN_ATOMIC_LOAD_2, make_unique<kf_atomic_load_n> ());
2090 kfm.add (BUILT_IN_ATOMIC_LOAD_4, make_unique<kf_atomic_load_n> ());
2091 kfm.add (BUILT_IN_ATOMIC_LOAD_8, make_unique<kf_atomic_load_n> ());
2092 kfm.add (BUILT_IN_ATOMIC_LOAD_16, make_unique<kf_atomic_load_n> ());
2093 kfm.add (BUILT_IN_ATOMIC_STORE, make_unique<kf_atomic_store> ());
2094 kfm.add (BUILT_IN_ATOMIC_STORE_N, make_unique<kf_atomic_store_n> ());
2095 kfm.add (BUILT_IN_ATOMIC_STORE_1, make_unique<kf_atomic_store_n> ());
2096 kfm.add (BUILT_IN_ATOMIC_STORE_2, make_unique<kf_atomic_store_n> ());
2097 kfm.add (BUILT_IN_ATOMIC_STORE_4, make_unique<kf_atomic_store_n> ());
2098 kfm.add (BUILT_IN_ATOMIC_STORE_8, make_unique<kf_atomic_store_n> ());
2099 kfm.add (BUILT_IN_ATOMIC_STORE_16, make_unique<kf_atomic_store_n> ());
2100 kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_1,
2101 make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
2102 kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_2,
2103 make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
2104 kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_4,
2105 make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
2106 kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_8,
2107 make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
2108 kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_16,
2109 make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
2110 kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_1,
2111 make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
2112 kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_2,
2113 make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
2114 kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_4,
2115 make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
2116 kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_8,
2117 make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
2118 kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_16,
2119 make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
2120 kfm.add (BUILT_IN_ATOMIC_AND_FETCH_1,
2121 make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
2122 kfm.add (BUILT_IN_ATOMIC_AND_FETCH_2,
2123 make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
2124 kfm.add (BUILT_IN_ATOMIC_AND_FETCH_4,
2125 make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
2126 kfm.add (BUILT_IN_ATOMIC_AND_FETCH_8,
2127 make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
2128 kfm.add (BUILT_IN_ATOMIC_AND_FETCH_16,
2129 make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
2130 kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_1,
2131 make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
2132 kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_2,
2133 make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
2134 kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_4,
2135 make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
2136 kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_8,
2137 make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
2138 kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_16,
2139 make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
2140 kfm.add (BUILT_IN_ATOMIC_OR_FETCH_1,
2141 make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
2142 kfm.add (BUILT_IN_ATOMIC_OR_FETCH_2,
2143 make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
2144 kfm.add (BUILT_IN_ATOMIC_OR_FETCH_4,
2145 make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
2146 kfm.add (BUILT_IN_ATOMIC_OR_FETCH_8,
2147 make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
2148 kfm.add (BUILT_IN_ATOMIC_OR_FETCH_16,
2149 make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
2150 kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_1,
2151 make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
2152 kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_2,
2153 make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
2154 kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_4,
2155 make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
2156 kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_8,
2157 make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
2158 kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_16,
2159 make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
2160 kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_1,
2161 make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
2162 kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_2,
2163 make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
2164 kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_4,
2165 make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
2166 kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_8,
2167 make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
2168 kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_16,
2169 make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
2170 kfm.add (BUILT_IN_ATOMIC_FETCH_AND_1,
2171 make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
2172 kfm.add (BUILT_IN_ATOMIC_FETCH_AND_2,
2173 make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
2174 kfm.add (BUILT_IN_ATOMIC_FETCH_AND_4,
2175 make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
2176 kfm.add (BUILT_IN_ATOMIC_FETCH_AND_8,
2177 make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
2178 kfm.add (BUILT_IN_ATOMIC_FETCH_AND_16,
2179 make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
2180 kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_1,
2181 make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
2182 kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_2,
2183 make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
2184 kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_4,
2185 make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
2186 kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_8,
2187 make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
2188 kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_16,
2189 make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
2190 kfm.add (BUILT_IN_ATOMIC_FETCH_OR_1,
2191 make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
2192 kfm.add (BUILT_IN_ATOMIC_FETCH_OR_2,
2193 make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
2194 kfm.add (BUILT_IN_ATOMIC_FETCH_OR_4,
2195 make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
2196 kfm.add (BUILT_IN_ATOMIC_FETCH_OR_8,
2197 make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
2198 kfm.add (BUILT_IN_ATOMIC_FETCH_OR_16,
2199 make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
2202 /* Handle calls to the various __builtin___ubsan_handle_*.
2203 These can return, but continuing after such a return
2204 isn't likely to be interesting to the user of the analyzer.
2205 Hence we terminate the analysis path at one of these calls. */
2207 class kf_ubsan_handler : public internal_known_function
2209 void impl_call_post (const call_details &cd) const final override
2211 if (cd.get_ctxt ())
2212 cd.get_ctxt ()->terminate_path ();
2216 static void
2217 register_sanitizer_builtins (known_function_manager &kfm)
2219 kfm.add (BUILT_IN_UBSAN_HANDLE_NONNULL_ARG,
2220 make_unique<kf_ubsan_handler> ());
2223 /* Populate KFM with instances of known functions supported by the core of the
2224 analyzer (as opposed to plugins). */
2226 void
2227 register_known_functions (known_function_manager &kfm,
2228 region_model_manager &rmm)
2230 /* Debugging/test support functions, all with a "__analyzer_" prefix. */
2231 register_known_analyzer_functions (kfm);
2233 /* Internal fns the analyzer has known_functions for. */
2235 kfm.add (IFN_BUILTIN_EXPECT, make_unique<kf_expect> ());
2236 kfm.add (IFN_UBSAN_BOUNDS, make_unique<kf_ubsan_bounds> ());
2239 /* GCC built-ins that do not correspond to a function
2240 in the standard library. */
2242 kfm.add (BUILT_IN_EXPECT, make_unique<kf_expect> ());
2243 kfm.add (BUILT_IN_EXPECT_WITH_PROBABILITY, make_unique<kf_expect> ());
2244 kfm.add (BUILT_IN_ALLOCA_WITH_ALIGN, make_unique<kf_alloca> ());
2245 kfm.add (BUILT_IN_STACK_RESTORE, make_unique<kf_stack_restore> ());
2246 kfm.add (BUILT_IN_STACK_SAVE, make_unique<kf_stack_save> ());
2248 register_atomic_builtins (kfm);
2249 register_sanitizer_builtins (kfm);
2250 register_varargs_builtins (kfm);
2253 /* Known builtins and C standard library functions
2254 the analyzer has known functions for. */
2256 kfm.add ("alloca", make_unique<kf_alloca> ());
2257 kfm.add ("__builtin_alloca", make_unique<kf_alloca> ());
2258 kfm.add ("calloc", make_unique<kf_calloc> ());
2259 kfm.add ("__builtin_calloc", make_unique<kf_calloc> ());
2260 kfm.add ("free", make_unique<kf_free> ());
2261 kfm.add ("__builtin_free", make_unique<kf_free> ());
2262 kfm.add ("malloc", make_unique<kf_malloc> ());
2263 kfm.add ("__builtin_malloc", make_unique<kf_malloc> ());
2264 kfm.add ("memcpy",
2265 make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
2266 kfm.add ("__builtin_memcpy",
2267 make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
2268 kfm.add ("__memcpy_chk", make_unique<kf_memcpy_memmove>
2269 (kf_memcpy_memmove::KF_MEMCPY_CHK));
2270 kfm.add ("__builtin___memcpy_chk", make_unique<kf_memcpy_memmove>
2271 (kf_memcpy_memmove::KF_MEMCPY_CHK));
2272 kfm.add ("memmove",
2273 make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
2274 kfm.add ("__builtin_memmove",
2275 make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
2276 kfm.add ("__memmove_chk", make_unique<kf_memcpy_memmove>
2277 (kf_memcpy_memmove::KF_MEMMOVE_CHK));
2278 kfm.add ("__builtin___memmove_chk", make_unique<kf_memcpy_memmove>
2279 (kf_memcpy_memmove::KF_MEMMOVE_CHK));
2280 kfm.add ("memset", make_unique<kf_memset> (false));
2281 kfm.add ("__builtin_memset", make_unique<kf_memset> (false));
2282 kfm.add ("__memset_chk", make_unique<kf_memset> (true));
2283 kfm.add ("__builtin___memset_chk", make_unique<kf_memset> (true));
2284 kfm.add ("realloc", make_unique<kf_realloc> ());
2285 kfm.add ("__builtin_realloc", make_unique<kf_realloc> ());
2286 kfm.add ("sprintf", make_unique<kf_sprintf> ());
2287 kfm.add ("__builtin_sprintf", make_unique<kf_sprintf> ());
2288 kfm.add ("strchr", make_unique<kf_strchr> ());
2289 kfm.add ("__builtin_strchr", make_unique<kf_strchr> ());
2290 kfm.add ("strcpy", make_unique<kf_strcpy> (2, false));
2291 kfm.add ("__builtin_strcpy", make_unique<kf_strcpy> (2, false));
2292 kfm.add ("__strcpy_chk", make_unique<kf_strcpy> (3, true));
2293 kfm.add ("__builtin___strcpy_chk", make_unique<kf_strcpy> (3, true));
2294 kfm.add ("strcat", make_unique<kf_strcat> (2, false));
2295 kfm.add ("__builtin_strcat", make_unique<kf_strcat> (2, false));
2296 kfm.add ("__strcat_chk", make_unique<kf_strcat> (3, true));
2297 kfm.add ("__builtin___strcat_chk", make_unique<kf_strcat> (3, true));
2298 kfm.add ("strdup", make_unique<kf_strdup> ());
2299 kfm.add ("__builtin_strdup", make_unique<kf_strdup> ());
2300 kfm.add ("strncpy", make_unique<kf_strncpy> ());
2301 kfm.add ("__builtin_strncpy", make_unique<kf_strncpy> ());
2302 kfm.add ("strndup", make_unique<kf_strndup> ());
2303 kfm.add ("__builtin_strndup", make_unique<kf_strndup> ());
2304 kfm.add ("strlen", make_unique<kf_strlen> ());
2305 kfm.add ("__builtin_strlen", make_unique<kf_strlen> ());
2306 kfm.add ("strstr", make_unique<kf_strstr> ());
2307 kfm.add ("__builtin_strstr", make_unique<kf_strstr> ());
2309 register_atomic_builtins (kfm);
2310 register_varargs_builtins (kfm);
2313 /* Known POSIX functions, and some non-standard extensions. */
2315 kfm.add ("fopen", make_unique<kf_fopen> ());
2316 kfm.add ("putenv", make_unique<kf_putenv> ());
2317 kfm.add ("strtok", make_unique<kf_strtok> (rmm));
2319 register_known_fd_functions (kfm);
2320 register_known_file_functions (kfm);
2323 /* glibc functions. */
2325 kfm.add ("__errno_location", make_unique<kf_errno_location> ());
2326 kfm.add ("error", make_unique<kf_error> (3));
2327 kfm.add ("error_at_line", make_unique<kf_error> (5));
2328 /* Variants of "error" and "error_at_line" seen by the
2329 analyzer at -O0 (PR analyzer/115724). */
2330 kfm.add ("__error_alias", make_unique<kf_error> (3));
2331 kfm.add ("__error_at_line_alias", make_unique<kf_error> (5));
2334 /* Other implementations of C standard library. */
2336 /* According to PR 107807 comment #2, Solaris implements "errno"
2337 like this:
2338 extern int *___errno(void) __attribute__((__const__));
2339 #define errno (*(___errno()))
2340 and macOS like this:
2341 extern int * __error(void);
2342 #define errno (*__error())
2343 and similarly __errno for newlib.
2344 Add these as synonyms for "__errno_location". */
2345 kfm.add ("___errno", make_unique<kf_errno_location> ());
2346 kfm.add ("__error", make_unique<kf_errno_location> ());
2347 kfm.add ("__errno", make_unique<kf_errno_location> ());
2350 /* Language-specific support functions. */
2351 register_known_functions_lang_cp (kfm);
2353 /* Some C++ implementations use the std:: copies of these functions
2354 from <cstdlib> etc for the C spellings of these headers (e.g. <stdlib.h>),
2355 so we must match against these too. */
2357 kfm.add_std_ns ("malloc", make_unique<kf_malloc> ());
2358 kfm.add_std_ns ("free", make_unique<kf_free> ());
2359 kfm.add_std_ns ("realloc", make_unique<kf_realloc> ());
2360 kfm.add_std_ns ("calloc", make_unique<kf_calloc> ());
2361 kfm.add_std_ns
2362 ("memcpy",
2363 make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
2364 kfm.add_std_ns
2365 ("memmove",
2366 make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
2367 kfm.add_std_ns ("memset", make_unique<kf_memset> (false));
2368 kfm.add_std_ns ("strcat", make_unique<kf_strcat> (2, false));
2369 kfm.add_std_ns ("strcpy", make_unique<kf_strcpy> (2, false));
2370 kfm.add_std_ns ("strlen", make_unique<kf_strlen> ());
2371 kfm.add_std_ns ("strncpy", make_unique<kf_strncpy> ());
2372 kfm.add_std_ns ("strtok", make_unique<kf_strtok> (rmm));
2376 } // namespace ana
2378 #endif /* #if ENABLE_ANALYZER */