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