Daily bump.
[official-gcc.git] / gcc / analyzer / sm-malloc.cc
blobbf5e3c365b444b57eac836d4c065d2a36bd5b646
1 /* A state machine for detecting misuses of the malloc/free API.
2 Copyright (C) 2019-2021 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 #include "system.h"
23 #include "coretypes.h"
24 #include "tree.h"
25 #include "function.h"
26 #include "basic-block.h"
27 #include "gimple.h"
28 #include "options.h"
29 #include "bitmap.h"
30 #include "diagnostic-path.h"
31 #include "diagnostic-metadata.h"
32 #include "function.h"
33 #include "json.h"
34 #include "analyzer/analyzer.h"
35 #include "diagnostic-event-id.h"
36 #include "analyzer/analyzer-logging.h"
37 #include "analyzer/sm.h"
38 #include "analyzer/pending-diagnostic.h"
39 #include "tristate.h"
40 #include "selftest.h"
41 #include "analyzer/call-string.h"
42 #include "analyzer/program-point.h"
43 #include "analyzer/store.h"
44 #include "analyzer/region-model.h"
45 #include "stringpool.h"
46 #include "attribs.h"
47 #include "analyzer/function-set.h"
48 #include "analyzer/program-state.h"
50 #if ENABLE_ANALYZER
52 namespace ana {
54 namespace {
56 /* This state machine and its various support classes track allocations
57 and deallocations.
59 It has a few standard allocation/deallocation pairs (e.g. new/delete),
60 and also supports user-defined ones via
61 __attribute__ ((malloc(DEALLOCATOR))).
63 There can be more than one valid deallocator for a given allocator,
64 for example:
65 __attribute__ ((malloc (fclose)))
66 __attribute__ ((malloc (freopen, 3)))
67 FILE* fopen (const char*, const char*);
68 A deallocator_set represents a particular set of valid deallocators.
70 We track the expected deallocator_set for a value, but not the allocation
71 function - there could be more than one allocator per deallocator_set.
72 For example, there could be dozens of allocators for "free" beyond just
73 malloc e.g. calloc, xstrdup, etc. We don't want to explode the number
74 of states by tracking individual allocators in the exploded graph;
75 we merely want to track "this value expects to have 'free' called on it".
76 Perhaps we can reconstruct which allocator was used later, when emitting
77 the path, if it's necessary for precision of wording of diagnostics. */
79 class deallocator;
80 class deallocator_set;
81 class malloc_state_machine;
83 /* An enum for discriminating between different kinds of allocation_state. */
85 enum resource_state
87 /* States that are independent of allocator/deallocator. */
89 /* The start state. */
90 RS_START,
92 /* State for a pointer that's known to be NULL. */
93 RS_NULL,
95 /* State for a pointer that's known to not be on the heap (e.g. to a local
96 or global). */
97 RS_NON_HEAP,
99 /* Stop state, for pointers we don't want to track any more. */
100 RS_STOP,
102 /* States that relate to a specific deallocator_set. */
104 /* State for a pointer returned from an allocator that hasn't
105 been checked for NULL.
106 It could be a pointer to heap-allocated memory, or could be NULL. */
107 RS_UNCHECKED,
109 /* State for a pointer returned from an allocator,
110 known to be non-NULL. */
111 RS_NONNULL,
113 /* State for a pointer passed to a deallocator. */
114 RS_FREED
117 /* Custom state subclass, which can optionally refer to an a
118 deallocator_set. */
120 struct allocation_state : public state_machine::state
122 allocation_state (const char *name, unsigned id,
123 enum resource_state rs,
124 const deallocator_set *deallocators,
125 const deallocator *deallocator)
126 : state (name, id), m_rs (rs),
127 m_deallocators (deallocators),
128 m_deallocator (deallocator)
131 void dump_to_pp (pretty_printer *pp) const FINAL OVERRIDE;
133 const allocation_state *get_nonnull () const;
135 enum resource_state m_rs;
136 const deallocator_set *m_deallocators;
137 const deallocator *m_deallocator;
140 /* An enum for choosing which wording to use in various diagnostics
141 when describing deallocations. */
143 enum wording
145 WORDING_FREED,
146 WORDING_DELETED,
147 WORDING_DEALLOCATED,
148 WORDING_REALLOCATED
151 /* Base class representing a deallocation function,
152 either a built-in one we know about, or one exposed via
153 __attribute__((malloc(DEALLOCATOR))). */
155 struct deallocator
157 hashval_t hash () const;
158 void dump_to_pp (pretty_printer *pp) const;
159 static int cmp (const deallocator *a, const deallocator *b);
160 static int cmp_ptr_ptr (const void *, const void *);
162 /* Name to use in diagnostics. */
163 const char *m_name;
165 /* Which wording to use in diagnostics. */
166 enum wording m_wording;
168 /* State for a value passed to one of the deallocators. */
169 state_machine::state_t m_freed;
171 protected:
172 deallocator (malloc_state_machine *sm,
173 const char *name,
174 enum wording wording);
177 /* Subclass representing a predefined deallocator.
178 e.g. "delete []", without needing a specific FUNCTION_DECL
179 ahead of time. */
181 struct standard_deallocator : public deallocator
183 standard_deallocator (malloc_state_machine *sm,
184 const char *name,
185 enum wording wording);
188 /* Subclass representing a user-defined deallocator
189 via __attribute__((malloc(DEALLOCATOR))) given
190 a specific FUNCTION_DECL. */
192 struct custom_deallocator : public deallocator
194 custom_deallocator (malloc_state_machine *sm,
195 tree deallocator_fndecl,
196 enum wording wording)
197 : deallocator (sm, IDENTIFIER_POINTER (DECL_NAME (deallocator_fndecl)),
198 wording)
203 /* Base class representing a set of possible deallocators.
204 Often this will be just a single deallocator, but some
205 allocators have multiple valid deallocators (e.g. the result of
206 "fopen" can be closed by either "fclose" or "freopen"). */
208 struct deallocator_set
210 deallocator_set (malloc_state_machine *sm,
211 enum wording wording);
212 virtual ~deallocator_set () {}
214 virtual bool contains_p (const deallocator *d) const = 0;
215 virtual const deallocator *maybe_get_single () const = 0;
216 virtual void dump_to_pp (pretty_printer *pp) const = 0;
217 void dump () const;
219 /* Which wording to use in diagnostics. */
220 enum wording m_wording;
222 /* Pointers to states.
223 These states are owned by the state_machine base class. */
225 /* State for an unchecked result from an allocator using this set. */
226 state_machine::state_t m_unchecked;
228 /* State for a known non-NULL result from such an allocator. */
229 state_machine::state_t m_nonnull;
232 /* Subclass of deallocator_set representing a set of deallocators
233 defined by one or more __attribute__((malloc(DEALLOCATOR))). */
235 struct custom_deallocator_set : public deallocator_set
237 typedef const auto_vec <const deallocator *> *key_t;
239 custom_deallocator_set (malloc_state_machine *sm,
240 const auto_vec <const deallocator *> *vec,
241 //const char *name,
242 //const char *dealloc_funcname,
243 //unsigned arg_idx,
244 enum wording wording);
246 bool contains_p (const deallocator *d) const FINAL OVERRIDE;
247 const deallocator *maybe_get_single () const FINAL OVERRIDE;
248 void dump_to_pp (pretty_printer *pp) const FINAL OVERRIDE;
250 auto_vec <const deallocator *> m_deallocator_vec;
253 /* Subclass of deallocator_set representing a set of deallocators
254 with a single standard_deallocator, e.g. "delete []". */
256 struct standard_deallocator_set : public deallocator_set
258 standard_deallocator_set (malloc_state_machine *sm,
259 const char *name,
260 enum wording wording);
262 bool contains_p (const deallocator *d) const FINAL OVERRIDE;
263 const deallocator *maybe_get_single () const FINAL OVERRIDE;
264 void dump_to_pp (pretty_printer *pp) const FINAL OVERRIDE;
266 standard_deallocator m_deallocator;
269 /* Traits class for ensuring uniqueness of deallocator_sets within
270 malloc_state_machine. */
272 struct deallocator_set_map_traits
274 typedef custom_deallocator_set::key_t key_type;
275 typedef custom_deallocator_set *value_type;
276 typedef custom_deallocator_set *compare_type;
278 static inline hashval_t hash (const key_type &k)
280 gcc_assert (k != NULL);
281 gcc_assert (k != reinterpret_cast<key_type> (1));
283 hashval_t result = 0;
284 unsigned i;
285 const deallocator *d;
286 FOR_EACH_VEC_ELT (*k, i, d)
287 result ^= d->hash ();
288 return result;
290 static inline bool equal_keys (const key_type &k1, const key_type &k2)
292 if (k1->length () != k2->length ())
293 return false;
295 for (unsigned i = 0; i < k1->length (); i++)
296 if ((*k1)[i] != (*k2)[i])
297 return false;
299 return true;
301 template <typename T>
302 static inline void remove (T &)
304 /* empty; the nodes are handled elsewhere. */
306 template <typename T>
307 static inline void mark_deleted (T &entry)
309 entry.m_key = reinterpret_cast<key_type> (1);
311 template <typename T>
312 static inline void mark_empty (T &entry)
314 entry.m_key = NULL;
316 template <typename T>
317 static inline bool is_deleted (const T &entry)
319 return entry.m_key == reinterpret_cast<key_type> (1);
321 template <typename T>
322 static inline bool is_empty (const T &entry)
324 return entry.m_key == NULL;
326 static const bool empty_zero_p = false;
329 /* A state machine for detecting misuses of the malloc/free API.
331 See sm-malloc.dot for an overview (keep this in-sync with that file). */
333 class malloc_state_machine : public state_machine
335 public:
336 typedef allocation_state custom_data_t;
338 malloc_state_machine (logger *logger);
339 ~malloc_state_machine ();
341 state_t
342 add_state (const char *name, enum resource_state rs,
343 const deallocator_set *deallocators,
344 const deallocator *deallocator);
346 bool inherited_state_p () const FINAL OVERRIDE { return false; }
348 state_machine::state_t
349 get_default_state (const svalue *sval) const FINAL OVERRIDE
351 if (tree cst = sval->maybe_get_constant ())
353 if (zerop (cst))
354 return m_null;
356 if (const region_svalue *ptr = sval->dyn_cast_region_svalue ())
358 const region *reg = ptr->get_pointee ();
359 const region *base_reg = reg->get_base_region ();
360 if (base_reg->get_kind () == RK_DECL
361 || base_reg->get_kind () == RK_STRING)
362 return m_non_heap;
364 return m_start;
367 bool on_stmt (sm_context *sm_ctxt,
368 const supernode *node,
369 const gimple *stmt) const FINAL OVERRIDE;
371 void on_phi (sm_context *sm_ctxt,
372 const supernode *node,
373 const gphi *phi,
374 tree rhs) const FINAL OVERRIDE;
376 void on_condition (sm_context *sm_ctxt,
377 const supernode *node,
378 const gimple *stmt,
379 const svalue *lhs,
380 enum tree_code op,
381 const svalue *rhs) const FINAL OVERRIDE;
383 bool can_purge_p (state_t s) const FINAL OVERRIDE;
384 pending_diagnostic *on_leak (tree var) const FINAL OVERRIDE;
386 bool reset_when_passed_to_unknown_fn_p (state_t s,
387 bool is_mutable) const FINAL OVERRIDE;
389 static bool unaffected_by_call_p (tree fndecl);
391 void on_realloc_with_move (region_model *model,
392 sm_state_map *smap,
393 const svalue *old_ptr_sval,
394 const svalue *new_ptr_sval,
395 const extrinsic_state &ext_state) const;
397 standard_deallocator_set m_free;
398 standard_deallocator_set m_scalar_delete;
399 standard_deallocator_set m_vector_delete;
401 standard_deallocator m_realloc;
403 /* States that are independent of api. */
405 /* State for a pointer that's known to be NULL. */
406 state_t m_null;
408 /* State for a pointer that's known to not be on the heap (e.g. to a local
409 or global). */
410 state_t m_non_heap; // TODO: or should this be a different state machine?
411 // or do we need child values etc?
413 /* Stop state, for pointers we don't want to track any more. */
414 state_t m_stop;
416 private:
417 const custom_deallocator_set *
418 get_or_create_custom_deallocator_set (tree allocator_fndecl);
419 custom_deallocator_set *
420 maybe_create_custom_deallocator_set (tree allocator_fndecl);
421 const deallocator *
422 get_or_create_deallocator (tree deallocator_fndecl);
424 void on_allocator_call (sm_context *sm_ctxt,
425 const gcall *call,
426 const deallocator_set *deallocators,
427 bool returns_nonnull = false) const;
428 void on_deallocator_call (sm_context *sm_ctxt,
429 const supernode *node,
430 const gcall *call,
431 const deallocator *d,
432 unsigned argno) const;
433 void on_realloc_call (sm_context *sm_ctxt,
434 const supernode *node,
435 const gcall *call) const;
436 void on_zero_assignment (sm_context *sm_ctxt,
437 const gimple *stmt,
438 tree lhs) const;
440 /* A map for consolidating deallocators so that they are
441 unique per deallocator FUNCTION_DECL. */
442 typedef hash_map<tree, deallocator *> deallocator_map_t;
443 deallocator_map_t m_deallocator_map;
445 /* Memoized lookups from FUNCTION_DECL to custom_deallocator_set *. */
446 typedef hash_map<tree, custom_deallocator_set *> deallocator_set_cache_t;
447 deallocator_set_cache_t m_custom_deallocator_set_cache;
449 /* A map for consolidating custom_deallocator_set instances. */
450 typedef hash_map<custom_deallocator_set::key_t,
451 custom_deallocator_set *,
452 deallocator_set_map_traits> custom_deallocator_set_map_t;
453 custom_deallocator_set_map_t m_custom_deallocator_set_map;
455 /* Record of dynamically-allocated objects, for cleanup. */
456 auto_vec <custom_deallocator_set *> m_dynamic_sets;
457 auto_vec <custom_deallocator *> m_dynamic_deallocators;
460 /* struct deallocator. */
462 deallocator::deallocator (malloc_state_machine *sm,
463 const char *name,
464 enum wording wording)
465 : m_name (name),
466 m_wording (wording),
467 m_freed (sm->add_state ("freed", RS_FREED, NULL, this))
471 hashval_t
472 deallocator::hash () const
474 return (hashval_t)m_freed->get_id ();
477 void
478 deallocator::dump_to_pp (pretty_printer *pp) const
480 pp_printf (pp, "%qs", m_name);
484 deallocator::cmp (const deallocator *a, const deallocator *b)
486 return (int)a->m_freed->get_id () - (int)b->m_freed->get_id ();
490 deallocator::cmp_ptr_ptr (const void *a, const void *b)
492 return cmp (*(const deallocator * const *)a,
493 *(const deallocator * const *)b);
497 /* struct standard_deallocator : public deallocator. */
499 standard_deallocator::standard_deallocator (malloc_state_machine *sm,
500 const char *name,
501 enum wording wording)
502 : deallocator (sm, name, wording)
506 /* struct deallocator_set. */
508 deallocator_set::deallocator_set (malloc_state_machine *sm,
509 enum wording wording)
510 : m_wording (wording),
511 m_unchecked (sm->add_state ("unchecked", RS_UNCHECKED, this, NULL)),
512 m_nonnull (sm->add_state ("nonnull", RS_NONNULL, this, NULL))
516 /* Dump a description of this deallocator_set to stderr. */
518 DEBUG_FUNCTION void
519 deallocator_set::dump () const
521 pretty_printer pp;
522 pp_show_color (&pp) = pp_show_color (global_dc->printer);
523 pp.buffer->stream = stderr;
524 dump_to_pp (&pp);
525 pp_newline (&pp);
526 pp_flush (&pp);
529 /* struct custom_deallocator_set : public deallocator_set. */
531 custom_deallocator_set::
532 custom_deallocator_set (malloc_state_machine *sm,
533 const auto_vec <const deallocator *> *vec,
534 enum wording wording)
535 : deallocator_set (sm, wording),
536 m_deallocator_vec (vec->length ())
538 unsigned i;
539 const deallocator *d;
540 FOR_EACH_VEC_ELT (*vec, i, d)
541 m_deallocator_vec.safe_push (d);
544 bool
545 custom_deallocator_set::contains_p (const deallocator *d) const
547 unsigned i;
548 const deallocator *cd;
549 FOR_EACH_VEC_ELT (m_deallocator_vec, i, cd)
550 if (cd == d)
551 return true;
552 return false;
555 const deallocator *
556 custom_deallocator_set::maybe_get_single () const
558 if (m_deallocator_vec.length () == 1)
559 return m_deallocator_vec[0];
560 return NULL;
563 void
564 custom_deallocator_set::dump_to_pp (pretty_printer *pp) const
566 pp_character (pp, '{');
567 unsigned i;
568 const deallocator *d;
569 FOR_EACH_VEC_ELT (m_deallocator_vec, i, d)
571 if (i > 0)
572 pp_string (pp, ", ");
573 d->dump_to_pp (pp);
575 pp_character (pp, '}');
578 /* struct standard_deallocator_set : public deallocator_set. */
580 standard_deallocator_set::standard_deallocator_set (malloc_state_machine *sm,
581 const char *name,
582 enum wording wording)
583 : deallocator_set (sm, wording),
584 m_deallocator (sm, name, wording)
588 bool
589 standard_deallocator_set::contains_p (const deallocator *d) const
591 return d == &m_deallocator;
594 const deallocator *
595 standard_deallocator_set::maybe_get_single () const
597 return &m_deallocator;
600 void
601 standard_deallocator_set::dump_to_pp (pretty_printer *pp) const
603 pp_character (pp, '{');
604 pp_string (pp, m_deallocator.m_name);
605 pp_character (pp, '}');
608 /* Return STATE cast to the custom state subclass, or NULL for the start state.
609 Everything should be an allocation_state apart from the start state. */
611 static const allocation_state *
612 dyn_cast_allocation_state (state_machine::state_t state)
614 if (state->get_id () == 0)
615 return NULL;
616 return static_cast <const allocation_state *> (state);
619 /* Return STATE cast to the custom state subclass, for a state that is
620 already known to not be the start state . */
622 static const allocation_state *
623 as_a_allocation_state (state_machine::state_t state)
625 gcc_assert (state->get_id () != 0);
626 return static_cast <const allocation_state *> (state);
629 /* Get the resource_state for STATE. */
631 static enum resource_state
632 get_rs (state_machine::state_t state)
634 if (const allocation_state *astate = dyn_cast_allocation_state (state))
635 return astate->m_rs;
636 else
637 return RS_START;
640 /* Return true if STATE is the start state. */
642 static bool
643 start_p (state_machine::state_t state)
645 return get_rs (state) == RS_START;
648 /* Return true if STATE is an unchecked result from an allocator. */
650 static bool
651 unchecked_p (state_machine::state_t state)
653 return get_rs (state) == RS_UNCHECKED;
656 /* Return true if STATE is a non-null result from an allocator. */
658 static bool
659 nonnull_p (state_machine::state_t state)
661 return get_rs (state) == RS_NONNULL;
664 /* Return true if STATE is a value that has been passed to a deallocator. */
666 static bool
667 freed_p (state_machine::state_t state)
669 return get_rs (state) == RS_FREED;
672 /* Class for diagnostics relating to malloc_state_machine. */
674 class malloc_diagnostic : public pending_diagnostic
676 public:
677 malloc_diagnostic (const malloc_state_machine &sm, tree arg)
678 : m_sm (sm), m_arg (arg)
681 bool subclass_equal_p (const pending_diagnostic &base_other) const OVERRIDE
683 return same_tree_p (m_arg, ((const malloc_diagnostic &)base_other).m_arg);
686 label_text describe_state_change (const evdesc::state_change &change)
687 OVERRIDE
689 if (change.m_old_state == m_sm.get_start_state ()
690 && unchecked_p (change.m_new_state))
691 // TODO: verify that it's the allocation stmt, not a copy
692 return label_text::borrow ("allocated here");
693 if (unchecked_p (change.m_old_state)
694 && nonnull_p (change.m_new_state))
696 if (change.m_expr)
697 return change.formatted_print ("assuming %qE is non-NULL",
698 change.m_expr);
699 else
700 return change.formatted_print ("assuming %qs is non-NULL",
701 "<unknown>");
703 if (change.m_new_state == m_sm.m_null)
705 if (unchecked_p (change.m_old_state))
707 if (change.m_expr)
708 return change.formatted_print ("assuming %qE is NULL",
709 change.m_expr);
710 else
711 return change.formatted_print ("assuming %qs is NULL",
712 "<unknown>");
714 else
716 if (change.m_expr)
717 return change.formatted_print ("%qE is NULL",
718 change.m_expr);
719 else
720 return change.formatted_print ("%qs is NULL",
721 "<unknown>");
725 return label_text ();
728 protected:
729 const malloc_state_machine &m_sm;
730 tree m_arg;
733 /* Concrete subclass for reporting mismatching allocator/deallocator
734 diagnostics. */
736 class mismatching_deallocation : public malloc_diagnostic
738 public:
739 mismatching_deallocation (const malloc_state_machine &sm, tree arg,
740 const deallocator_set *expected_deallocators,
741 const deallocator *actual_dealloc)
742 : malloc_diagnostic (sm, arg),
743 m_expected_deallocators (expected_deallocators),
744 m_actual_dealloc (actual_dealloc)
747 const char *get_kind () const FINAL OVERRIDE
749 return "mismatching_deallocation";
752 bool emit (rich_location *rich_loc) FINAL OVERRIDE
754 auto_diagnostic_group d;
755 diagnostic_metadata m;
756 m.add_cwe (762); /* CWE-762: Mismatched Memory Management Routines. */
757 if (const deallocator *expected_dealloc
758 = m_expected_deallocators->maybe_get_single ())
759 return warning_meta (rich_loc, m, OPT_Wanalyzer_mismatching_deallocation,
760 "%qE should have been deallocated with %qs"
761 " but was deallocated with %qs",
762 m_arg, expected_dealloc->m_name,
763 m_actual_dealloc->m_name);
764 else
765 return warning_meta (rich_loc, m, OPT_Wanalyzer_mismatching_deallocation,
766 "%qs called on %qE returned from a mismatched"
767 " allocation function",
768 m_actual_dealloc->m_name, m_arg);
771 label_text describe_state_change (const evdesc::state_change &change)
772 FINAL OVERRIDE
774 if (unchecked_p (change.m_new_state))
776 m_alloc_event = change.m_event_id;
777 if (const deallocator *expected_dealloc
778 = m_expected_deallocators->maybe_get_single ())
779 return change.formatted_print ("allocated here"
780 " (expects deallocation with %qs)",
781 expected_dealloc->m_name);
782 else
783 return change.formatted_print ("allocated here");
785 return malloc_diagnostic::describe_state_change (change);
788 label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
790 if (m_alloc_event.known_p ())
792 if (const deallocator *expected_dealloc
793 = m_expected_deallocators->maybe_get_single ())
794 return ev.formatted_print
795 ("deallocated with %qs here;"
796 " allocation at %@ expects deallocation with %qs",
797 m_actual_dealloc->m_name, &m_alloc_event,
798 expected_dealloc->m_name);
799 else
800 return ev.formatted_print
801 ("deallocated with %qs here;"
802 " allocated at %@",
803 m_actual_dealloc->m_name, &m_alloc_event);
805 return ev.formatted_print ("deallocated with %qs here",
806 m_actual_dealloc->m_name);
809 private:
810 diagnostic_event_id_t m_alloc_event;
811 const deallocator_set *m_expected_deallocators;
812 const deallocator *m_actual_dealloc;
815 /* Concrete subclass for reporting double-free diagnostics. */
817 class double_free : public malloc_diagnostic
819 public:
820 double_free (const malloc_state_machine &sm, tree arg, const char *funcname)
821 : malloc_diagnostic (sm, arg), m_funcname (funcname)
824 const char *get_kind () const FINAL OVERRIDE { return "double_free"; }
826 bool emit (rich_location *rich_loc) FINAL OVERRIDE
828 auto_diagnostic_group d;
829 diagnostic_metadata m;
830 m.add_cwe (415); /* CWE-415: Double Free. */
831 return warning_meta (rich_loc, m, OPT_Wanalyzer_double_free,
832 "double-%qs of %qE", m_funcname, m_arg);
835 label_text describe_state_change (const evdesc::state_change &change)
836 FINAL OVERRIDE
838 if (freed_p (change.m_new_state))
840 m_first_free_event = change.m_event_id;
841 return change.formatted_print ("first %qs here", m_funcname);
843 return malloc_diagnostic::describe_state_change (change);
846 label_text describe_call_with_state (const evdesc::call_with_state &info)
847 FINAL OVERRIDE
849 if (freed_p (info.m_state))
850 return info.formatted_print
851 ("passing freed pointer %qE in call to %qE from %qE",
852 info.m_expr, info.m_callee_fndecl, info.m_caller_fndecl);
853 return label_text ();
856 label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
858 if (m_first_free_event.known_p ())
859 return ev.formatted_print ("second %qs here; first %qs was at %@",
860 m_funcname, m_funcname,
861 &m_first_free_event);
862 return ev.formatted_print ("second %qs here", m_funcname);
865 private:
866 diagnostic_event_id_t m_first_free_event;
867 const char *m_funcname;
870 /* Abstract subclass for describing possible bad uses of NULL.
871 Responsible for describing the call that could return NULL. */
873 class possible_null : public malloc_diagnostic
875 public:
876 possible_null (const malloc_state_machine &sm, tree arg)
877 : malloc_diagnostic (sm, arg)
880 label_text describe_state_change (const evdesc::state_change &change)
881 FINAL OVERRIDE
883 if (change.m_old_state == m_sm.get_start_state ()
884 && unchecked_p (change.m_new_state))
886 m_origin_of_unchecked_event = change.m_event_id;
887 return label_text::borrow ("this call could return NULL");
889 return malloc_diagnostic::describe_state_change (change);
892 label_text describe_return_of_state (const evdesc::return_of_state &info)
893 FINAL OVERRIDE
895 if (unchecked_p (info.m_state))
896 return info.formatted_print ("possible return of NULL to %qE from %qE",
897 info.m_caller_fndecl, info.m_callee_fndecl);
898 return label_text ();
901 protected:
902 diagnostic_event_id_t m_origin_of_unchecked_event;
905 /* Concrete subclass for describing dereference of a possible NULL
906 value. */
908 class possible_null_deref : public possible_null
910 public:
911 possible_null_deref (const malloc_state_machine &sm, tree arg)
912 : possible_null (sm, arg)
915 const char *get_kind () const FINAL OVERRIDE { return "possible_null_deref"; }
917 bool emit (rich_location *rich_loc) FINAL OVERRIDE
919 /* CWE-690: Unchecked Return Value to NULL Pointer Dereference. */
920 diagnostic_metadata m;
921 m.add_cwe (690);
922 return warning_meta (rich_loc, m,
923 OPT_Wanalyzer_possible_null_dereference,
924 "dereference of possibly-NULL %qE", m_arg);
927 label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
929 if (m_origin_of_unchecked_event.known_p ())
930 return ev.formatted_print ("%qE could be NULL: unchecked value from %@",
931 ev.m_expr,
932 &m_origin_of_unchecked_event);
933 else
934 return ev.formatted_print ("%qE could be NULL", ev.m_expr);
939 /* Return true if FNDECL is a C++ method. */
941 static bool
942 method_p (tree fndecl)
944 return TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE;
947 /* Return a 1-based description of ARG_IDX (0-based) of FNDECL.
948 Compare with %P in the C++ FE (implemented in cp/error.c: parm_to_string
949 as called from cp_printer). */
951 static label_text
952 describe_argument_index (tree fndecl, int arg_idx)
954 if (method_p (fndecl))
955 if (arg_idx == 0)
956 return label_text::borrow ("'this'");
957 pretty_printer pp;
958 pp_printf (&pp, "%u", arg_idx + 1 - method_p (fndecl));
959 return label_text::take (xstrdup (pp_formatted_text (&pp)));
962 /* Subroutine for use by possible_null_arg::emit and null_arg::emit.
963 Issue a note informing that the pertinent argument must be non-NULL. */
965 static void
966 inform_nonnull_attribute (tree fndecl, int arg_idx)
968 label_text arg_desc = describe_argument_index (fndecl, arg_idx);
969 inform (DECL_SOURCE_LOCATION (fndecl),
970 "argument %s of %qD must be non-null",
971 arg_desc.m_buffer, fndecl);
972 arg_desc.maybe_free ();
973 /* Ideally we would use the location of the parm and underline the
974 attribute also - but we don't have the location_t values at this point
975 in the middle-end.
976 For reference, the C and C++ FEs have get_fndecl_argument_location. */
979 /* Concrete subclass for describing passing a possibly-NULL value to a
980 function marked with __attribute__((nonnull)). */
982 class possible_null_arg : public possible_null
984 public:
985 possible_null_arg (const malloc_state_machine &sm, tree arg,
986 tree fndecl, int arg_idx)
987 : possible_null (sm, arg),
988 m_fndecl (fndecl), m_arg_idx (arg_idx)
991 const char *get_kind () const FINAL OVERRIDE { return "possible_null_arg"; }
993 bool subclass_equal_p (const pending_diagnostic &base_other) const
995 const possible_null_arg &sub_other
996 = (const possible_null_arg &)base_other;
997 return (same_tree_p (m_arg, sub_other.m_arg)
998 && m_fndecl == sub_other.m_fndecl
999 && m_arg_idx == sub_other.m_arg_idx);
1003 bool emit (rich_location *rich_loc) FINAL OVERRIDE
1005 /* CWE-690: Unchecked Return Value to NULL Pointer Dereference. */
1006 auto_diagnostic_group d;
1007 diagnostic_metadata m;
1008 m.add_cwe (690);
1009 bool warned
1010 = warning_meta (rich_loc, m, OPT_Wanalyzer_possible_null_argument,
1011 "use of possibly-NULL %qE where non-null expected",
1012 m_arg);
1013 if (warned)
1014 inform_nonnull_attribute (m_fndecl, m_arg_idx);
1015 return warned;
1018 label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
1020 label_text arg_desc = describe_argument_index (m_fndecl, m_arg_idx);
1021 label_text result;
1022 if (m_origin_of_unchecked_event.known_p ())
1023 result = ev.formatted_print ("argument %s (%qE) from %@ could be NULL"
1024 " where non-null expected",
1025 arg_desc.m_buffer, ev.m_expr,
1026 &m_origin_of_unchecked_event);
1027 else
1028 result = ev.formatted_print ("argument %s (%qE) could be NULL"
1029 " where non-null expected",
1030 arg_desc.m_buffer, ev.m_expr);
1031 arg_desc.maybe_free ();
1032 return result;
1035 private:
1036 tree m_fndecl;
1037 int m_arg_idx;
1040 /* Concrete subclass for describing a dereference of a NULL value. */
1042 class null_deref : public malloc_diagnostic
1044 public:
1045 null_deref (const malloc_state_machine &sm, tree arg)
1046 : malloc_diagnostic (sm, arg) {}
1048 const char *get_kind () const FINAL OVERRIDE { return "null_deref"; }
1050 bool emit (rich_location *rich_loc) FINAL OVERRIDE
1052 /* CWE-476: NULL Pointer Dereference. */
1053 diagnostic_metadata m;
1054 m.add_cwe (476);
1055 return warning_meta (rich_loc, m,
1056 OPT_Wanalyzer_null_dereference,
1057 "dereference of NULL %qE", m_arg);
1060 label_text describe_return_of_state (const evdesc::return_of_state &info)
1061 FINAL OVERRIDE
1063 if (info.m_state == m_sm.m_null)
1064 return info.formatted_print ("return of NULL to %qE from %qE",
1065 info.m_caller_fndecl, info.m_callee_fndecl);
1066 return label_text ();
1069 label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
1071 return ev.formatted_print ("dereference of NULL %qE", ev.m_expr);
1075 /* Concrete subclass for describing passing a NULL value to a
1076 function marked with __attribute__((nonnull)). */
1078 class null_arg : public malloc_diagnostic
1080 public:
1081 null_arg (const malloc_state_machine &sm, tree arg,
1082 tree fndecl, int arg_idx)
1083 : malloc_diagnostic (sm, arg),
1084 m_fndecl (fndecl), m_arg_idx (arg_idx)
1087 const char *get_kind () const FINAL OVERRIDE { return "null_arg"; }
1089 bool subclass_equal_p (const pending_diagnostic &base_other) const
1091 const null_arg &sub_other
1092 = (const null_arg &)base_other;
1093 return (same_tree_p (m_arg, sub_other.m_arg)
1094 && m_fndecl == sub_other.m_fndecl
1095 && m_arg_idx == sub_other.m_arg_idx);
1098 bool emit (rich_location *rich_loc) FINAL OVERRIDE
1100 /* CWE-476: NULL Pointer Dereference. */
1101 auto_diagnostic_group d;
1102 diagnostic_metadata m;
1103 m.add_cwe (476);
1105 bool warned;
1106 if (zerop (m_arg))
1107 warned = warning_meta (rich_loc, m, OPT_Wanalyzer_null_argument,
1108 "use of NULL where non-null expected");
1109 else
1110 warned = warning_meta (rich_loc, m, OPT_Wanalyzer_null_argument,
1111 "use of NULL %qE where non-null expected",
1112 m_arg);
1113 if (warned)
1114 inform_nonnull_attribute (m_fndecl, m_arg_idx);
1115 return warned;
1118 label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
1120 label_text arg_desc = describe_argument_index (m_fndecl, m_arg_idx);
1121 label_text result;
1122 if (zerop (ev.m_expr))
1123 result = ev.formatted_print ("argument %s NULL where non-null expected",
1124 arg_desc.m_buffer);
1125 else
1126 result = ev.formatted_print ("argument %s (%qE) NULL"
1127 " where non-null expected",
1128 arg_desc.m_buffer, ev.m_expr);
1129 arg_desc.maybe_free ();
1130 return result;
1133 private:
1134 tree m_fndecl;
1135 int m_arg_idx;
1138 class use_after_free : public malloc_diagnostic
1140 public:
1141 use_after_free (const malloc_state_machine &sm, tree arg,
1142 const deallocator *deallocator)
1143 : malloc_diagnostic (sm, arg),
1144 m_deallocator (deallocator)
1146 gcc_assert (deallocator);
1149 const char *get_kind () const FINAL OVERRIDE { return "use_after_free"; }
1151 bool emit (rich_location *rich_loc) FINAL OVERRIDE
1153 /* CWE-416: Use After Free. */
1154 diagnostic_metadata m;
1155 m.add_cwe (416);
1156 return warning_meta (rich_loc, m, OPT_Wanalyzer_use_after_free,
1157 "use after %<%s%> of %qE",
1158 m_deallocator->m_name, m_arg);
1161 label_text describe_state_change (const evdesc::state_change &change)
1162 FINAL OVERRIDE
1164 if (freed_p (change.m_new_state))
1166 m_free_event = change.m_event_id;
1167 switch (m_deallocator->m_wording)
1169 default:
1170 case WORDING_REALLOCATED:
1171 gcc_unreachable ();
1172 case WORDING_FREED:
1173 return label_text::borrow ("freed here");
1174 case WORDING_DELETED:
1175 return label_text::borrow ("deleted here");
1176 case WORDING_DEALLOCATED:
1177 return label_text::borrow ("deallocated here");
1180 return malloc_diagnostic::describe_state_change (change);
1183 label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
1185 const char *funcname = m_deallocator->m_name;
1186 if (m_free_event.known_p ())
1187 switch (m_deallocator->m_wording)
1189 default:
1190 case WORDING_REALLOCATED:
1191 gcc_unreachable ();
1192 case WORDING_FREED:
1193 return ev.formatted_print ("use after %<%s%> of %qE; freed at %@",
1194 funcname, ev.m_expr, &m_free_event);
1195 case WORDING_DELETED:
1196 return ev.formatted_print ("use after %<%s%> of %qE; deleted at %@",
1197 funcname, ev.m_expr, &m_free_event);
1198 case WORDING_DEALLOCATED:
1199 return ev.formatted_print ("use after %<%s%> of %qE;"
1200 " deallocated at %@",
1201 funcname, ev.m_expr, &m_free_event);
1203 else
1204 return ev.formatted_print ("use after %<%s%> of %qE",
1205 funcname, ev.m_expr);
1208 /* Implementation of pending_diagnostic::supercedes_p for
1209 use_after_free.
1211 We want use-after-free to supercede use-of-unitialized-value,
1212 so that if we have these at the same stmt, we don't emit
1213 a use-of-uninitialized, just the use-after-free.
1214 (this is because we fully purge information about freed
1215 buffers when we free them to avoid state explosions, so
1216 that if they are accessed after the free, it looks like
1217 they are uninitialized). */
1219 bool supercedes_p (const pending_diagnostic &other) const FINAL OVERRIDE
1221 if (other.use_of_uninit_p ())
1222 return true;
1224 return false;
1227 private:
1228 diagnostic_event_id_t m_free_event;
1229 const deallocator *m_deallocator;
1232 class malloc_leak : public malloc_diagnostic
1234 public:
1235 malloc_leak (const malloc_state_machine &sm, tree arg)
1236 : malloc_diagnostic (sm, arg) {}
1238 const char *get_kind () const FINAL OVERRIDE { return "malloc_leak"; }
1240 bool emit (rich_location *rich_loc) FINAL OVERRIDE
1242 diagnostic_metadata m;
1243 m.add_cwe (401);
1244 if (m_arg)
1245 return warning_meta (rich_loc, m, OPT_Wanalyzer_malloc_leak,
1246 "leak of %qE", m_arg);
1247 else
1248 return warning_meta (rich_loc, m, OPT_Wanalyzer_malloc_leak,
1249 "leak of %qs", "<unknown>");
1252 label_text describe_state_change (const evdesc::state_change &change)
1253 FINAL OVERRIDE
1255 if (unchecked_p (change.m_new_state)
1256 || (start_p (change.m_old_state) && nonnull_p (change.m_new_state)))
1258 m_alloc_event = change.m_event_id;
1259 return label_text::borrow ("allocated here");
1261 return malloc_diagnostic::describe_state_change (change);
1264 label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
1266 if (ev.m_expr)
1268 if (m_alloc_event.known_p ())
1269 return ev.formatted_print ("%qE leaks here; was allocated at %@",
1270 ev.m_expr, &m_alloc_event);
1271 else
1272 return ev.formatted_print ("%qE leaks here", ev.m_expr);
1274 else
1276 if (m_alloc_event.known_p ())
1277 return ev.formatted_print ("%qs leaks here; was allocated at %@",
1278 "<unknown>", &m_alloc_event);
1279 else
1280 return ev.formatted_print ("%qs leaks here", "<unknown>");
1284 private:
1285 diagnostic_event_id_t m_alloc_event;
1288 class free_of_non_heap : public malloc_diagnostic
1290 public:
1291 free_of_non_heap (const malloc_state_machine &sm, tree arg,
1292 const char *funcname)
1293 : malloc_diagnostic (sm, arg), m_funcname (funcname), m_kind (KIND_UNKNOWN)
1297 const char *get_kind () const FINAL OVERRIDE { return "free_of_non_heap"; }
1299 bool subclass_equal_p (const pending_diagnostic &base_other) const
1300 FINAL OVERRIDE
1302 const free_of_non_heap &other = (const free_of_non_heap &)base_other;
1303 return (same_tree_p (m_arg, other.m_arg) && m_kind == other.m_kind);
1306 bool emit (rich_location *rich_loc) FINAL OVERRIDE
1308 auto_diagnostic_group d;
1309 diagnostic_metadata m;
1310 m.add_cwe (590); /* CWE-590: Free of Memory not on the Heap. */
1311 switch (m_kind)
1313 default:
1314 gcc_unreachable ();
1315 case KIND_UNKNOWN:
1316 return warning_meta (rich_loc, m, OPT_Wanalyzer_free_of_non_heap,
1317 "%<%s%> of %qE which points to memory"
1318 " not on the heap",
1319 m_funcname, m_arg);
1320 break;
1321 case KIND_ALLOCA:
1322 return warning_meta (rich_loc, m, OPT_Wanalyzer_free_of_non_heap,
1323 "%<%s%> of memory allocated on the stack by"
1324 " %qs (%qE) will corrupt the heap",
1325 m_funcname, "alloca", m_arg);
1326 break;
1330 label_text describe_state_change (const evdesc::state_change &change)
1331 FINAL OVERRIDE
1333 /* Attempt to reconstruct what kind of pointer it is.
1334 (It seems neater for this to be a part of the state, though). */
1335 if (change.m_expr && TREE_CODE (change.m_expr) == SSA_NAME)
1337 gimple *def_stmt = SSA_NAME_DEF_STMT (change.m_expr);
1338 if (gcall *call = dyn_cast <gcall *> (def_stmt))
1340 if (is_special_named_call_p (call, "alloca", 1)
1341 || is_special_named_call_p (call, "__builtin_alloca", 1))
1343 m_kind = KIND_ALLOCA;
1344 return label_text::borrow
1345 ("memory is allocated on the stack here");
1349 return label_text::borrow ("pointer is from here");
1352 label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
1354 return ev.formatted_print ("call to %qs here", m_funcname);
1357 private:
1358 enum kind
1360 KIND_UNKNOWN,
1361 KIND_ALLOCA
1363 const char *m_funcname;
1364 enum kind m_kind;
1367 /* struct allocation_state : public state_machine::state. */
1369 /* Implementation of state_machine::state::dump_to_pp vfunc
1370 for allocation_state: append the API that this allocation is
1371 associated with. */
1373 void
1374 allocation_state::dump_to_pp (pretty_printer *pp) const
1376 state_machine::state::dump_to_pp (pp);
1377 if (m_deallocators)
1379 pp_string (pp, " (");
1380 m_deallocators->dump_to_pp (pp);
1381 pp_character (pp, ')');
1385 /* Given a allocation_state for a deallocator_set, get the "nonnull" state
1386 for the corresponding allocator(s). */
1388 const allocation_state *
1389 allocation_state::get_nonnull () const
1391 gcc_assert (m_deallocators);
1392 return as_a_allocation_state (m_deallocators->m_nonnull);
1395 /* malloc_state_machine's ctor. */
1397 malloc_state_machine::malloc_state_machine (logger *logger)
1398 : state_machine ("malloc", logger),
1399 m_free (this, "free", WORDING_FREED),
1400 m_scalar_delete (this, "delete", WORDING_DELETED),
1401 m_vector_delete (this, "delete[]", WORDING_DELETED),
1402 m_realloc (this, "realloc", WORDING_REALLOCATED)
1404 gcc_assert (m_start->get_id () == 0);
1405 m_null = add_state ("null", RS_FREED, NULL, NULL);
1406 m_non_heap = add_state ("non-heap", RS_NON_HEAP, NULL, NULL);
1407 m_stop = add_state ("stop", RS_STOP, NULL, NULL);
1410 malloc_state_machine::~malloc_state_machine ()
1412 unsigned i;
1413 custom_deallocator_set *set;
1414 FOR_EACH_VEC_ELT (m_dynamic_sets, i, set)
1415 delete set;
1416 custom_deallocator *d;
1417 FOR_EACH_VEC_ELT (m_dynamic_deallocators, i, d)
1418 delete d;
1421 state_machine::state_t
1422 malloc_state_machine::add_state (const char *name, enum resource_state rs,
1423 const deallocator_set *deallocators,
1424 const deallocator *deallocator)
1426 return add_custom_state (new allocation_state (name, alloc_state_id (),
1427 rs, deallocators,
1428 deallocator));
1431 /* If ALLOCATOR_FNDECL has any "__attribute__((malloc(FOO)))",
1432 return a custom_deallocator_set for them, consolidating them
1433 to ensure uniqueness of the sets.
1435 Return NULL if it has no such attributes. */
1437 const custom_deallocator_set *
1438 malloc_state_machine::
1439 get_or_create_custom_deallocator_set (tree allocator_fndecl)
1441 /* Early rejection of decls without attributes. */
1442 tree attrs = DECL_ATTRIBUTES (allocator_fndecl);
1443 if (!attrs)
1444 return NULL;
1446 /* Otherwise, call maybe_create_custom_deallocator_set,
1447 memoizing the result. */
1448 if (custom_deallocator_set **slot
1449 = m_custom_deallocator_set_cache.get (allocator_fndecl))
1450 return *slot;
1451 custom_deallocator_set *set
1452 = maybe_create_custom_deallocator_set (allocator_fndecl);
1453 m_custom_deallocator_set_cache.put (allocator_fndecl, set);
1454 return set;
1457 /* Given ALLOCATOR_FNDECL, a FUNCTION_DECL with attributes,
1458 look for any "__attribute__((malloc(FOO)))" and return a
1459 custom_deallocator_set for them, consolidating them
1460 to ensure uniqueness of the sets.
1462 Return NULL if it has no such attributes.
1464 Subroutine of get_or_create_custom_deallocator_set which
1465 memoizes the result. */
1467 custom_deallocator_set *
1468 malloc_state_machine::
1469 maybe_create_custom_deallocator_set (tree allocator_fndecl)
1471 tree attrs = DECL_ATTRIBUTES (allocator_fndecl);
1472 gcc_assert (attrs);
1474 /* Look for instances of __attribute__((malloc(FOO))). */
1475 auto_vec<const deallocator *> deallocator_vec;
1476 for (tree allocs = attrs;
1477 (allocs = lookup_attribute ("malloc", allocs));
1478 allocs = TREE_CHAIN (allocs))
1480 tree args = TREE_VALUE (allocs);
1481 if (!args)
1482 continue;
1483 if (TREE_VALUE (args))
1485 const deallocator *d
1486 = get_or_create_deallocator (TREE_VALUE (args));
1487 deallocator_vec.safe_push (d);
1491 /* If there weren't any deallocators, bail. */
1492 if (deallocator_vec.length () == 0)
1493 return NULL;
1495 /* Consolidate, so that we reuse existing deallocator_set
1496 instances. */
1497 deallocator_vec.qsort (deallocator::cmp_ptr_ptr);
1498 custom_deallocator_set **slot
1499 = m_custom_deallocator_set_map.get (&deallocator_vec);
1500 if (slot)
1501 return *slot;
1502 custom_deallocator_set *set
1503 = new custom_deallocator_set (this, &deallocator_vec, WORDING_DEALLOCATED);
1504 m_custom_deallocator_set_map.put (&set->m_deallocator_vec, set);
1505 m_dynamic_sets.safe_push (set);
1506 return set;
1509 /* Get the deallocator for DEALLOCATOR_FNDECL, creating it if necessary. */
1511 const deallocator *
1512 malloc_state_machine::get_or_create_deallocator (tree deallocator_fndecl)
1514 deallocator **slot = m_deallocator_map.get (deallocator_fndecl);
1515 if (slot)
1516 return *slot;
1518 /* Reuse "free". */
1519 deallocator *d;
1520 if (is_named_call_p (deallocator_fndecl, "free")
1521 || is_std_named_call_p (deallocator_fndecl, "free")
1522 || is_named_call_p (deallocator_fndecl, "__builtin_free"))
1523 d = &m_free.m_deallocator;
1524 else
1526 custom_deallocator *cd
1527 = new custom_deallocator (this, deallocator_fndecl,
1528 WORDING_DEALLOCATED);
1529 m_dynamic_deallocators.safe_push (cd);
1530 d = cd;
1532 m_deallocator_map.put (deallocator_fndecl, d);
1533 return d;
1536 /* Try to identify the function declaration either by name or as a known malloc
1537 builtin. */
1539 static bool
1540 known_allocator_p (const_tree fndecl, const gcall *call)
1542 /* Either it is a function we know by name and number of arguments... */
1543 if (is_named_call_p (fndecl, "malloc", call, 1)
1544 || is_named_call_p (fndecl, "calloc", call, 2)
1545 || is_std_named_call_p (fndecl, "malloc", call, 1)
1546 || is_std_named_call_p (fndecl, "calloc", call, 2)
1547 || is_named_call_p (fndecl, "strdup", call, 1)
1548 || is_named_call_p (fndecl, "strndup", call, 2))
1549 return true;
1551 /* ... or it is a builtin allocator that allocates objects freed with
1552 __builtin_free. */
1553 if (fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
1554 switch (DECL_FUNCTION_CODE (fndecl))
1556 case BUILT_IN_MALLOC:
1557 case BUILT_IN_CALLOC:
1558 case BUILT_IN_STRDUP:
1559 case BUILT_IN_STRNDUP:
1560 return true;
1561 default:
1562 break;
1565 return false;
1568 /* Implementation of state_machine::on_stmt vfunc for malloc_state_machine. */
1570 bool
1571 malloc_state_machine::on_stmt (sm_context *sm_ctxt,
1572 const supernode *node,
1573 const gimple *stmt) const
1575 if (const gcall *call = dyn_cast <const gcall *> (stmt))
1576 if (tree callee_fndecl = sm_ctxt->get_fndecl_for_call (call))
1578 if (known_allocator_p (callee_fndecl, call))
1580 on_allocator_call (sm_ctxt, call, &m_free);
1581 return true;
1584 if (is_named_call_p (callee_fndecl, "operator new", call, 1))
1585 on_allocator_call (sm_ctxt, call, &m_scalar_delete);
1586 else if (is_named_call_p (callee_fndecl, "operator new []", call, 1))
1587 on_allocator_call (sm_ctxt, call, &m_vector_delete);
1588 else if (is_named_call_p (callee_fndecl, "operator delete", call, 1)
1589 || is_named_call_p (callee_fndecl, "operator delete", call, 2))
1591 on_deallocator_call (sm_ctxt, node, call,
1592 &m_scalar_delete.m_deallocator, 0);
1593 return true;
1595 else if (is_named_call_p (callee_fndecl, "operator delete []", call, 1))
1597 on_deallocator_call (sm_ctxt, node, call,
1598 &m_vector_delete.m_deallocator, 0);
1599 return true;
1602 if (is_named_call_p (callee_fndecl, "alloca", call, 1)
1603 || is_named_call_p (callee_fndecl, "__builtin_alloca", call, 1))
1605 tree lhs = gimple_call_lhs (call);
1606 if (lhs)
1607 sm_ctxt->on_transition (node, stmt, lhs, m_start, m_non_heap);
1608 return true;
1611 if (is_named_call_p (callee_fndecl, "free", call, 1)
1612 || is_std_named_call_p (callee_fndecl, "free", call, 1)
1613 || is_named_call_p (callee_fndecl, "__builtin_free", call, 1))
1615 on_deallocator_call (sm_ctxt, node, call,
1616 &m_free.m_deallocator, 0);
1617 return true;
1620 if (is_named_call_p (callee_fndecl, "realloc", call, 2)
1621 || is_named_call_p (callee_fndecl, "__builtin_realloc", call, 2))
1623 on_realloc_call (sm_ctxt, node, call);
1624 return true;
1627 if (unaffected_by_call_p (callee_fndecl))
1628 return true;
1630 /* Cast away const-ness for cache-like operations. */
1631 malloc_state_machine *mutable_this
1632 = const_cast <malloc_state_machine *> (this);
1634 /* Handle "__attribute__((malloc(FOO)))". */
1635 if (const deallocator_set *deallocators
1636 = mutable_this->get_or_create_custom_deallocator_set
1637 (callee_fndecl))
1639 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (callee_fndecl));
1640 bool returns_nonnull
1641 = lookup_attribute ("returns_nonnull", attrs);
1642 on_allocator_call (sm_ctxt, call, deallocators, returns_nonnull);
1645 /* Handle "__attribute__((nonnull))". */
1647 tree fntype = TREE_TYPE (callee_fndecl);
1648 bitmap nonnull_args = get_nonnull_args (fntype);
1649 if (nonnull_args)
1651 for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
1653 tree arg = gimple_call_arg (stmt, i);
1654 if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
1655 continue;
1656 /* If we have a nonnull-args, and either all pointers, or just
1657 the specified pointers. */
1658 if (bitmap_empty_p (nonnull_args)
1659 || bitmap_bit_p (nonnull_args, i))
1661 state_t state = sm_ctxt->get_state (stmt, arg);
1662 /* Can't use a switch as the states are non-const. */
1663 if (unchecked_p (state))
1665 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1666 sm_ctxt->warn (node, stmt, arg,
1667 new possible_null_arg (*this, diag_arg,
1668 callee_fndecl,
1669 i));
1670 const allocation_state *astate
1671 = as_a_allocation_state (state);
1672 sm_ctxt->set_next_state (stmt, arg,
1673 astate->get_nonnull ());
1675 else if (state == m_null)
1677 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1678 sm_ctxt->warn (node, stmt, arg,
1679 new null_arg (*this, diag_arg,
1680 callee_fndecl, i));
1681 sm_ctxt->set_next_state (stmt, arg, m_stop);
1685 BITMAP_FREE (nonnull_args);
1689 /* Check for this after nonnull, so that if we have both
1690 then we transition to "freed", rather than "checked". */
1691 unsigned dealloc_argno = fndecl_dealloc_argno (callee_fndecl);
1692 if (dealloc_argno != UINT_MAX)
1694 const deallocator *d
1695 = mutable_this->get_or_create_deallocator (callee_fndecl);
1696 on_deallocator_call (sm_ctxt, node, call, d, dealloc_argno);
1700 if (tree lhs = sm_ctxt->is_zero_assignment (stmt))
1701 if (any_pointer_p (lhs))
1702 on_zero_assignment (sm_ctxt, stmt,lhs);
1704 /* If we have "LHS = &EXPR;" and EXPR is something other than a MEM_REF,
1705 transition LHS from start to non_heap.
1706 Doing it for ADDR_EXPR(MEM_REF()) is likely wrong, and can lead to
1707 unbounded chains of unmergeable sm-state on pointer arithmetic in loops
1708 when optimization is enabled. */
1709 if (const gassign *assign_stmt = dyn_cast <const gassign *> (stmt))
1711 enum tree_code op = gimple_assign_rhs_code (assign_stmt);
1712 if (op == ADDR_EXPR)
1714 tree lhs = gimple_assign_lhs (assign_stmt);
1715 if (lhs)
1717 tree addr_expr = gimple_assign_rhs1 (assign_stmt);
1718 if (TREE_CODE (TREE_OPERAND (addr_expr, 0)) != MEM_REF)
1719 sm_ctxt->on_transition (node, stmt, lhs, m_start, m_non_heap);
1724 /* Handle dereferences. */
1725 for (unsigned i = 0; i < gimple_num_ops (stmt); i++)
1727 tree op = gimple_op (stmt, i);
1728 if (!op)
1729 continue;
1730 if (TREE_CODE (op) == COMPONENT_REF)
1731 op = TREE_OPERAND (op, 0);
1733 if (TREE_CODE (op) == MEM_REF)
1735 tree arg = TREE_OPERAND (op, 0);
1737 state_t state = sm_ctxt->get_state (stmt, arg);
1738 if (unchecked_p (state))
1740 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1741 sm_ctxt->warn (node, stmt, arg,
1742 new possible_null_deref (*this, diag_arg));
1743 const allocation_state *astate = as_a_allocation_state (state);
1744 sm_ctxt->set_next_state (stmt, arg, astate->get_nonnull ());
1746 else if (state == m_null)
1748 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1749 sm_ctxt->warn (node, stmt, arg,
1750 new null_deref (*this, diag_arg));
1751 sm_ctxt->set_next_state (stmt, arg, m_stop);
1753 else if (freed_p (state))
1755 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1756 const allocation_state *astate = as_a_allocation_state (state);
1757 sm_ctxt->warn (node, stmt, arg,
1758 new use_after_free (*this, diag_arg,
1759 astate->m_deallocator));
1760 sm_ctxt->set_next_state (stmt, arg, m_stop);
1764 return false;
1767 /* Handle a call to an allocator.
1768 RETURNS_NONNULL is true if CALL is to a fndecl known to have
1769 __attribute__((returns_nonnull)). */
1771 void
1772 malloc_state_machine::on_allocator_call (sm_context *sm_ctxt,
1773 const gcall *call,
1774 const deallocator_set *deallocators,
1775 bool returns_nonnull) const
1777 tree lhs = gimple_call_lhs (call);
1778 if (lhs)
1780 if (sm_ctxt->get_state (call, lhs) == m_start)
1781 sm_ctxt->set_next_state (call, lhs,
1782 (returns_nonnull
1783 ? deallocators->m_nonnull
1784 : deallocators->m_unchecked));
1786 else
1788 /* TODO: report leak. */
1792 void
1793 malloc_state_machine::on_deallocator_call (sm_context *sm_ctxt,
1794 const supernode *node,
1795 const gcall *call,
1796 const deallocator *d,
1797 unsigned argno) const
1799 if (argno >= gimple_call_num_args (call))
1800 return;
1801 tree arg = gimple_call_arg (call, argno);
1803 state_t state = sm_ctxt->get_state (call, arg);
1805 /* start/unchecked/nonnull -> freed. */
1806 if (state == m_start)
1807 sm_ctxt->set_next_state (call, arg, d->m_freed);
1808 else if (unchecked_p (state) || nonnull_p (state))
1810 const allocation_state *astate = as_a_allocation_state (state);
1811 gcc_assert (astate->m_deallocators);
1812 if (!astate->m_deallocators->contains_p (d))
1814 /* Wrong allocator. */
1815 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1816 pending_diagnostic *pd
1817 = new mismatching_deallocation (*this, diag_arg,
1818 astate->m_deallocators,
1820 sm_ctxt->warn (node, call, arg, pd);
1822 sm_ctxt->set_next_state (call, arg, d->m_freed);
1825 /* Keep state "null" as-is, rather than transitioning to "freed";
1826 we don't want to complain about double-free of NULL. */
1827 else if (state == d->m_freed)
1829 /* freed -> stop, with warning. */
1830 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1831 sm_ctxt->warn (node, call, arg,
1832 new double_free (*this, diag_arg, d->m_name));
1833 sm_ctxt->set_next_state (call, arg, m_stop);
1835 else if (state == m_non_heap)
1837 /* non-heap -> stop, with warning. */
1838 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1839 sm_ctxt->warn (node, call, arg,
1840 new free_of_non_heap (*this, diag_arg,
1841 d->m_name));
1842 sm_ctxt->set_next_state (call, arg, m_stop);
1846 /* Handle a call to "realloc".
1847 Check for free of non-heap or mismatching allocators,
1848 transitioning to the "stop" state for such cases.
1850 Otherwise, region_model::impl_call_realloc will later
1851 get called (which will handle other sm-state transitions
1852 when the state is bifurcated). */
1854 void
1855 malloc_state_machine::on_realloc_call (sm_context *sm_ctxt,
1856 const supernode *node,
1857 const gcall *call) const
1859 const unsigned argno = 0;
1860 const deallocator *d = &m_realloc;
1862 tree arg = gimple_call_arg (call, argno);
1864 state_t state = sm_ctxt->get_state (call, arg);
1866 if (unchecked_p (state) || nonnull_p (state))
1868 const allocation_state *astate = as_a_allocation_state (state);
1869 gcc_assert (astate->m_deallocators);
1870 if (!astate->m_deallocators->contains_p (&m_free.m_deallocator))
1872 /* Wrong allocator. */
1873 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1874 pending_diagnostic *pd
1875 = new mismatching_deallocation (*this, diag_arg,
1876 astate->m_deallocators,
1878 sm_ctxt->warn (node, call, arg, pd);
1879 sm_ctxt->set_next_state (call, arg, m_stop);
1880 if (path_context *path_ctxt = sm_ctxt->get_path_context ())
1881 path_ctxt->terminate_path ();
1884 else if (state == m_free.m_deallocator.m_freed)
1886 /* freed -> stop, with warning. */
1887 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1888 sm_ctxt->warn (node, call, arg,
1889 new double_free (*this, diag_arg, "free"));
1890 sm_ctxt->set_next_state (call, arg, m_stop);
1891 if (path_context *path_ctxt = sm_ctxt->get_path_context ())
1892 path_ctxt->terminate_path ();
1894 else if (state == m_non_heap)
1896 /* non-heap -> stop, with warning. */
1897 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1898 sm_ctxt->warn (node, call, arg,
1899 new free_of_non_heap (*this, diag_arg,
1900 d->m_name));
1901 sm_ctxt->set_next_state (call, arg, m_stop);
1902 if (path_context *path_ctxt = sm_ctxt->get_path_context ())
1903 path_ctxt->terminate_path ();
1907 /* Implementation of state_machine::on_phi vfunc for malloc_state_machine. */
1909 void
1910 malloc_state_machine::on_phi (sm_context *sm_ctxt,
1911 const supernode *node ATTRIBUTE_UNUSED,
1912 const gphi *phi,
1913 tree rhs) const
1915 if (zerop (rhs))
1917 tree lhs = gimple_phi_result (phi);
1918 on_zero_assignment (sm_ctxt, phi, lhs);
1922 /* Implementation of state_machine::on_condition vfunc for malloc_state_machine.
1923 Potentially transition state 'unchecked' to 'nonnull' or to 'null'. */
1925 void
1926 malloc_state_machine::on_condition (sm_context *sm_ctxt,
1927 const supernode *node ATTRIBUTE_UNUSED,
1928 const gimple *stmt,
1929 const svalue *lhs,
1930 enum tree_code op,
1931 const svalue *rhs) const
1933 if (!rhs->all_zeroes_p ())
1934 return;
1936 if (!any_pointer_p (lhs))
1937 return;
1938 if (!any_pointer_p (rhs))
1939 return;
1941 if (op == NE_EXPR)
1943 log ("got 'ARG != 0' match");
1944 state_t s = sm_ctxt->get_state (stmt, lhs);
1945 if (unchecked_p (s))
1947 const allocation_state *astate = as_a_allocation_state (s);
1948 sm_ctxt->set_next_state (stmt, lhs, astate->get_nonnull ());
1951 else if (op == EQ_EXPR)
1953 log ("got 'ARG == 0' match");
1954 state_t s = sm_ctxt->get_state (stmt, lhs);
1955 if (unchecked_p (s))
1956 sm_ctxt->set_next_state (stmt, lhs, m_null);
1960 /* Implementation of state_machine::can_purge_p vfunc for malloc_state_machine.
1961 Don't allow purging of pointers in state 'unchecked' or 'nonnull'
1962 (to avoid false leak reports). */
1964 bool
1965 malloc_state_machine::can_purge_p (state_t s) const
1967 enum resource_state rs = get_rs (s);
1968 return rs != RS_UNCHECKED && rs != RS_NONNULL;
1971 /* Implementation of state_machine::on_leak vfunc for malloc_state_machine
1972 (for complaining about leaks of pointers in state 'unchecked' and
1973 'nonnull'). */
1975 pending_diagnostic *
1976 malloc_state_machine::on_leak (tree var) const
1978 return new malloc_leak (*this, var);
1981 /* Implementation of state_machine::reset_when_passed_to_unknown_fn_p vfunc
1982 for malloc_state_machine. */
1984 bool
1985 malloc_state_machine::reset_when_passed_to_unknown_fn_p (state_t s,
1986 bool is_mutable) const
1988 /* An on-stack ptr doesn't stop being stack-allocated when passed to an
1989 unknown fn. */
1990 if (s == m_non_heap)
1991 return false;
1993 /* Otherwise, pointers passed as non-const can be freed. */
1994 return is_mutable;
1997 /* Return true if calls to FNDECL are known to not affect this sm-state. */
1999 bool
2000 malloc_state_machine::unaffected_by_call_p (tree fndecl)
2002 /* A set of functions that are known to not affect allocation
2003 status, even if we haven't fully modelled the rest of their
2004 behavior yet. */
2005 static const char * const funcnames[] = {
2006 /* This array must be kept sorted. */
2007 "strsep",
2009 const size_t count
2010 = sizeof(funcnames) / sizeof (funcnames[0]);
2011 function_set fs (funcnames, count);
2013 if (fs.contains_decl_p (fndecl))
2014 return true;
2016 return false;
2019 /* Shared logic for handling GIMPLE_ASSIGNs and GIMPLE_PHIs that
2020 assign zero to LHS. */
2022 void
2023 malloc_state_machine::on_zero_assignment (sm_context *sm_ctxt,
2024 const gimple *stmt,
2025 tree lhs) const
2027 state_t s = sm_ctxt->get_state (stmt, lhs);
2028 enum resource_state rs = get_rs (s);
2029 if (rs == RS_START
2030 || rs == RS_UNCHECKED
2031 || rs == RS_NONNULL
2032 || rs == RS_FREED)
2033 sm_ctxt->set_next_state (stmt, lhs, m_null);
2036 /* Special-case hook for handling realloc, for the "success with move to
2037 a new buffer" case, marking OLD_PTR_SVAL as freed and NEW_PTR_SVAL as
2038 non-null.
2040 This is similar to on_deallocator_call and on_allocator_call,
2041 but the checks happen in on_realloc_call, and by splitting the states. */
2043 void
2044 malloc_state_machine::
2045 on_realloc_with_move (region_model *model,
2046 sm_state_map *smap,
2047 const svalue *old_ptr_sval,
2048 const svalue *new_ptr_sval,
2049 const extrinsic_state &ext_state) const
2051 smap->set_state (model, old_ptr_sval,
2052 m_free.m_deallocator.m_freed,
2053 NULL, ext_state);
2055 smap->set_state (model, new_ptr_sval,
2056 m_free.m_nonnull,
2057 NULL, ext_state);
2060 } // anonymous namespace
2062 /* Internal interface to this file. */
2064 state_machine *
2065 make_malloc_state_machine (logger *logger)
2067 return new malloc_state_machine (logger);
2070 /* Specialcase hook for handling realloc, for use by
2071 region_model::impl_call_realloc::success_with_move::update_model. */
2073 void
2074 region_model::on_realloc_with_move (const call_details &cd,
2075 const svalue *old_ptr_sval,
2076 const svalue *new_ptr_sval)
2078 region_model_context *ctxt = cd.get_ctxt ();
2079 if (!ctxt)
2080 return;
2081 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2082 if (!ext_state)
2083 return;
2085 sm_state_map *smap;
2086 const state_machine *sm;
2087 unsigned sm_idx;
2088 if (!ctxt->get_malloc_map (&smap, &sm, &sm_idx))
2089 return;
2091 gcc_assert (smap);
2092 gcc_assert (sm);
2094 const malloc_state_machine &malloc_sm
2095 = (const malloc_state_machine &)*sm;
2097 malloc_sm.on_realloc_with_move (this,
2098 smap,
2099 old_ptr_sval,
2100 new_ptr_sval,
2101 *ext_state);
2104 } // namespace ana
2106 #endif /* #if ENABLE_ANALYZER */