]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/analyzer/sm-malloc.cc
Add -fdiagnostics-format={json-stderr|json-file}
[thirdparty/gcc.git] / gcc / analyzer / sm-malloc.cc
CommitLineData
757bf1df 1/* A state machine for detecting misuses of the malloc/free API.
7adcbafe 2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
757bf1df
DM
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tree.h"
25#include "function.h"
26#include "basic-block.h"
27#include "gimple.h"
28#include "options.h"
29#include "bitmap.h"
30#include "diagnostic-path.h"
31#include "diagnostic-metadata.h"
32#include "function.h"
809192e7 33#include "json.h"
757bf1df
DM
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"
808f4dfe
DM
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"
c7e276b8
DM
45#include "stringpool.h"
46#include "attribs.h"
cd323d97 47#include "analyzer/function-set.h"
eafa9d96 48#include "analyzer/program-state.h"
757bf1df
DM
49
50#if ENABLE_ANALYZER
51
75038aa6
DM
52namespace ana {
53
757bf1df
DM
54namespace {
55
c7e276b8
DM
56/* This state machine and its various support classes track allocations
57 and deallocations.
58
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))).
62
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.
69
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. */
78
79class deallocator;
80class deallocator_set;
1690a839
DM
81class malloc_state_machine;
82
83/* An enum for discriminating between different kinds of allocation_state. */
84
85enum resource_state
86{
c7e276b8 87 /* States that are independent of allocator/deallocator. */
1690a839
DM
88
89 /* The start state. */
90 RS_START,
91
92 /* State for a pointer that's known to be NULL. */
93 RS_NULL,
94
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,
98
99 /* Stop state, for pointers we don't want to track any more. */
100 RS_STOP,
101
c7e276b8 102 /* States that relate to a specific deallocator_set. */
1690a839 103
c7e276b8 104 /* State for a pointer returned from an allocator that hasn't
1690a839
DM
105 been checked for NULL.
106 It could be a pointer to heap-allocated memory, or could be NULL. */
107 RS_UNCHECKED,
108
c7e276b8 109 /* State for a pointer returned from an allocator,
1690a839
DM
110 known to be non-NULL. */
111 RS_NONNULL,
112
c7e276b8 113 /* State for a pointer passed to a deallocator. */
1690a839
DM
114 RS_FREED
115};
116
c7e276b8
DM
117/* Custom state subclass, which can optionally refer to an a
118 deallocator_set. */
1690a839
DM
119
120struct allocation_state : public state_machine::state
121{
122 allocation_state (const char *name, unsigned id,
c7e276b8
DM
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)
1690a839
DM
129 {}
130
ff171cb1 131 void dump_to_pp (pretty_printer *pp) const final override;
1690a839
DM
132
133 const allocation_state *get_nonnull () const;
134
135 enum resource_state m_rs;
c7e276b8
DM
136 const deallocator_set *m_deallocators;
137 const deallocator *m_deallocator;
1690a839
DM
138};
139
140/* An enum for choosing which wording to use in various diagnostics
141 when describing deallocations. */
142
143enum wording
144{
145 WORDING_FREED,
c7e276b8 146 WORDING_DELETED,
a6baafca
DM
147 WORDING_DEALLOCATED,
148 WORDING_REALLOCATED
1690a839
DM
149};
150
c7e276b8
DM
151/* Base class representing a deallocation function,
152 either a built-in one we know about, or one exposed via
153 __attribute__((malloc(DEALLOCATOR))). */
1690a839 154
c7e276b8 155struct deallocator
1690a839 156{
c7e276b8
DM
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 *);
1690a839 161
c7e276b8 162 /* Name to use in diagnostics. */
1690a839
DM
163 const char *m_name;
164
c7e276b8
DM
165 /* Which wording to use in diagnostics. */
166 enum wording m_wording;
167
168 /* State for a value passed to one of the deallocators. */
169 state_machine::state_t m_freed;
170
171protected:
172 deallocator (malloc_state_machine *sm,
173 const char *name,
174 enum wording wording);
175};
176
177/* Subclass representing a predefined deallocator.
178 e.g. "delete []", without needing a specific FUNCTION_DECL
179 ahead of time. */
180
181struct standard_deallocator : public deallocator
182{
183 standard_deallocator (malloc_state_machine *sm,
184 const char *name,
185 enum wording wording);
186};
187
188/* Subclass representing a user-defined deallocator
189 via __attribute__((malloc(DEALLOCATOR))) given
190 a specific FUNCTION_DECL. */
191
192struct custom_deallocator : public deallocator
193{
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)
199 {
200 }
201};
202
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"). */
207
208struct deallocator_set
209{
210 deallocator_set (malloc_state_machine *sm,
211 enum wording wording);
212 virtual ~deallocator_set () {}
213
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;
1690a839
DM
218
219 /* Which wording to use in diagnostics. */
220 enum wording m_wording;
221
c7e276b8 222 /* Pointers to states.
1690a839
DM
223 These states are owned by the state_machine base class. */
224
c7e276b8 225 /* State for an unchecked result from an allocator using this set. */
1690a839
DM
226 state_machine::state_t m_unchecked;
227
c7e276b8 228 /* State for a known non-NULL result from such an allocator. */
1690a839 229 state_machine::state_t m_nonnull;
c7e276b8 230};
1690a839 231
c7e276b8
DM
232/* Subclass of deallocator_set representing a set of deallocators
233 defined by one or more __attribute__((malloc(DEALLOCATOR))). */
234
235struct custom_deallocator_set : public deallocator_set
236{
237 typedef const auto_vec <const deallocator *> *key_t;
238
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);
245
ff171cb1
DM
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;
c7e276b8
DM
249
250 auto_vec <const deallocator *> m_deallocator_vec;
251};
252
253/* Subclass of deallocator_set representing a set of deallocators
254 with a single standard_deallocator, e.g. "delete []". */
255
256struct standard_deallocator_set : public deallocator_set
257{
258 standard_deallocator_set (malloc_state_machine *sm,
259 const char *name,
260 enum wording wording);
261
ff171cb1
DM
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;
c7e276b8
DM
265
266 standard_deallocator m_deallocator;
267};
268
269/* Traits class for ensuring uniqueness of deallocator_sets within
270 malloc_state_machine. */
271
272struct deallocator_set_map_traits
273{
274 typedef custom_deallocator_set::key_t key_type;
275 typedef custom_deallocator_set *value_type;
276 typedef custom_deallocator_set *compare_type;
277
278 static inline hashval_t hash (const key_type &k)
279 {
280 gcc_assert (k != NULL);
281 gcc_assert (k != reinterpret_cast<key_type> (1));
282
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;
289 }
290 static inline bool equal_keys (const key_type &k1, const key_type &k2)
291 {
292 if (k1->length () != k2->length ())
293 return false;
294
295 for (unsigned i = 0; i < k1->length (); i++)
296 if ((*k1)[i] != (*k2)[i])
297 return false;
298
299 return true;
300 }
301 template <typename T>
302 static inline void remove (T &)
303 {
304 /* empty; the nodes are handled elsewhere. */
305 }
306 template <typename T>
307 static inline void mark_deleted (T &entry)
308 {
309 entry.m_key = reinterpret_cast<key_type> (1);
310 }
311 template <typename T>
312 static inline void mark_empty (T &entry)
313 {
314 entry.m_key = NULL;
315 }
316 template <typename T>
317 static inline bool is_deleted (const T &entry)
318 {
319 return entry.m_key == reinterpret_cast<key_type> (1);
320 }
321 template <typename T>
322 static inline bool is_empty (const T &entry)
323 {
324 return entry.m_key == NULL;
325 }
326 static const bool empty_zero_p = false;
1690a839
DM
327};
328
757bf1df
DM
329/* A state machine for detecting misuses of the malloc/free API.
330
331 See sm-malloc.dot for an overview (keep this in-sync with that file). */
332
333class malloc_state_machine : public state_machine
334{
335public:
1690a839
DM
336 typedef allocation_state custom_data_t;
337
757bf1df 338 malloc_state_machine (logger *logger);
c7e276b8 339 ~malloc_state_machine ();
757bf1df 340
1690a839 341 state_t
c7e276b8
DM
342 add_state (const char *name, enum resource_state rs,
343 const deallocator_set *deallocators,
344 const deallocator *deallocator);
1690a839 345
ff171cb1 346 bool inherited_state_p () const final override { return false; }
757bf1df 347
808f4dfe 348 state_machine::state_t
ff171cb1 349 get_default_state (const svalue *sval) const final override
808f4dfe
DM
350 {
351 if (tree cst = sval->maybe_get_constant ())
352 {
353 if (zerop (cst))
354 return m_null;
355 }
356 if (const region_svalue *ptr = sval->dyn_cast_region_svalue ())
357 {
358 const region *reg = ptr->get_pointee ();
a61aaee6
DM
359 switch (reg->get_memory_space ())
360 {
361 default:
362 break;
363 case MEMSPACE_CODE:
364 case MEMSPACE_GLOBALS:
365 case MEMSPACE_STACK:
366 case MEMSPACE_READONLY_DATA:
367 return m_non_heap;
368 }
808f4dfe
DM
369 }
370 return m_start;
371 }
372
757bf1df
DM
373 bool on_stmt (sm_context *sm_ctxt,
374 const supernode *node,
ff171cb1 375 const gimple *stmt) const final override;
757bf1df 376
8525d1f5
DM
377 void on_phi (sm_context *sm_ctxt,
378 const supernode *node,
379 const gphi *phi,
ff171cb1 380 tree rhs) const final override;
8525d1f5 381
757bf1df
DM
382 void on_condition (sm_context *sm_ctxt,
383 const supernode *node,
384 const gimple *stmt,
48e8a7a6 385 const svalue *lhs,
757bf1df 386 enum tree_code op,
ff171cb1 387 const svalue *rhs) const final override;
757bf1df 388
ff171cb1
DM
389 bool can_purge_p (state_t s) const final override;
390 pending_diagnostic *on_leak (tree var) const final override;
757bf1df 391
808f4dfe 392 bool reset_when_passed_to_unknown_fn_p (state_t s,
ff171cb1 393 bool is_mutable) const final override;
808f4dfe 394
cd323d97
DM
395 static bool unaffected_by_call_p (tree fndecl);
396
eafa9d96
DM
397 void on_realloc_with_move (region_model *model,
398 sm_state_map *smap,
399 const svalue *old_ptr_sval,
400 const svalue *new_ptr_sval,
401 const extrinsic_state &ext_state) const;
402
c7e276b8
DM
403 standard_deallocator_set m_free;
404 standard_deallocator_set m_scalar_delete;
405 standard_deallocator_set m_vector_delete;
1690a839 406
a6baafca
DM
407 standard_deallocator m_realloc;
408
1690a839 409 /* States that are independent of api. */
757bf1df
DM
410
411 /* State for a pointer that's known to be NULL. */
412 state_t m_null;
413
757bf1df
DM
414 /* State for a pointer that's known to not be on the heap (e.g. to a local
415 or global). */
416 state_t m_non_heap; // TODO: or should this be a different state machine?
417 // or do we need child values etc?
418
419 /* Stop state, for pointers we don't want to track any more. */
420 state_t m_stop;
8525d1f5
DM
421
422private:
c7e276b8
DM
423 const custom_deallocator_set *
424 get_or_create_custom_deallocator_set (tree allocator_fndecl);
425 custom_deallocator_set *
426 maybe_create_custom_deallocator_set (tree allocator_fndecl);
427 const deallocator *
428 get_or_create_deallocator (tree deallocator_fndecl);
429
1690a839
DM
430 void on_allocator_call (sm_context *sm_ctxt,
431 const gcall *call,
c7e276b8
DM
432 const deallocator_set *deallocators,
433 bool returns_nonnull = false) const;
a61aaee6
DM
434 void handle_free_of_non_heap (sm_context *sm_ctxt,
435 const supernode *node,
436 const gcall *call,
437 tree arg,
438 const deallocator *d) const;
1690a839
DM
439 void on_deallocator_call (sm_context *sm_ctxt,
440 const supernode *node,
441 const gcall *call,
c7e276b8
DM
442 const deallocator *d,
443 unsigned argno) const;
a6baafca
DM
444 void on_realloc_call (sm_context *sm_ctxt,
445 const supernode *node,
446 const gcall *call) const;
8525d1f5 447 void on_zero_assignment (sm_context *sm_ctxt,
8525d1f5
DM
448 const gimple *stmt,
449 tree lhs) const;
c7e276b8
DM
450
451 /* A map for consolidating deallocators so that they are
452 unique per deallocator FUNCTION_DECL. */
453 typedef hash_map<tree, deallocator *> deallocator_map_t;
454 deallocator_map_t m_deallocator_map;
455
456 /* Memoized lookups from FUNCTION_DECL to custom_deallocator_set *. */
457 typedef hash_map<tree, custom_deallocator_set *> deallocator_set_cache_t;
458 deallocator_set_cache_t m_custom_deallocator_set_cache;
459
460 /* A map for consolidating custom_deallocator_set instances. */
461 typedef hash_map<custom_deallocator_set::key_t,
462 custom_deallocator_set *,
463 deallocator_set_map_traits> custom_deallocator_set_map_t;
464 custom_deallocator_set_map_t m_custom_deallocator_set_map;
465
466 /* Record of dynamically-allocated objects, for cleanup. */
467 auto_vec <custom_deallocator_set *> m_dynamic_sets;
468 auto_vec <custom_deallocator *> m_dynamic_deallocators;
757bf1df
DM
469};
470
c7e276b8 471/* struct deallocator. */
1690a839 472
c7e276b8
DM
473deallocator::deallocator (malloc_state_machine *sm,
474 const char *name,
475 enum wording wording)
1690a839 476: m_name (name),
1690a839 477 m_wording (wording),
c7e276b8
DM
478 m_freed (sm->add_state ("freed", RS_FREED, NULL, this))
479{
480}
481
482hashval_t
483deallocator::hash () const
484{
485 return (hashval_t)m_freed->get_id ();
486}
487
488void
489deallocator::dump_to_pp (pretty_printer *pp) const
490{
491 pp_printf (pp, "%qs", m_name);
492}
493
494int
495deallocator::cmp (const deallocator *a, const deallocator *b)
496{
497 return (int)a->m_freed->get_id () - (int)b->m_freed->get_id ();
498}
499
500int
501deallocator::cmp_ptr_ptr (const void *a, const void *b)
502{
503 return cmp (*(const deallocator * const *)a,
504 *(const deallocator * const *)b);
505}
506
507
508/* struct standard_deallocator : public deallocator. */
509
510standard_deallocator::standard_deallocator (malloc_state_machine *sm,
511 const char *name,
512 enum wording wording)
513: deallocator (sm, name, wording)
1690a839
DM
514{
515}
516
c7e276b8
DM
517/* struct deallocator_set. */
518
519deallocator_set::deallocator_set (malloc_state_machine *sm,
520 enum wording wording)
521: m_wording (wording),
522 m_unchecked (sm->add_state ("unchecked", RS_UNCHECKED, this, NULL)),
523 m_nonnull (sm->add_state ("nonnull", RS_NONNULL, this, NULL))
524{
525}
526
527/* Dump a description of this deallocator_set to stderr. */
528
529DEBUG_FUNCTION void
530deallocator_set::dump () const
531{
532 pretty_printer pp;
533 pp_show_color (&pp) = pp_show_color (global_dc->printer);
534 pp.buffer->stream = stderr;
535 dump_to_pp (&pp);
536 pp_newline (&pp);
537 pp_flush (&pp);
538}
539
540/* struct custom_deallocator_set : public deallocator_set. */
541
542custom_deallocator_set::
543custom_deallocator_set (malloc_state_machine *sm,
544 const auto_vec <const deallocator *> *vec,
545 enum wording wording)
546: deallocator_set (sm, wording),
547 m_deallocator_vec (vec->length ())
548{
549 unsigned i;
550 const deallocator *d;
551 FOR_EACH_VEC_ELT (*vec, i, d)
552 m_deallocator_vec.safe_push (d);
553}
554
555bool
556custom_deallocator_set::contains_p (const deallocator *d) const
557{
558 unsigned i;
559 const deallocator *cd;
560 FOR_EACH_VEC_ELT (m_deallocator_vec, i, cd)
561 if (cd == d)
562 return true;
563 return false;
564}
565
566const deallocator *
567custom_deallocator_set::maybe_get_single () const
568{
569 if (m_deallocator_vec.length () == 1)
570 return m_deallocator_vec[0];
571 return NULL;
572}
573
574void
575custom_deallocator_set::dump_to_pp (pretty_printer *pp) const
576{
577 pp_character (pp, '{');
578 unsigned i;
579 const deallocator *d;
580 FOR_EACH_VEC_ELT (m_deallocator_vec, i, d)
581 {
582 if (i > 0)
583 pp_string (pp, ", ");
584 d->dump_to_pp (pp);
585 }
586 pp_character (pp, '}');
587}
588
589/* struct standard_deallocator_set : public deallocator_set. */
590
591standard_deallocator_set::standard_deallocator_set (malloc_state_machine *sm,
592 const char *name,
593 enum wording wording)
594: deallocator_set (sm, wording),
595 m_deallocator (sm, name, wording)
596{
597}
598
599bool
600standard_deallocator_set::contains_p (const deallocator *d) const
601{
602 return d == &m_deallocator;
603}
604
605const deallocator *
606standard_deallocator_set::maybe_get_single () const
607{
608 return &m_deallocator;
609}
610
611void
612standard_deallocator_set::dump_to_pp (pretty_printer *pp) const
613{
614 pp_character (pp, '{');
615 pp_string (pp, m_deallocator.m_name);
616 pp_character (pp, '}');
617}
618
1690a839
DM
619/* Return STATE cast to the custom state subclass, or NULL for the start state.
620 Everything should be an allocation_state apart from the start state. */
621
622static const allocation_state *
623dyn_cast_allocation_state (state_machine::state_t state)
624{
625 if (state->get_id () == 0)
626 return NULL;
627 return static_cast <const allocation_state *> (state);
628}
629
630/* Return STATE cast to the custom state subclass, for a state that is
631 already known to not be the start state . */
632
633static const allocation_state *
634as_a_allocation_state (state_machine::state_t state)
635{
636 gcc_assert (state->get_id () != 0);
637 return static_cast <const allocation_state *> (state);
638}
639
640/* Get the resource_state for STATE. */
641
642static enum resource_state
643get_rs (state_machine::state_t state)
644{
645 if (const allocation_state *astate = dyn_cast_allocation_state (state))
646 return astate->m_rs;
647 else
648 return RS_START;
649}
650
c7e276b8
DM
651/* Return true if STATE is the start state. */
652
653static bool
654start_p (state_machine::state_t state)
655{
656 return get_rs (state) == RS_START;
657}
658
1690a839
DM
659/* Return true if STATE is an unchecked result from an allocator. */
660
661static bool
662unchecked_p (state_machine::state_t state)
663{
664 return get_rs (state) == RS_UNCHECKED;
665}
666
667/* Return true if STATE is a non-null result from an allocator. */
668
669static bool
670nonnull_p (state_machine::state_t state)
671{
672 return get_rs (state) == RS_NONNULL;
673}
674
675/* Return true if STATE is a value that has been passed to a deallocator. */
676
677static bool
678freed_p (state_machine::state_t state)
679{
680 return get_rs (state) == RS_FREED;
681}
682
757bf1df
DM
683/* Class for diagnostics relating to malloc_state_machine. */
684
685class malloc_diagnostic : public pending_diagnostic
686{
687public:
688 malloc_diagnostic (const malloc_state_machine &sm, tree arg)
689 : m_sm (sm), m_arg (arg)
690 {}
691
ff171cb1 692 bool subclass_equal_p (const pending_diagnostic &base_other) const override
757bf1df 693 {
14f9d7b9 694 return same_tree_p (m_arg, ((const malloc_diagnostic &)base_other).m_arg);
757bf1df
DM
695 }
696
697 label_text describe_state_change (const evdesc::state_change &change)
ff171cb1 698 override
757bf1df 699 {
10fc42a8 700 if (change.m_old_state == m_sm.get_start_state ()
1690a839 701 && unchecked_p (change.m_new_state))
757bf1df
DM
702 // TODO: verify that it's the allocation stmt, not a copy
703 return label_text::borrow ("allocated here");
1690a839
DM
704 if (unchecked_p (change.m_old_state)
705 && nonnull_p (change.m_new_state))
808f4dfe
DM
706 {
707 if (change.m_expr)
708 return change.formatted_print ("assuming %qE is non-NULL",
709 change.m_expr);
710 else
711 return change.formatted_print ("assuming %qs is non-NULL",
712 "<unknown>");
713 }
757bf1df 714 if (change.m_new_state == m_sm.m_null)
0993ad65 715 {
1690a839 716 if (unchecked_p (change.m_old_state))
808f4dfe
DM
717 {
718 if (change.m_expr)
719 return change.formatted_print ("assuming %qE is NULL",
720 change.m_expr);
721 else
722 return change.formatted_print ("assuming %qs is NULL",
723 "<unknown>");
724 }
0993ad65 725 else
808f4dfe
DM
726 {
727 if (change.m_expr)
728 return change.formatted_print ("%qE is NULL",
729 change.m_expr);
730 else
731 return change.formatted_print ("%qs is NULL",
732 "<unknown>");
733 }
0993ad65
DM
734 }
735
757bf1df
DM
736 return label_text ();
737 }
738
739protected:
740 const malloc_state_machine &m_sm;
741 tree m_arg;
742};
743
1690a839
DM
744/* Concrete subclass for reporting mismatching allocator/deallocator
745 diagnostics. */
746
747class mismatching_deallocation : public malloc_diagnostic
748{
749public:
750 mismatching_deallocation (const malloc_state_machine &sm, tree arg,
c7e276b8
DM
751 const deallocator_set *expected_deallocators,
752 const deallocator *actual_dealloc)
1690a839 753 : malloc_diagnostic (sm, arg),
c7e276b8 754 m_expected_deallocators (expected_deallocators),
1690a839
DM
755 m_actual_dealloc (actual_dealloc)
756 {}
757
ff171cb1 758 const char *get_kind () const final override
1690a839
DM
759 {
760 return "mismatching_deallocation";
761 }
762
ff171cb1 763 int get_controlling_option () const final override
7fd6e36e
DM
764 {
765 return OPT_Wanalyzer_mismatching_deallocation;
766 }
767
ff171cb1 768 bool emit (rich_location *rich_loc) final override
1690a839
DM
769 {
770 auto_diagnostic_group d;
771 diagnostic_metadata m;
772 m.add_cwe (762); /* CWE-762: Mismatched Memory Management Routines. */
c7e276b8
DM
773 if (const deallocator *expected_dealloc
774 = m_expected_deallocators->maybe_get_single ())
7fd6e36e 775 return warning_meta (rich_loc, m, get_controlling_option (),
c7e276b8
DM
776 "%qE should have been deallocated with %qs"
777 " but was deallocated with %qs",
778 m_arg, expected_dealloc->m_name,
779 m_actual_dealloc->m_name);
780 else
7fd6e36e 781 return warning_meta (rich_loc, m, get_controlling_option (),
c7e276b8
DM
782 "%qs called on %qE returned from a mismatched"
783 " allocation function",
784 m_actual_dealloc->m_name, m_arg);
1690a839
DM
785 }
786
787 label_text describe_state_change (const evdesc::state_change &change)
ff171cb1 788 final override
1690a839
DM
789 {
790 if (unchecked_p (change.m_new_state))
791 {
792 m_alloc_event = change.m_event_id;
c7e276b8
DM
793 if (const deallocator *expected_dealloc
794 = m_expected_deallocators->maybe_get_single ())
795 return change.formatted_print ("allocated here"
796 " (expects deallocation with %qs)",
797 expected_dealloc->m_name);
798 else
799 return change.formatted_print ("allocated here");
1690a839
DM
800 }
801 return malloc_diagnostic::describe_state_change (change);
802 }
803
ff171cb1 804 label_text describe_final_event (const evdesc::final_event &ev) final override
1690a839
DM
805 {
806 if (m_alloc_event.known_p ())
c7e276b8
DM
807 {
808 if (const deallocator *expected_dealloc
809 = m_expected_deallocators->maybe_get_single ())
810 return ev.formatted_print
811 ("deallocated with %qs here;"
812 " allocation at %@ expects deallocation with %qs",
813 m_actual_dealloc->m_name, &m_alloc_event,
814 expected_dealloc->m_name);
815 else
816 return ev.formatted_print
817 ("deallocated with %qs here;"
818 " allocated at %@",
819 m_actual_dealloc->m_name, &m_alloc_event);
820 }
1690a839 821 return ev.formatted_print ("deallocated with %qs here",
c7e276b8 822 m_actual_dealloc->m_name);
1690a839
DM
823 }
824
825private:
826 diagnostic_event_id_t m_alloc_event;
c7e276b8
DM
827 const deallocator_set *m_expected_deallocators;
828 const deallocator *m_actual_dealloc;
1690a839
DM
829};
830
757bf1df
DM
831/* Concrete subclass for reporting double-free diagnostics. */
832
833class double_free : public malloc_diagnostic
834{
835public:
1690a839
DM
836 double_free (const malloc_state_machine &sm, tree arg, const char *funcname)
837 : malloc_diagnostic (sm, arg), m_funcname (funcname)
757bf1df
DM
838 {}
839
ff171cb1 840 const char *get_kind () const final override { return "double_free"; }
757bf1df 841
ff171cb1 842 int get_controlling_option () const final override
7fd6e36e
DM
843 {
844 return OPT_Wanalyzer_double_free;
845 }
846
ff171cb1 847 bool emit (rich_location *rich_loc) final override
757bf1df
DM
848 {
849 auto_diagnostic_group d;
850 diagnostic_metadata m;
851 m.add_cwe (415); /* CWE-415: Double Free. */
7fd6e36e 852 return warning_meta (rich_loc, m, get_controlling_option (),
c7e276b8 853 "double-%qs of %qE", m_funcname, m_arg);
757bf1df
DM
854 }
855
856 label_text describe_state_change (const evdesc::state_change &change)
ff171cb1 857 final override
757bf1df 858 {
1690a839 859 if (freed_p (change.m_new_state))
757bf1df
DM
860 {
861 m_first_free_event = change.m_event_id;
1690a839 862 return change.formatted_print ("first %qs here", m_funcname);
757bf1df
DM
863 }
864 return malloc_diagnostic::describe_state_change (change);
865 }
866
867 label_text describe_call_with_state (const evdesc::call_with_state &info)
ff171cb1 868 final override
757bf1df 869 {
1690a839 870 if (freed_p (info.m_state))
757bf1df
DM
871 return info.formatted_print
872 ("passing freed pointer %qE in call to %qE from %qE",
873 info.m_expr, info.m_callee_fndecl, info.m_caller_fndecl);
874 return label_text ();
875 }
876
ff171cb1 877 label_text describe_final_event (const evdesc::final_event &ev) final override
757bf1df
DM
878 {
879 if (m_first_free_event.known_p ())
880 return ev.formatted_print ("second %qs here; first %qs was at %@",
1690a839 881 m_funcname, m_funcname,
757bf1df 882 &m_first_free_event);
1690a839 883 return ev.formatted_print ("second %qs here", m_funcname);
757bf1df
DM
884 }
885
886private:
887 diagnostic_event_id_t m_first_free_event;
1690a839 888 const char *m_funcname;
757bf1df
DM
889};
890
891/* Abstract subclass for describing possible bad uses of NULL.
892 Responsible for describing the call that could return NULL. */
893
894class possible_null : public malloc_diagnostic
895{
896public:
897 possible_null (const malloc_state_machine &sm, tree arg)
898 : malloc_diagnostic (sm, arg)
899 {}
900
901 label_text describe_state_change (const evdesc::state_change &change)
ff171cb1 902 final override
757bf1df 903 {
10fc42a8 904 if (change.m_old_state == m_sm.get_start_state ()
1690a839 905 && unchecked_p (change.m_new_state))
757bf1df
DM
906 {
907 m_origin_of_unchecked_event = change.m_event_id;
908 return label_text::borrow ("this call could return NULL");
909 }
910 return malloc_diagnostic::describe_state_change (change);
911 }
912
913 label_text describe_return_of_state (const evdesc::return_of_state &info)
ff171cb1 914 final override
757bf1df 915 {
1690a839 916 if (unchecked_p (info.m_state))
757bf1df
DM
917 return info.formatted_print ("possible return of NULL to %qE from %qE",
918 info.m_caller_fndecl, info.m_callee_fndecl);
919 return label_text ();
920 }
921
922protected:
923 diagnostic_event_id_t m_origin_of_unchecked_event;
924};
925
926/* Concrete subclass for describing dereference of a possible NULL
927 value. */
928
929class possible_null_deref : public possible_null
930{
931public:
932 possible_null_deref (const malloc_state_machine &sm, tree arg)
933 : possible_null (sm, arg)
934 {}
935
ff171cb1 936 const char *get_kind () const final override { return "possible_null_deref"; }
757bf1df 937
ff171cb1 938 int get_controlling_option () const final override
7fd6e36e
DM
939 {
940 return OPT_Wanalyzer_possible_null_dereference;
941 }
942
ff171cb1 943 bool emit (rich_location *rich_loc) final override
757bf1df
DM
944 {
945 /* CWE-690: Unchecked Return Value to NULL Pointer Dereference. */
946 diagnostic_metadata m;
947 m.add_cwe (690);
7fd6e36e 948 return warning_meta (rich_loc, m, get_controlling_option (),
6c8e5844 949 "dereference of possibly-NULL %qE", m_arg);
757bf1df
DM
950 }
951
ff171cb1 952 label_text describe_final_event (const evdesc::final_event &ev) final override
757bf1df
DM
953 {
954 if (m_origin_of_unchecked_event.known_p ())
955 return ev.formatted_print ("%qE could be NULL: unchecked value from %@",
956 ev.m_expr,
957 &m_origin_of_unchecked_event);
958 else
959 return ev.formatted_print ("%qE could be NULL", ev.m_expr);
960 }
961
962};
963
2f7c50b7
DM
964/* Return true if FNDECL is a C++ method. */
965
966static bool
967method_p (tree fndecl)
968{
969 return TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE;
970}
971
972/* Return a 1-based description of ARG_IDX (0-based) of FNDECL.
e53b6e56 973 Compare with %P in the C++ FE (implemented in cp/error.cc: parm_to_string
2f7c50b7
DM
974 as called from cp_printer). */
975
976static label_text
977describe_argument_index (tree fndecl, int arg_idx)
978{
979 if (method_p (fndecl))
980 if (arg_idx == 0)
981 return label_text::borrow ("'this'");
982 pretty_printer pp;
983 pp_printf (&pp, "%u", arg_idx + 1 - method_p (fndecl));
984 return label_text::take (xstrdup (pp_formatted_text (&pp)));
985}
986
757bf1df
DM
987/* Subroutine for use by possible_null_arg::emit and null_arg::emit.
988 Issue a note informing that the pertinent argument must be non-NULL. */
989
990static void
991inform_nonnull_attribute (tree fndecl, int arg_idx)
992{
2f7c50b7 993 label_text arg_desc = describe_argument_index (fndecl, arg_idx);
757bf1df 994 inform (DECL_SOURCE_LOCATION (fndecl),
2f7c50b7
DM
995 "argument %s of %qD must be non-null",
996 arg_desc.m_buffer, fndecl);
997 arg_desc.maybe_free ();
757bf1df
DM
998 /* Ideally we would use the location of the parm and underline the
999 attribute also - but we don't have the location_t values at this point
1000 in the middle-end.
1001 For reference, the C and C++ FEs have get_fndecl_argument_location. */
1002}
1003
1004/* Concrete subclass for describing passing a possibly-NULL value to a
1005 function marked with __attribute__((nonnull)). */
1006
1007class possible_null_arg : public possible_null
1008{
1009public:
1010 possible_null_arg (const malloc_state_machine &sm, tree arg,
1011 tree fndecl, int arg_idx)
1012 : possible_null (sm, arg),
1013 m_fndecl (fndecl), m_arg_idx (arg_idx)
1014 {}
1015
ff171cb1 1016 const char *get_kind () const final override { return "possible_null_arg"; }
757bf1df 1017
2ac1459f
DM
1018 bool subclass_equal_p (const pending_diagnostic &base_other)
1019 const final override
757bf1df
DM
1020 {
1021 const possible_null_arg &sub_other
1022 = (const possible_null_arg &)base_other;
14f9d7b9 1023 return (same_tree_p (m_arg, sub_other.m_arg)
757bf1df
DM
1024 && m_fndecl == sub_other.m_fndecl
1025 && m_arg_idx == sub_other.m_arg_idx);
1026 }
1027
ff171cb1 1028 int get_controlling_option () const final override
7fd6e36e
DM
1029 {
1030 return OPT_Wanalyzer_possible_null_argument;
1031 }
757bf1df 1032
ff171cb1 1033 bool emit (rich_location *rich_loc) final override
757bf1df
DM
1034 {
1035 /* CWE-690: Unchecked Return Value to NULL Pointer Dereference. */
1036 auto_diagnostic_group d;
1037 diagnostic_metadata m;
1038 m.add_cwe (690);
1039 bool warned
7fd6e36e 1040 = warning_meta (rich_loc, m, get_controlling_option (),
6c8e5844
DM
1041 "use of possibly-NULL %qE where non-null expected",
1042 m_arg);
757bf1df
DM
1043 if (warned)
1044 inform_nonnull_attribute (m_fndecl, m_arg_idx);
1045 return warned;
1046 }
1047
ff171cb1 1048 label_text describe_final_event (const evdesc::final_event &ev) final override
757bf1df 1049 {
2f7c50b7
DM
1050 label_text arg_desc = describe_argument_index (m_fndecl, m_arg_idx);
1051 label_text result;
757bf1df 1052 if (m_origin_of_unchecked_event.known_p ())
2f7c50b7
DM
1053 result = ev.formatted_print ("argument %s (%qE) from %@ could be NULL"
1054 " where non-null expected",
1055 arg_desc.m_buffer, ev.m_expr,
1056 &m_origin_of_unchecked_event);
757bf1df 1057 else
2f7c50b7
DM
1058 result = ev.formatted_print ("argument %s (%qE) could be NULL"
1059 " where non-null expected",
1060 arg_desc.m_buffer, ev.m_expr);
1061 arg_desc.maybe_free ();
1062 return result;
757bf1df
DM
1063 }
1064
1065private:
1066 tree m_fndecl;
1067 int m_arg_idx;
1068};
1069
1070/* Concrete subclass for describing a dereference of a NULL value. */
1071
1072class null_deref : public malloc_diagnostic
1073{
1074public:
1075 null_deref (const malloc_state_machine &sm, tree arg)
1076 : malloc_diagnostic (sm, arg) {}
1077
ff171cb1 1078 const char *get_kind () const final override { return "null_deref"; }
757bf1df 1079
ff171cb1 1080 int get_controlling_option () const final override
7fd6e36e
DM
1081 {
1082 return OPT_Wanalyzer_null_dereference;
1083 }
1084
ff171cb1 1085 bool emit (rich_location *rich_loc) final override
757bf1df 1086 {
f3f312b5 1087 /* CWE-476: NULL Pointer Dereference. */
757bf1df 1088 diagnostic_metadata m;
f3f312b5 1089 m.add_cwe (476);
7fd6e36e 1090 return warning_meta (rich_loc, m, get_controlling_option (),
6c8e5844 1091 "dereference of NULL %qE", m_arg);
757bf1df
DM
1092 }
1093
1094 label_text describe_return_of_state (const evdesc::return_of_state &info)
ff171cb1 1095 final override
757bf1df
DM
1096 {
1097 if (info.m_state == m_sm.m_null)
1098 return info.formatted_print ("return of NULL to %qE from %qE",
1099 info.m_caller_fndecl, info.m_callee_fndecl);
1100 return label_text ();
1101 }
1102
ff171cb1 1103 label_text describe_final_event (const evdesc::final_event &ev) final override
757bf1df
DM
1104 {
1105 return ev.formatted_print ("dereference of NULL %qE", ev.m_expr);
1106 }
1107};
1108
1109/* Concrete subclass for describing passing a NULL value to a
1110 function marked with __attribute__((nonnull)). */
1111
1112class null_arg : public malloc_diagnostic
1113{
1114public:
1115 null_arg (const malloc_state_machine &sm, tree arg,
1116 tree fndecl, int arg_idx)
1117 : malloc_diagnostic (sm, arg),
1118 m_fndecl (fndecl), m_arg_idx (arg_idx)
1119 {}
1120
ff171cb1 1121 const char *get_kind () const final override { return "null_arg"; }
757bf1df 1122
2ac1459f
DM
1123 bool subclass_equal_p (const pending_diagnostic &base_other)
1124 const final override
757bf1df
DM
1125 {
1126 const null_arg &sub_other
1127 = (const null_arg &)base_other;
14f9d7b9 1128 return (same_tree_p (m_arg, sub_other.m_arg)
757bf1df
DM
1129 && m_fndecl == sub_other.m_fndecl
1130 && m_arg_idx == sub_other.m_arg_idx);
1131 }
1132
ff171cb1 1133 int get_controlling_option () const final override
7fd6e36e
DM
1134 {
1135 return OPT_Wanalyzer_null_argument;
1136 }
1137
ff171cb1 1138 bool emit (rich_location *rich_loc) final override
757bf1df 1139 {
f3f312b5 1140 /* CWE-476: NULL Pointer Dereference. */
757bf1df
DM
1141 auto_diagnostic_group d;
1142 diagnostic_metadata m;
f3f312b5 1143 m.add_cwe (476);
808f4dfe
DM
1144
1145 bool warned;
1146 if (zerop (m_arg))
7fd6e36e 1147 warned = warning_meta (rich_loc, m, get_controlling_option (),
808f4dfe
DM
1148 "use of NULL where non-null expected");
1149 else
7fd6e36e 1150 warned = warning_meta (rich_loc, m, get_controlling_option (),
808f4dfe
DM
1151 "use of NULL %qE where non-null expected",
1152 m_arg);
757bf1df
DM
1153 if (warned)
1154 inform_nonnull_attribute (m_fndecl, m_arg_idx);
1155 return warned;
1156 }
1157
ff171cb1 1158 label_text describe_final_event (const evdesc::final_event &ev) final override
757bf1df 1159 {
2f7c50b7
DM
1160 label_text arg_desc = describe_argument_index (m_fndecl, m_arg_idx);
1161 label_text result;
808f4dfe 1162 if (zerop (ev.m_expr))
2f7c50b7
DM
1163 result = ev.formatted_print ("argument %s NULL where non-null expected",
1164 arg_desc.m_buffer);
808f4dfe 1165 else
2f7c50b7
DM
1166 result = ev.formatted_print ("argument %s (%qE) NULL"
1167 " where non-null expected",
1168 arg_desc.m_buffer, ev.m_expr);
1169 arg_desc.maybe_free ();
1170 return result;
757bf1df
DM
1171 }
1172
1173private:
1174 tree m_fndecl;
1175 int m_arg_idx;
1176};
1177
1178class use_after_free : public malloc_diagnostic
1179{
1180public:
1690a839 1181 use_after_free (const malloc_state_machine &sm, tree arg,
c7e276b8
DM
1182 const deallocator *deallocator)
1183 : malloc_diagnostic (sm, arg),
1184 m_deallocator (deallocator)
1185 {
1186 gcc_assert (deallocator);
1187 }
757bf1df 1188
ff171cb1 1189 const char *get_kind () const final override { return "use_after_free"; }
757bf1df 1190
ff171cb1 1191 int get_controlling_option () const final override
7fd6e36e
DM
1192 {
1193 return OPT_Wanalyzer_use_after_free;
1194 }
1195
ff171cb1 1196 bool emit (rich_location *rich_loc) final override
757bf1df
DM
1197 {
1198 /* CWE-416: Use After Free. */
1199 diagnostic_metadata m;
1200 m.add_cwe (416);
7fd6e36e 1201 return warning_meta (rich_loc, m, get_controlling_option (),
1690a839 1202 "use after %<%s%> of %qE",
c7e276b8 1203 m_deallocator->m_name, m_arg);
757bf1df
DM
1204 }
1205
1206 label_text describe_state_change (const evdesc::state_change &change)
ff171cb1 1207 final override
757bf1df 1208 {
1690a839 1209 if (freed_p (change.m_new_state))
757bf1df
DM
1210 {
1211 m_free_event = change.m_event_id;
c7e276b8 1212 switch (m_deallocator->m_wording)
1690a839
DM
1213 {
1214 default:
a6baafca 1215 case WORDING_REALLOCATED:
1690a839
DM
1216 gcc_unreachable ();
1217 case WORDING_FREED:
1218 return label_text::borrow ("freed here");
1219 case WORDING_DELETED:
1220 return label_text::borrow ("deleted here");
c7e276b8
DM
1221 case WORDING_DEALLOCATED:
1222 return label_text::borrow ("deallocated here");
1690a839 1223 }
757bf1df
DM
1224 }
1225 return malloc_diagnostic::describe_state_change (change);
1226 }
1227
ff171cb1 1228 label_text describe_final_event (const evdesc::final_event &ev) final override
757bf1df 1229 {
c7e276b8 1230 const char *funcname = m_deallocator->m_name;
757bf1df 1231 if (m_free_event.known_p ())
c7e276b8 1232 switch (m_deallocator->m_wording)
1690a839
DM
1233 {
1234 default:
a6baafca 1235 case WORDING_REALLOCATED:
1690a839
DM
1236 gcc_unreachable ();
1237 case WORDING_FREED:
1238 return ev.formatted_print ("use after %<%s%> of %qE; freed at %@",
1239 funcname, ev.m_expr, &m_free_event);
1240 case WORDING_DELETED:
1241 return ev.formatted_print ("use after %<%s%> of %qE; deleted at %@",
1242 funcname, ev.m_expr, &m_free_event);
c7e276b8
DM
1243 case WORDING_DEALLOCATED:
1244 return ev.formatted_print ("use after %<%s%> of %qE;"
1245 " deallocated at %@",
1246 funcname, ev.m_expr, &m_free_event);
1690a839 1247 }
757bf1df 1248 else
1690a839
DM
1249 return ev.formatted_print ("use after %<%s%> of %qE",
1250 funcname, ev.m_expr);
757bf1df
DM
1251 }
1252
33255ad3
DM
1253 /* Implementation of pending_diagnostic::supercedes_p for
1254 use_after_free.
1255
1256 We want use-after-free to supercede use-of-unitialized-value,
1257 so that if we have these at the same stmt, we don't emit
1258 a use-of-uninitialized, just the use-after-free.
1259 (this is because we fully purge information about freed
1260 buffers when we free them to avoid state explosions, so
1261 that if they are accessed after the free, it looks like
1262 they are uninitialized). */
1263
ff171cb1 1264 bool supercedes_p (const pending_diagnostic &other) const final override
33255ad3
DM
1265 {
1266 if (other.use_of_uninit_p ())
1267 return true;
1268
1269 return false;
1270 }
1271
757bf1df
DM
1272private:
1273 diagnostic_event_id_t m_free_event;
c7e276b8 1274 const deallocator *m_deallocator;
757bf1df
DM
1275};
1276
1277class malloc_leak : public malloc_diagnostic
1278{
1279public:
1280 malloc_leak (const malloc_state_machine &sm, tree arg)
1281 : malloc_diagnostic (sm, arg) {}
1282
ff171cb1 1283 const char *get_kind () const final override { return "malloc_leak"; }
757bf1df 1284
ff171cb1 1285 int get_controlling_option () const final override
7fd6e36e
DM
1286 {
1287 return OPT_Wanalyzer_malloc_leak;
1288 }
1289
ff171cb1 1290 bool emit (rich_location *rich_loc) final override
757bf1df
DM
1291 {
1292 diagnostic_metadata m;
1293 m.add_cwe (401);
808f4dfe 1294 if (m_arg)
7fd6e36e 1295 return warning_meta (rich_loc, m, get_controlling_option (),
808f4dfe
DM
1296 "leak of %qE", m_arg);
1297 else
7fd6e36e 1298 return warning_meta (rich_loc, m, get_controlling_option (),
808f4dfe 1299 "leak of %qs", "<unknown>");
757bf1df
DM
1300 }
1301
1302 label_text describe_state_change (const evdesc::state_change &change)
ff171cb1 1303 final override
757bf1df 1304 {
c7e276b8
DM
1305 if (unchecked_p (change.m_new_state)
1306 || (start_p (change.m_old_state) && nonnull_p (change.m_new_state)))
757bf1df 1307 {
1690a839 1308 m_alloc_event = change.m_event_id;
757bf1df
DM
1309 return label_text::borrow ("allocated here");
1310 }
1311 return malloc_diagnostic::describe_state_change (change);
1312 }
1313
ff171cb1 1314 label_text describe_final_event (const evdesc::final_event &ev) final override
757bf1df 1315 {
808f4dfe
DM
1316 if (ev.m_expr)
1317 {
1690a839 1318 if (m_alloc_event.known_p ())
808f4dfe 1319 return ev.formatted_print ("%qE leaks here; was allocated at %@",
1690a839 1320 ev.m_expr, &m_alloc_event);
808f4dfe
DM
1321 else
1322 return ev.formatted_print ("%qE leaks here", ev.m_expr);
1323 }
757bf1df 1324 else
808f4dfe 1325 {
1690a839 1326 if (m_alloc_event.known_p ())
808f4dfe 1327 return ev.formatted_print ("%qs leaks here; was allocated at %@",
1690a839 1328 "<unknown>", &m_alloc_event);
808f4dfe
DM
1329 else
1330 return ev.formatted_print ("%qs leaks here", "<unknown>");
1331 }
757bf1df
DM
1332 }
1333
1334private:
1690a839 1335 diagnostic_event_id_t m_alloc_event;
757bf1df
DM
1336};
1337
1338class free_of_non_heap : public malloc_diagnostic
1339{
1340public:
1690a839 1341 free_of_non_heap (const malloc_state_machine &sm, tree arg,
a61aaee6 1342 const region *freed_reg,
1690a839 1343 const char *funcname)
a61aaee6 1344 : malloc_diagnostic (sm, arg), m_freed_reg (freed_reg), m_funcname (funcname)
757bf1df
DM
1345 {
1346 }
1347
ff171cb1 1348 const char *get_kind () const final override { return "free_of_non_heap"; }
757bf1df
DM
1349
1350 bool subclass_equal_p (const pending_diagnostic &base_other) const
ff171cb1 1351 final override
757bf1df
DM
1352 {
1353 const free_of_non_heap &other = (const free_of_non_heap &)base_other;
a61aaee6
DM
1354 return (same_tree_p (m_arg, other.m_arg)
1355 && m_freed_reg == other.m_freed_reg);
757bf1df
DM
1356 }
1357
ff171cb1 1358 int get_controlling_option () const final override
7fd6e36e
DM
1359 {
1360 return OPT_Wanalyzer_free_of_non_heap;
1361 }
1362
ff171cb1 1363 bool emit (rich_location *rich_loc) final override
757bf1df
DM
1364 {
1365 auto_diagnostic_group d;
1366 diagnostic_metadata m;
1367 m.add_cwe (590); /* CWE-590: Free of Memory not on the Heap. */
a61aaee6 1368 switch (get_memory_space ())
757bf1df
DM
1369 {
1370 default:
a61aaee6 1371 case MEMSPACE_HEAP:
757bf1df 1372 gcc_unreachable ();
a61aaee6
DM
1373 case MEMSPACE_UNKNOWN:
1374 case MEMSPACE_CODE:
1375 case MEMSPACE_GLOBALS:
1376 case MEMSPACE_READONLY_DATA:
7fd6e36e 1377 return warning_meta (rich_loc, m, get_controlling_option (),
1690a839 1378 "%<%s%> of %qE which points to memory"
6c8e5844 1379 " not on the heap",
1690a839 1380 m_funcname, m_arg);
757bf1df 1381 break;
a61aaee6 1382 case MEMSPACE_STACK:
7fd6e36e 1383 return warning_meta (rich_loc, m, get_controlling_option (),
a61aaee6
DM
1384 "%<%s%> of %qE which points to memory"
1385 " on the stack",
1386 m_funcname, m_arg);
757bf1df
DM
1387 break;
1388 }
1389 }
1390
a61aaee6 1391 label_text describe_state_change (const evdesc::state_change &)
ff171cb1 1392 final override
757bf1df 1393 {
757bf1df
DM
1394 return label_text::borrow ("pointer is from here");
1395 }
1396
ff171cb1 1397 label_text describe_final_event (const evdesc::final_event &ev) final override
757bf1df 1398 {
1690a839 1399 return ev.formatted_print ("call to %qs here", m_funcname);
757bf1df
DM
1400 }
1401
ff171cb1 1402 void mark_interesting_stuff (interesting_t *interest) final override
a61aaee6
DM
1403 {
1404 if (m_freed_reg)
1405 interest->add_region_creation (m_freed_reg);
1406 }
1407
757bf1df 1408private:
a61aaee6 1409 enum memory_space get_memory_space () const
757bf1df 1410 {
a61aaee6
DM
1411 if (m_freed_reg)
1412 return m_freed_reg->get_memory_space ();
1413 else
1414 return MEMSPACE_UNKNOWN;
1415 }
1416
1417 const region *m_freed_reg;
1690a839 1418 const char *m_funcname;
757bf1df
DM
1419};
1420
1690a839
DM
1421/* struct allocation_state : public state_machine::state. */
1422
1423/* Implementation of state_machine::state::dump_to_pp vfunc
1424 for allocation_state: append the API that this allocation is
1425 associated with. */
1426
1427void
1428allocation_state::dump_to_pp (pretty_printer *pp) const
1429{
1430 state_machine::state::dump_to_pp (pp);
c7e276b8
DM
1431 if (m_deallocators)
1432 {
1433 pp_string (pp, " (");
1434 m_deallocators->dump_to_pp (pp);
1435 pp_character (pp, ')');
1436 }
1690a839
DM
1437}
1438
c7e276b8
DM
1439/* Given a allocation_state for a deallocator_set, get the "nonnull" state
1440 for the corresponding allocator(s). */
1690a839
DM
1441
1442const allocation_state *
1443allocation_state::get_nonnull () const
1444{
c7e276b8
DM
1445 gcc_assert (m_deallocators);
1446 return as_a_allocation_state (m_deallocators->m_nonnull);
1690a839
DM
1447}
1448
757bf1df
DM
1449/* malloc_state_machine's ctor. */
1450
1451malloc_state_machine::malloc_state_machine (logger *logger)
1690a839 1452: state_machine ("malloc", logger),
c7e276b8
DM
1453 m_free (this, "free", WORDING_FREED),
1454 m_scalar_delete (this, "delete", WORDING_DELETED),
a6baafca
DM
1455 m_vector_delete (this, "delete[]", WORDING_DELETED),
1456 m_realloc (this, "realloc", WORDING_REALLOCATED)
1690a839
DM
1457{
1458 gcc_assert (m_start->get_id () == 0);
c7e276b8
DM
1459 m_null = add_state ("null", RS_FREED, NULL, NULL);
1460 m_non_heap = add_state ("non-heap", RS_NON_HEAP, NULL, NULL);
1461 m_stop = add_state ("stop", RS_STOP, NULL, NULL);
1462}
1463
1464malloc_state_machine::~malloc_state_machine ()
1465{
1466 unsigned i;
1467 custom_deallocator_set *set;
1468 FOR_EACH_VEC_ELT (m_dynamic_sets, i, set)
1469 delete set;
1470 custom_deallocator *d;
1471 FOR_EACH_VEC_ELT (m_dynamic_deallocators, i, d)
1472 delete d;
1690a839
DM
1473}
1474
1475state_machine::state_t
1476malloc_state_machine::add_state (const char *name, enum resource_state rs,
c7e276b8
DM
1477 const deallocator_set *deallocators,
1478 const deallocator *deallocator)
1690a839
DM
1479{
1480 return add_custom_state (new allocation_state (name, alloc_state_id (),
c7e276b8
DM
1481 rs, deallocators,
1482 deallocator));
1483}
1484
1485/* If ALLOCATOR_FNDECL has any "__attribute__((malloc(FOO)))",
1486 return a custom_deallocator_set for them, consolidating them
1487 to ensure uniqueness of the sets.
1488
1489 Return NULL if it has no such attributes. */
1490
1491const custom_deallocator_set *
1492malloc_state_machine::
1493get_or_create_custom_deallocator_set (tree allocator_fndecl)
1494{
1495 /* Early rejection of decls without attributes. */
1496 tree attrs = DECL_ATTRIBUTES (allocator_fndecl);
1497 if (!attrs)
1498 return NULL;
1499
1500 /* Otherwise, call maybe_create_custom_deallocator_set,
1501 memoizing the result. */
1502 if (custom_deallocator_set **slot
1503 = m_custom_deallocator_set_cache.get (allocator_fndecl))
1504 return *slot;
1505 custom_deallocator_set *set
1506 = maybe_create_custom_deallocator_set (allocator_fndecl);
1507 m_custom_deallocator_set_cache.put (allocator_fndecl, set);
1508 return set;
1509}
1510
1511/* Given ALLOCATOR_FNDECL, a FUNCTION_DECL with attributes,
1512 look for any "__attribute__((malloc(FOO)))" and return a
1513 custom_deallocator_set for them, consolidating them
1514 to ensure uniqueness of the sets.
1515
1516 Return NULL if it has no such attributes.
1517
1518 Subroutine of get_or_create_custom_deallocator_set which
1519 memoizes the result. */
1520
1521custom_deallocator_set *
1522malloc_state_machine::
1523maybe_create_custom_deallocator_set (tree allocator_fndecl)
1524{
1525 tree attrs = DECL_ATTRIBUTES (allocator_fndecl);
1526 gcc_assert (attrs);
1527
1528 /* Look for instances of __attribute__((malloc(FOO))). */
1529 auto_vec<const deallocator *> deallocator_vec;
1530 for (tree allocs = attrs;
1531 (allocs = lookup_attribute ("malloc", allocs));
1532 allocs = TREE_CHAIN (allocs))
1533 {
1534 tree args = TREE_VALUE (allocs);
1535 if (!args)
1536 continue;
1537 if (TREE_VALUE (args))
1538 {
1539 const deallocator *d
1540 = get_or_create_deallocator (TREE_VALUE (args));
1541 deallocator_vec.safe_push (d);
1542 }
1543 }
1544
1545 /* If there weren't any deallocators, bail. */
1546 if (deallocator_vec.length () == 0)
1547 return NULL;
1548
1549 /* Consolidate, so that we reuse existing deallocator_set
1550 instances. */
1551 deallocator_vec.qsort (deallocator::cmp_ptr_ptr);
1552 custom_deallocator_set **slot
1553 = m_custom_deallocator_set_map.get (&deallocator_vec);
1554 if (slot)
1555 return *slot;
1556 custom_deallocator_set *set
1557 = new custom_deallocator_set (this, &deallocator_vec, WORDING_DEALLOCATED);
1558 m_custom_deallocator_set_map.put (&set->m_deallocator_vec, set);
1559 m_dynamic_sets.safe_push (set);
1560 return set;
1561}
1562
1563/* Get the deallocator for DEALLOCATOR_FNDECL, creating it if necessary. */
1564
1565const deallocator *
1566malloc_state_machine::get_or_create_deallocator (tree deallocator_fndecl)
1567{
1568 deallocator **slot = m_deallocator_map.get (deallocator_fndecl);
1569 if (slot)
1570 return *slot;
1571
1572 /* Reuse "free". */
1573 deallocator *d;
1574 if (is_named_call_p (deallocator_fndecl, "free")
84606efb
SP
1575 || is_std_named_call_p (deallocator_fndecl, "free")
1576 || is_named_call_p (deallocator_fndecl, "__builtin_free"))
c7e276b8
DM
1577 d = &m_free.m_deallocator;
1578 else
1579 {
1580 custom_deallocator *cd
1581 = new custom_deallocator (this, deallocator_fndecl,
1582 WORDING_DEALLOCATED);
1583 m_dynamic_deallocators.safe_push (cd);
1584 d = cd;
1585 }
1586 m_deallocator_map.put (deallocator_fndecl, d);
1587 return d;
757bf1df
DM
1588}
1589
31534ac2
SP
1590/* Try to identify the function declaration either by name or as a known malloc
1591 builtin. */
1592
1593static bool
1594known_allocator_p (const_tree fndecl, const gcall *call)
1595{
1596 /* Either it is a function we know by name and number of arguments... */
1597 if (is_named_call_p (fndecl, "malloc", call, 1)
1598 || is_named_call_p (fndecl, "calloc", call, 2)
1599 || is_std_named_call_p (fndecl, "malloc", call, 1)
1600 || is_std_named_call_p (fndecl, "calloc", call, 2)
1601 || is_named_call_p (fndecl, "strdup", call, 1)
1602 || is_named_call_p (fndecl, "strndup", call, 2))
1603 return true;
1604
1605 /* ... or it is a builtin allocator that allocates objects freed with
1606 __builtin_free. */
1a830c06 1607 if (fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
31534ac2
SP
1608 switch (DECL_FUNCTION_CODE (fndecl))
1609 {
1610 case BUILT_IN_MALLOC:
1611 case BUILT_IN_CALLOC:
1612 case BUILT_IN_STRDUP:
1613 case BUILT_IN_STRNDUP:
1614 return true;
1615 default:
1616 break;
1617 }
1618
1619 return false;
1620}
1621
757bf1df
DM
1622/* Implementation of state_machine::on_stmt vfunc for malloc_state_machine. */
1623
1624bool
1625malloc_state_machine::on_stmt (sm_context *sm_ctxt,
1626 const supernode *node,
1627 const gimple *stmt) const
1628{
1629 if (const gcall *call = dyn_cast <const gcall *> (stmt))
1630 if (tree callee_fndecl = sm_ctxt->get_fndecl_for_call (call))
1631 {
31534ac2 1632 if (known_allocator_p (callee_fndecl, call))
757bf1df 1633 {
c7e276b8 1634 on_allocator_call (sm_ctxt, call, &m_free);
1690a839
DM
1635 return true;
1636 }
1637
1638 if (is_named_call_p (callee_fndecl, "operator new", call, 1))
c7e276b8 1639 on_allocator_call (sm_ctxt, call, &m_scalar_delete);
1690a839 1640 else if (is_named_call_p (callee_fndecl, "operator new []", call, 1))
c7e276b8 1641 on_allocator_call (sm_ctxt, call, &m_vector_delete);
1690a839
DM
1642 else if (is_named_call_p (callee_fndecl, "operator delete", call, 1)
1643 || is_named_call_p (callee_fndecl, "operator delete", call, 2))
1644 {
c7e276b8
DM
1645 on_deallocator_call (sm_ctxt, node, call,
1646 &m_scalar_delete.m_deallocator, 0);
1690a839
DM
1647 return true;
1648 }
1649 else if (is_named_call_p (callee_fndecl, "operator delete []", call, 1))
1650 {
c7e276b8
DM
1651 on_deallocator_call (sm_ctxt, node, call,
1652 &m_vector_delete.m_deallocator, 0);
757bf1df
DM
1653 return true;
1654 }
1655
1656 if (is_named_call_p (callee_fndecl, "alloca", call, 1)
1657 || is_named_call_p (callee_fndecl, "__builtin_alloca", call, 1))
1658 {
1659 tree lhs = gimple_call_lhs (call);
1660 if (lhs)
808f4dfe 1661 sm_ctxt->on_transition (node, stmt, lhs, m_start, m_non_heap);
757bf1df
DM
1662 return true;
1663 }
1664
1665 if (is_named_call_p (callee_fndecl, "free", call, 1)
9f00b22f 1666 || is_std_named_call_p (callee_fndecl, "free", call, 1)
757bf1df
DM
1667 || is_named_call_p (callee_fndecl, "__builtin_free", call, 1))
1668 {
c7e276b8
DM
1669 on_deallocator_call (sm_ctxt, node, call,
1670 &m_free.m_deallocator, 0);
757bf1df
DM
1671 return true;
1672 }
1673
a6baafca
DM
1674 if (is_named_call_p (callee_fndecl, "realloc", call, 2)
1675 || is_named_call_p (callee_fndecl, "__builtin_realloc", call, 2))
1676 {
1677 on_realloc_call (sm_ctxt, node, call);
1678 return true;
1679 }
1680
cd323d97
DM
1681 if (unaffected_by_call_p (callee_fndecl))
1682 return true;
1683
c7e276b8
DM
1684 /* Cast away const-ness for cache-like operations. */
1685 malloc_state_machine *mutable_this
1686 = const_cast <malloc_state_machine *> (this);
1687
1688 /* Handle "__attribute__((malloc(FOO)))". */
1689 if (const deallocator_set *deallocators
1690 = mutable_this->get_or_create_custom_deallocator_set
1691 (callee_fndecl))
1692 {
1693 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (callee_fndecl));
1694 bool returns_nonnull
1695 = lookup_attribute ("returns_nonnull", attrs);
1696 on_allocator_call (sm_ctxt, call, deallocators, returns_nonnull);
1697 }
1698
757bf1df
DM
1699 /* Handle "__attribute__((nonnull))". */
1700 {
1701 tree fntype = TREE_TYPE (callee_fndecl);
1702 bitmap nonnull_args = get_nonnull_args (fntype);
1703 if (nonnull_args)
1704 {
1705 for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
1706 {
1707 tree arg = gimple_call_arg (stmt, i);
1708 if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
1709 continue;
1710 /* If we have a nonnull-args, and either all pointers, or just
1711 the specified pointers. */
1712 if (bitmap_empty_p (nonnull_args)
1713 || bitmap_bit_p (nonnull_args, i))
1714 {
25ef215a
DM
1715 state_t state = sm_ctxt->get_state (stmt, arg);
1716 /* Can't use a switch as the states are non-const. */
1690a839 1717 if (unchecked_p (state))
25ef215a 1718 {
7d8f4240 1719 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
25ef215a
DM
1720 sm_ctxt->warn (node, stmt, arg,
1721 new possible_null_arg (*this, diag_arg,
1722 callee_fndecl,
1723 i));
1690a839
DM
1724 const allocation_state *astate
1725 = as_a_allocation_state (state);
1726 sm_ctxt->set_next_state (stmt, arg,
1727 astate->get_nonnull ());
25ef215a
DM
1728 }
1729 else if (state == m_null)
1730 {
7d8f4240 1731 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
25ef215a
DM
1732 sm_ctxt->warn (node, stmt, arg,
1733 new null_arg (*this, diag_arg,
1734 callee_fndecl, i));
1735 sm_ctxt->set_next_state (stmt, arg, m_stop);
1736 }
757bf1df
DM
1737 }
1738 }
1739 BITMAP_FREE (nonnull_args);
1740 }
1741 }
c7e276b8
DM
1742
1743 /* Check for this after nonnull, so that if we have both
1744 then we transition to "freed", rather than "checked". */
1745 unsigned dealloc_argno = fndecl_dealloc_argno (callee_fndecl);
1746 if (dealloc_argno != UINT_MAX)
1747 {
1748 const deallocator *d
1749 = mutable_this->get_or_create_deallocator (callee_fndecl);
1750 on_deallocator_call (sm_ctxt, node, call, d, dealloc_argno);
1751 }
757bf1df
DM
1752 }
1753
808f4dfe 1754 if (tree lhs = sm_ctxt->is_zero_assignment (stmt))
8525d1f5 1755 if (any_pointer_p (lhs))
1690a839 1756 on_zero_assignment (sm_ctxt, stmt,lhs);
757bf1df 1757
757bf1df
DM
1758 /* Handle dereferences. */
1759 for (unsigned i = 0; i < gimple_num_ops (stmt); i++)
1760 {
1761 tree op = gimple_op (stmt, i);
1762 if (!op)
1763 continue;
1764 if (TREE_CODE (op) == COMPONENT_REF)
1765 op = TREE_OPERAND (op, 0);
1766
1767 if (TREE_CODE (op) == MEM_REF)
1768 {
1769 tree arg = TREE_OPERAND (op, 0);
757bf1df 1770
25ef215a 1771 state_t state = sm_ctxt->get_state (stmt, arg);
1690a839 1772 if (unchecked_p (state))
25ef215a 1773 {
0f9aa35c 1774 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
25ef215a
DM
1775 sm_ctxt->warn (node, stmt, arg,
1776 new possible_null_deref (*this, diag_arg));
1690a839
DM
1777 const allocation_state *astate = as_a_allocation_state (state);
1778 sm_ctxt->set_next_state (stmt, arg, astate->get_nonnull ());
25ef215a
DM
1779 }
1780 else if (state == m_null)
1781 {
0f9aa35c 1782 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
25ef215a
DM
1783 sm_ctxt->warn (node, stmt, arg,
1784 new null_deref (*this, diag_arg));
1785 sm_ctxt->set_next_state (stmt, arg, m_stop);
1786 }
1690a839 1787 else if (freed_p (state))
25ef215a 1788 {
0f9aa35c 1789 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1690a839 1790 const allocation_state *astate = as_a_allocation_state (state);
25ef215a 1791 sm_ctxt->warn (node, stmt, arg,
1690a839 1792 new use_after_free (*this, diag_arg,
c7e276b8 1793 astate->m_deallocator));
25ef215a
DM
1794 sm_ctxt->set_next_state (stmt, arg, m_stop);
1795 }
757bf1df
DM
1796 }
1797 }
1798 return false;
1799}
1800
c7e276b8
DM
1801/* Handle a call to an allocator.
1802 RETURNS_NONNULL is true if CALL is to a fndecl known to have
1803 __attribute__((returns_nonnull)). */
1690a839
DM
1804
1805void
1806malloc_state_machine::on_allocator_call (sm_context *sm_ctxt,
1807 const gcall *call,
c7e276b8
DM
1808 const deallocator_set *deallocators,
1809 bool returns_nonnull) const
1690a839
DM
1810{
1811 tree lhs = gimple_call_lhs (call);
1812 if (lhs)
1813 {
1814 if (sm_ctxt->get_state (call, lhs) == m_start)
c7e276b8
DM
1815 sm_ctxt->set_next_state (call, lhs,
1816 (returns_nonnull
1817 ? deallocators->m_nonnull
1818 : deallocators->m_unchecked));
1690a839
DM
1819 }
1820 else
1821 {
1822 /* TODO: report leak. */
1823 }
1824}
1825
a61aaee6
DM
1826/* Handle deallocations of non-heap pointers.
1827 non-heap -> stop, with warning. */
1828
1829void
1830malloc_state_machine::handle_free_of_non_heap (sm_context *sm_ctxt,
1831 const supernode *node,
1832 const gcall *call,
1833 tree arg,
1834 const deallocator *d) const
1835{
1836 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1837 const region *freed_reg = NULL;
1838 if (const program_state *old_state = sm_ctxt->get_old_program_state ())
1839 {
1840 const region_model *old_model = old_state->m_region_model;
1841 const svalue *ptr_sval = old_model->get_rvalue (arg, NULL);
1842 freed_reg = old_model->deref_rvalue (ptr_sval, arg, NULL);
1843 }
1844 sm_ctxt->warn (node, call, arg,
1845 new free_of_non_heap (*this, diag_arg, freed_reg,
1846 d->m_name));
1847 sm_ctxt->set_next_state (call, arg, m_stop);
1848}
1849
1690a839
DM
1850void
1851malloc_state_machine::on_deallocator_call (sm_context *sm_ctxt,
1852 const supernode *node,
1853 const gcall *call,
c7e276b8
DM
1854 const deallocator *d,
1855 unsigned argno) const
1690a839 1856{
c7e276b8
DM
1857 if (argno >= gimple_call_num_args (call))
1858 return;
1859 tree arg = gimple_call_arg (call, argno);
1690a839
DM
1860
1861 state_t state = sm_ctxt->get_state (call, arg);
1862
1863 /* start/unchecked/nonnull -> freed. */
1864 if (state == m_start)
c7e276b8 1865 sm_ctxt->set_next_state (call, arg, d->m_freed);
1690a839
DM
1866 else if (unchecked_p (state) || nonnull_p (state))
1867 {
1868 const allocation_state *astate = as_a_allocation_state (state);
c7e276b8
DM
1869 gcc_assert (astate->m_deallocators);
1870 if (!astate->m_deallocators->contains_p (d))
1690a839
DM
1871 {
1872 /* Wrong allocator. */
0f9aa35c 1873 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
c7e276b8 1874 pending_diagnostic *pd
1690a839 1875 = new mismatching_deallocation (*this, diag_arg,
c7e276b8
DM
1876 astate->m_deallocators,
1877 d);
1878 sm_ctxt->warn (node, call, arg, pd);
1690a839 1879 }
c7e276b8 1880 sm_ctxt->set_next_state (call, arg, d->m_freed);
1690a839
DM
1881 }
1882
1883 /* Keep state "null" as-is, rather than transitioning to "freed";
1884 we don't want to complain about double-free of NULL. */
c7e276b8 1885 else if (state == d->m_freed)
1690a839
DM
1886 {
1887 /* freed -> stop, with warning. */
0f9aa35c 1888 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1690a839 1889 sm_ctxt->warn (node, call, arg,
c7e276b8 1890 new double_free (*this, diag_arg, d->m_name));
1690a839
DM
1891 sm_ctxt->set_next_state (call, arg, m_stop);
1892 }
1893 else if (state == m_non_heap)
1894 {
1895 /* non-heap -> stop, with warning. */
a61aaee6 1896 handle_free_of_non_heap (sm_ctxt, node, call, arg, d);
1690a839
DM
1897 }
1898}
1899
eafa9d96
DM
1900/* Handle a call to "realloc".
1901 Check for free of non-heap or mismatching allocators,
1902 transitioning to the "stop" state for such cases.
a6baafca 1903
eafa9d96
DM
1904 Otherwise, region_model::impl_call_realloc will later
1905 get called (which will handle other sm-state transitions
1906 when the state is bifurcated). */
a6baafca
DM
1907
1908void
1909malloc_state_machine::on_realloc_call (sm_context *sm_ctxt,
eafa9d96 1910 const supernode *node,
a6baafca
DM
1911 const gcall *call) const
1912{
eafa9d96
DM
1913 const unsigned argno = 0;
1914 const deallocator *d = &m_realloc;
1915
1916 tree arg = gimple_call_arg (call, argno);
a6baafca 1917
eafa9d96 1918 state_t state = sm_ctxt->get_state (call, arg);
a6baafca 1919
a6baafca
DM
1920 if (unchecked_p (state) || nonnull_p (state))
1921 {
1922 const allocation_state *astate = as_a_allocation_state (state);
1923 gcc_assert (astate->m_deallocators);
eafa9d96 1924 if (!astate->m_deallocators->contains_p (&m_free.m_deallocator))
a6baafca
DM
1925 {
1926 /* Wrong allocator. */
eafa9d96 1927 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
a6baafca 1928 pending_diagnostic *pd
eafa9d96 1929 = new mismatching_deallocation (*this, diag_arg,
a6baafca 1930 astate->m_deallocators,
eafa9d96
DM
1931 d);
1932 sm_ctxt->warn (node, call, arg, pd);
1933 sm_ctxt->set_next_state (call, arg, m_stop);
1934 if (path_context *path_ctxt = sm_ctxt->get_path_context ())
1935 path_ctxt->terminate_path ();
a6baafca
DM
1936 }
1937 }
eafa9d96
DM
1938 else if (state == m_free.m_deallocator.m_freed)
1939 {
1940 /* freed -> stop, with warning. */
1941 tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
1942 sm_ctxt->warn (node, call, arg,
1943 new double_free (*this, diag_arg, "free"));
1944 sm_ctxt->set_next_state (call, arg, m_stop);
1945 if (path_context *path_ctxt = sm_ctxt->get_path_context ())
1946 path_ctxt->terminate_path ();
1947 }
1948 else if (state == m_non_heap)
1949 {
1950 /* non-heap -> stop, with warning. */
a61aaee6 1951 handle_free_of_non_heap (sm_ctxt, node, call, arg, d);
eafa9d96
DM
1952 if (path_context *path_ctxt = sm_ctxt->get_path_context ())
1953 path_ctxt->terminate_path ();
1954 }
a6baafca
DM
1955}
1956
8525d1f5
DM
1957/* Implementation of state_machine::on_phi vfunc for malloc_state_machine. */
1958
1959void
1960malloc_state_machine::on_phi (sm_context *sm_ctxt,
1690a839 1961 const supernode *node ATTRIBUTE_UNUSED,
8525d1f5
DM
1962 const gphi *phi,
1963 tree rhs) const
1964{
1965 if (zerop (rhs))
1966 {
1967 tree lhs = gimple_phi_result (phi);
1690a839 1968 on_zero_assignment (sm_ctxt, phi, lhs);
8525d1f5
DM
1969 }
1970}
1971
757bf1df
DM
1972/* Implementation of state_machine::on_condition vfunc for malloc_state_machine.
1973 Potentially transition state 'unchecked' to 'nonnull' or to 'null'. */
1974
1975void
1976malloc_state_machine::on_condition (sm_context *sm_ctxt,
1690a839 1977 const supernode *node ATTRIBUTE_UNUSED,
757bf1df 1978 const gimple *stmt,
48e8a7a6 1979 const svalue *lhs,
757bf1df 1980 enum tree_code op,
48e8a7a6 1981 const svalue *rhs) const
757bf1df 1982{
48e8a7a6 1983 if (!rhs->all_zeroes_p ())
757bf1df
DM
1984 return;
1985
1986 if (!any_pointer_p (lhs))
1987 return;
1988 if (!any_pointer_p (rhs))
1989 return;
1990
1991 if (op == NE_EXPR)
1992 {
1993 log ("got 'ARG != 0' match");
1690a839
DM
1994 state_t s = sm_ctxt->get_state (stmt, lhs);
1995 if (unchecked_p (s))
1996 {
1997 const allocation_state *astate = as_a_allocation_state (s);
1998 sm_ctxt->set_next_state (stmt, lhs, astate->get_nonnull ());
1999 }
757bf1df
DM
2000 }
2001 else if (op == EQ_EXPR)
2002 {
2003 log ("got 'ARG == 0' match");
1690a839
DM
2004 state_t s = sm_ctxt->get_state (stmt, lhs);
2005 if (unchecked_p (s))
2006 sm_ctxt->set_next_state (stmt, lhs, m_null);
757bf1df
DM
2007 }
2008}
2009
2010/* Implementation of state_machine::can_purge_p vfunc for malloc_state_machine.
2011 Don't allow purging of pointers in state 'unchecked' or 'nonnull'
2012 (to avoid false leak reports). */
2013
2014bool
2015malloc_state_machine::can_purge_p (state_t s) const
2016{
1690a839
DM
2017 enum resource_state rs = get_rs (s);
2018 return rs != RS_UNCHECKED && rs != RS_NONNULL;
757bf1df
DM
2019}
2020
2021/* Implementation of state_machine::on_leak vfunc for malloc_state_machine
2022 (for complaining about leaks of pointers in state 'unchecked' and
2023 'nonnull'). */
2024
2025pending_diagnostic *
2026malloc_state_machine::on_leak (tree var) const
2027{
2028 return new malloc_leak (*this, var);
2029}
2030
808f4dfe
DM
2031/* Implementation of state_machine::reset_when_passed_to_unknown_fn_p vfunc
2032 for malloc_state_machine. */
2033
2034bool
2035malloc_state_machine::reset_when_passed_to_unknown_fn_p (state_t s,
2036 bool is_mutable) const
2037{
2038 /* An on-stack ptr doesn't stop being stack-allocated when passed to an
2039 unknown fn. */
2040 if (s == m_non_heap)
2041 return false;
2042
2043 /* Otherwise, pointers passed as non-const can be freed. */
2044 return is_mutable;
2045}
2046
cd323d97
DM
2047/* Return true if calls to FNDECL are known to not affect this sm-state. */
2048
2049bool
2050malloc_state_machine::unaffected_by_call_p (tree fndecl)
2051{
2052 /* A set of functions that are known to not affect allocation
2053 status, even if we haven't fully modelled the rest of their
2054 behavior yet. */
2055 static const char * const funcnames[] = {
2056 /* This array must be kept sorted. */
2057 "strsep",
2058 };
ca32b29e 2059 const size_t count = ARRAY_SIZE (funcnames);
cd323d97
DM
2060 function_set fs (funcnames, count);
2061
2062 if (fs.contains_decl_p (fndecl))
2063 return true;
2064
2065 return false;
2066}
2067
8525d1f5
DM
2068/* Shared logic for handling GIMPLE_ASSIGNs and GIMPLE_PHIs that
2069 assign zero to LHS. */
2070
2071void
2072malloc_state_machine::on_zero_assignment (sm_context *sm_ctxt,
8525d1f5
DM
2073 const gimple *stmt,
2074 tree lhs) const
2075{
1690a839
DM
2076 state_t s = sm_ctxt->get_state (stmt, lhs);
2077 enum resource_state rs = get_rs (s);
2078 if (rs == RS_START
2079 || rs == RS_UNCHECKED
2080 || rs == RS_NONNULL
2081 || rs == RS_FREED)
2082 sm_ctxt->set_next_state (stmt, lhs, m_null);
8525d1f5
DM
2083}
2084
eafa9d96
DM
2085/* Special-case hook for handling realloc, for the "success with move to
2086 a new buffer" case, marking OLD_PTR_SVAL as freed and NEW_PTR_SVAL as
2087 non-null.
2088
2089 This is similar to on_deallocator_call and on_allocator_call,
2090 but the checks happen in on_realloc_call, and by splitting the states. */
2091
2092void
2093malloc_state_machine::
2094on_realloc_with_move (region_model *model,
2095 sm_state_map *smap,
2096 const svalue *old_ptr_sval,
2097 const svalue *new_ptr_sval,
2098 const extrinsic_state &ext_state) const
2099{
2100 smap->set_state (model, old_ptr_sval,
2101 m_free.m_deallocator.m_freed,
2102 NULL, ext_state);
2103
2104 smap->set_state (model, new_ptr_sval,
2105 m_free.m_nonnull,
2106 NULL, ext_state);
2107}
2108
757bf1df
DM
2109} // anonymous namespace
2110
2111/* Internal interface to this file. */
2112
2113state_machine *
2114make_malloc_state_machine (logger *logger)
2115{
2116 return new malloc_state_machine (logger);
2117}
2118
eafa9d96
DM
2119/* Specialcase hook for handling realloc, for use by
2120 region_model::impl_call_realloc::success_with_move::update_model. */
2121
2122void
2123region_model::on_realloc_with_move (const call_details &cd,
2124 const svalue *old_ptr_sval,
2125 const svalue *new_ptr_sval)
2126{
2127 region_model_context *ctxt = cd.get_ctxt ();
2128 if (!ctxt)
2129 return;
2130 const extrinsic_state *ext_state = ctxt->get_ext_state ();
2131 if (!ext_state)
2132 return;
2133
2134 sm_state_map *smap;
2135 const state_machine *sm;
2136 unsigned sm_idx;
2137 if (!ctxt->get_malloc_map (&smap, &sm, &sm_idx))
2138 return;
2139
2140 gcc_assert (smap);
2141 gcc_assert (sm);
2142
2143 const malloc_state_machine &malloc_sm
2144 = (const malloc_state_machine &)*sm;
2145
2146 malloc_sm.on_realloc_with_move (this,
2147 smap,
2148 old_ptr_sval,
2149 new_ptr_sval,
2150 *ext_state);
2151}
2152
75038aa6
DM
2153} // namespace ana
2154
757bf1df 2155#endif /* #if ENABLE_ANALYZER */