1/* A state machine for detecting misuses of the malloc/free API.
2   Copyright (C) 2019-2020 Free Software Foundation, Inc.
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"
33#include "analyzer/analyzer.h"
34#include "diagnostic-event-id.h"
35#include "analyzer/analyzer-logging.h"
36#include "analyzer/sm.h"
37#include "analyzer/pending-diagnostic.h"
38
39#if ENABLE_ANALYZER
40
41namespace ana {
42
43namespace {
44
45/* A state machine for detecting misuses of the malloc/free API.
46
47   See sm-malloc.dot for an overview (keep this in-sync with that file).  */
48
49class malloc_state_machine : public state_machine
50{
51public:
52  malloc_state_machine (logger *logger);
53
54  bool inherited_state_p () const FINAL OVERRIDE { return false; }
55
56  bool on_stmt (sm_context *sm_ctxt,
57		const supernode *node,
58		const gimple *stmt) const FINAL OVERRIDE;
59
60  void on_phi (sm_context *sm_ctxt,
61	       const supernode *node,
62	       const gphi *phi,
63	       tree rhs) const FINAL OVERRIDE;
64
65  void on_condition (sm_context *sm_ctxt,
66		     const supernode *node,
67		     const gimple *stmt,
68		     tree lhs,
69		     enum tree_code op,
70		     tree rhs) const FINAL OVERRIDE;
71
72  bool can_purge_p (state_t s) const FINAL OVERRIDE;
73  pending_diagnostic *on_leak (tree var) const FINAL OVERRIDE;
74
75  /* Start state.  */
76  state_t m_start;
77
78  /* State for a pointer returned from malloc that hasn't been checked for
79     NULL.
80     It could be a pointer to heap-allocated memory, or could be NULL.  */
81  state_t m_unchecked;
82
83  /* State for a pointer that's known to be NULL.  */
84  state_t m_null;
85
86  /* State for a pointer to heap-allocated memory, known to be non-NULL.  */
87  state_t m_nonnull;
88
89  /* State for a pointer to freed memory.  */
90  state_t m_freed;
91
92  /* State for a pointer that's known to not be on the heap (e.g. to a local
93     or global).  */
94  state_t m_non_heap; // TODO: or should this be a different state machine?
95  // or do we need child values etc?
96
97  /* Stop state, for pointers we don't want to track any more.  */
98  state_t m_stop;
99
100private:
101  void on_zero_assignment (sm_context *sm_ctxt,
102			   const supernode *node,
103			   const gimple *stmt,
104			   tree lhs) const;
105};
106
107/* Class for diagnostics relating to malloc_state_machine.  */
108
109class malloc_diagnostic : public pending_diagnostic
110{
111public:
112  malloc_diagnostic (const malloc_state_machine &sm, tree arg)
113  : m_sm (sm), m_arg (arg)
114  {}
115
116  bool subclass_equal_p (const pending_diagnostic &base_other) const OVERRIDE
117  {
118    return same_tree_p (m_arg, ((const malloc_diagnostic &)base_other).m_arg);
119  }
120
121  label_text describe_state_change (const evdesc::state_change &change)
122    OVERRIDE
123  {
124    if (change.m_old_state == m_sm.m_start
125	&& change.m_new_state == m_sm.m_unchecked)
126      // TODO: verify that it's the allocation stmt, not a copy
127      return label_text::borrow ("allocated here");
128    if (change.m_old_state == m_sm.m_unchecked
129	&& change.m_new_state == m_sm.m_nonnull)
130      return change.formatted_print ("assuming %qE is non-NULL",
131				     change.m_expr);
132    if (change.m_new_state == m_sm.m_null)
133      {
134	if (change.m_old_state == m_sm.m_unchecked)
135	  return change.formatted_print ("assuming %qE is NULL",
136					 change.m_expr);
137	else
138	  return change.formatted_print ("%qE is NULL",
139					 change.m_expr);
140      }
141
142    return label_text ();
143  }
144
145protected:
146  const malloc_state_machine &m_sm;
147  tree m_arg;
148};
149
150/* Concrete subclass for reporting double-free diagnostics.  */
151
152class double_free : public malloc_diagnostic
153{
154public:
155  double_free (const malloc_state_machine &sm, tree arg)
156  : malloc_diagnostic (sm, arg)
157  {}
158
159  const char *get_kind () const FINAL OVERRIDE { return "double_free"; }
160
161  bool emit (rich_location *rich_loc) FINAL OVERRIDE
162  {
163    auto_diagnostic_group d;
164    diagnostic_metadata m;
165    m.add_cwe (415); /* CWE-415: Double Free.  */
166    return warning_meta (rich_loc, m, OPT_Wanalyzer_double_free,
167			 "double-%<free%> of %qE", m_arg);
168  }
169
170  label_text describe_state_change (const evdesc::state_change &change)
171    FINAL OVERRIDE
172  {
173    if (change.m_new_state == m_sm.m_freed)
174      {
175	m_first_free_event = change.m_event_id;
176	return change.formatted_print ("first %qs here", "free");
177      }
178    return malloc_diagnostic::describe_state_change (change);
179  }
180
181  label_text describe_call_with_state (const evdesc::call_with_state &info)
182    FINAL OVERRIDE
183  {
184    if (info.m_state == m_sm.m_freed)
185      return info.formatted_print
186	("passing freed pointer %qE in call to %qE from %qE",
187	 info.m_expr, info.m_callee_fndecl, info.m_caller_fndecl);
188    return label_text ();
189  }
190
191  label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
192  {
193    if (m_first_free_event.known_p ())
194      return ev.formatted_print ("second %qs here; first %qs was at %@",
195				 "free", "free",
196				 &m_first_free_event);
197    return ev.formatted_print ("second %qs here", "free");
198  }
199
200private:
201  diagnostic_event_id_t m_first_free_event;
202};
203
204/* Abstract subclass for describing possible bad uses of NULL.
205   Responsible for describing the call that could return NULL.  */
206
207class possible_null : public malloc_diagnostic
208{
209public:
210  possible_null (const malloc_state_machine &sm, tree arg)
211  : malloc_diagnostic (sm, arg)
212  {}
213
214  label_text describe_state_change (const evdesc::state_change &change)
215    FINAL OVERRIDE
216  {
217    if (change.m_old_state == m_sm.m_start
218	&& change.m_new_state == m_sm.m_unchecked)
219      {
220	m_origin_of_unchecked_event = change.m_event_id;
221	return label_text::borrow ("this call could return NULL");
222      }
223    return malloc_diagnostic::describe_state_change (change);
224  }
225
226  label_text describe_return_of_state (const evdesc::return_of_state &info)
227    FINAL OVERRIDE
228  {
229    if (info.m_state == m_sm.m_unchecked)
230      return info.formatted_print ("possible return of NULL to %qE from %qE",
231				   info.m_caller_fndecl, info.m_callee_fndecl);
232    return label_text ();
233  }
234
235protected:
236  diagnostic_event_id_t m_origin_of_unchecked_event;
237};
238
239/* Concrete subclass for describing dereference of a possible NULL
240   value.  */
241
242class possible_null_deref : public possible_null
243{
244public:
245  possible_null_deref (const malloc_state_machine &sm, tree arg)
246  : possible_null (sm, arg)
247  {}
248
249  const char *get_kind () const FINAL OVERRIDE { return "possible_null_deref"; }
250
251  bool emit (rich_location *rich_loc) FINAL OVERRIDE
252  {
253    /* CWE-690: Unchecked Return Value to NULL Pointer Dereference.  */
254    diagnostic_metadata m;
255    m.add_cwe (690);
256    return warning_meta (rich_loc, m,
257			 OPT_Wanalyzer_possible_null_dereference,
258			 "dereference of possibly-NULL %qE", m_arg);
259  }
260
261  label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
262  {
263    if (m_origin_of_unchecked_event.known_p ())
264      return ev.formatted_print ("%qE could be NULL: unchecked value from %@",
265				 ev.m_expr,
266				 &m_origin_of_unchecked_event);
267    else
268      return ev.formatted_print ("%qE could be NULL", ev.m_expr);
269  }
270
271};
272
273/* Subroutine for use by possible_null_arg::emit and null_arg::emit.
274   Issue a note informing that the pertinent argument must be non-NULL.  */
275
276static void
277inform_nonnull_attribute (tree fndecl, int arg_idx)
278{
279  inform (DECL_SOURCE_LOCATION (fndecl),
280	  "argument %u of %qD must be non-null",
281	  arg_idx + 1, fndecl);
282  /* Ideally we would use the location of the parm and underline the
283     attribute also - but we don't have the location_t values at this point
284     in the middle-end.
285     For reference, the C and C++ FEs have get_fndecl_argument_location.  */
286}
287
288/* Concrete subclass for describing passing a possibly-NULL value to a
289   function marked with __attribute__((nonnull)).  */
290
291class possible_null_arg : public possible_null
292{
293public:
294  possible_null_arg (const malloc_state_machine &sm, tree arg,
295		     tree fndecl, int arg_idx)
296  : possible_null (sm, arg),
297    m_fndecl (fndecl), m_arg_idx (arg_idx)
298  {}
299
300  const char *get_kind () const FINAL OVERRIDE { return "possible_null_arg"; }
301
302  bool subclass_equal_p (const pending_diagnostic &base_other) const
303  {
304    const possible_null_arg &sub_other
305      = (const possible_null_arg &)base_other;
306    return (same_tree_p (m_arg, sub_other.m_arg)
307	    && m_fndecl == sub_other.m_fndecl
308	    && m_arg_idx == sub_other.m_arg_idx);
309  }
310
311
312  bool emit (rich_location *rich_loc) FINAL OVERRIDE
313  {
314    /* CWE-690: Unchecked Return Value to NULL Pointer Dereference.  */
315    auto_diagnostic_group d;
316    diagnostic_metadata m;
317    m.add_cwe (690);
318    bool warned
319      = warning_meta (rich_loc, m, OPT_Wanalyzer_possible_null_argument,
320		      "use of possibly-NULL %qE where non-null expected",
321		      m_arg);
322    if (warned)
323      inform_nonnull_attribute (m_fndecl, m_arg_idx);
324    return warned;
325  }
326
327  label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
328  {
329    if (m_origin_of_unchecked_event.known_p ())
330      return ev.formatted_print ("argument %u (%qE) from %@ could be NULL"
331				 " where non-null expected",
332				 m_arg_idx + 1, ev.m_expr,
333				 &m_origin_of_unchecked_event);
334    else
335      return ev.formatted_print ("argument %u (%qE) could be NULL"
336				 " where non-null expected",
337				 m_arg_idx + 1, ev.m_expr);
338  }
339
340private:
341  tree m_fndecl;
342  int m_arg_idx;
343};
344
345/* Concrete subclass for describing a dereference of a NULL value.  */
346
347class null_deref : public malloc_diagnostic
348{
349public:
350  null_deref (const malloc_state_machine &sm, tree arg)
351  : malloc_diagnostic (sm, arg) {}
352
353  const char *get_kind () const FINAL OVERRIDE { return "null_deref"; }
354
355  bool emit (rich_location *rich_loc) FINAL OVERRIDE
356  {
357    /* CWE-690: Unchecked Return Value to NULL Pointer Dereference.  */
358    diagnostic_metadata m;
359    m.add_cwe (690);
360    return warning_meta (rich_loc, m,
361			 OPT_Wanalyzer_null_dereference,
362			 "dereference of NULL %qE", m_arg);
363  }
364
365  label_text describe_return_of_state (const evdesc::return_of_state &info)
366    FINAL OVERRIDE
367  {
368    if (info.m_state == m_sm.m_null)
369      return info.formatted_print ("return of NULL to %qE from %qE",
370				   info.m_caller_fndecl, info.m_callee_fndecl);
371    return label_text ();
372  }
373
374  label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
375  {
376    return ev.formatted_print ("dereference of NULL %qE", ev.m_expr);
377  }
378};
379
380/* Concrete subclass for describing passing a NULL value to a
381   function marked with __attribute__((nonnull)).  */
382
383class null_arg : public malloc_diagnostic
384{
385public:
386  null_arg (const malloc_state_machine &sm, tree arg,
387	    tree fndecl, int arg_idx)
388  : malloc_diagnostic (sm, arg),
389    m_fndecl (fndecl), m_arg_idx (arg_idx)
390  {}
391
392  const char *get_kind () const FINAL OVERRIDE { return "null_arg"; }
393
394  bool subclass_equal_p (const pending_diagnostic &base_other) const
395  {
396    const null_arg &sub_other
397      = (const null_arg &)base_other;
398    return (same_tree_p (m_arg, sub_other.m_arg)
399	    && m_fndecl == sub_other.m_fndecl
400	    && m_arg_idx == sub_other.m_arg_idx);
401  }
402
403  bool emit (rich_location *rich_loc) FINAL OVERRIDE
404  {
405    /* CWE-690: Unchecked Return Value to NULL Pointer Dereference.  */
406    auto_diagnostic_group d;
407    diagnostic_metadata m;
408    m.add_cwe (690);
409    bool warned = warning_meta (rich_loc, m, OPT_Wanalyzer_null_argument,
410				"use of NULL %qE where non-null expected",
411				m_arg);
412    if (warned)
413      inform_nonnull_attribute (m_fndecl, m_arg_idx);
414    return warned;
415  }
416
417  label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
418  {
419    return ev.formatted_print ("argument %u (%qE) NULL"
420			       " where non-null expected",
421			       m_arg_idx + 1, ev.m_expr);
422  }
423
424private:
425  tree m_fndecl;
426  int m_arg_idx;
427};
428
429class use_after_free : public malloc_diagnostic
430{
431public:
432  use_after_free (const malloc_state_machine &sm, tree arg)
433  : malloc_diagnostic (sm, arg)
434  {}
435
436  const char *get_kind () const FINAL OVERRIDE { return "use_after_free"; }
437
438  bool emit (rich_location *rich_loc) FINAL OVERRIDE
439  {
440    /* CWE-416: Use After Free.  */
441    diagnostic_metadata m;
442    m.add_cwe (416);
443    return warning_meta (rich_loc, m, OPT_Wanalyzer_use_after_free,
444			 "use after %<free%> of %qE", m_arg);
445  }
446
447  label_text describe_state_change (const evdesc::state_change &change)
448    FINAL OVERRIDE
449  {
450    if (change.m_new_state == m_sm.m_freed)
451      {
452	m_free_event = change.m_event_id;
453	return label_text::borrow ("freed here");
454      }
455    return malloc_diagnostic::describe_state_change (change);
456  }
457
458  label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
459  {
460    if (m_free_event.known_p ())
461      return ev.formatted_print ("use after %<free%> of %qE; freed at %@",
462				 ev.m_expr, &m_free_event);
463    else
464      return ev.formatted_print ("use after %<free%> of %qE", ev.m_expr);
465  }
466
467private:
468  diagnostic_event_id_t m_free_event;
469};
470
471class malloc_leak : public malloc_diagnostic
472{
473public:
474  malloc_leak (const malloc_state_machine &sm, tree arg)
475  : malloc_diagnostic (sm, arg) {}
476
477  const char *get_kind () const FINAL OVERRIDE { return "malloc_leak"; }
478
479  bool emit (rich_location *rich_loc) FINAL OVERRIDE
480  {
481    diagnostic_metadata m;
482    m.add_cwe (401);
483    return warning_meta (rich_loc, m, OPT_Wanalyzer_malloc_leak,
484			 "leak of %qE", m_arg);
485  }
486
487  label_text describe_state_change (const evdesc::state_change &change)
488    FINAL OVERRIDE
489  {
490    if (change.m_new_state == m_sm.m_unchecked)
491      {
492	m_malloc_event = change.m_event_id;
493	return label_text::borrow ("allocated here");
494      }
495    return malloc_diagnostic::describe_state_change (change);
496  }
497
498  label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
499  {
500    if (m_malloc_event.known_p ())
501      return ev.formatted_print ("%qE leaks here; was allocated at %@",
502				 ev.m_expr, &m_malloc_event);
503    else
504      return ev.formatted_print ("%qE leaks here", ev.m_expr);
505  }
506
507private:
508  diagnostic_event_id_t m_malloc_event;
509};
510
511class free_of_non_heap : public malloc_diagnostic
512{
513public:
514  free_of_non_heap (const malloc_state_machine &sm, tree arg)
515  : malloc_diagnostic (sm, arg), m_kind (KIND_UNKNOWN)
516  {
517  }
518
519  const char *get_kind () const FINAL OVERRIDE { return "free_of_non_heap"; }
520
521  bool subclass_equal_p (const pending_diagnostic &base_other) const
522    FINAL OVERRIDE
523  {
524    const free_of_non_heap &other = (const free_of_non_heap &)base_other;
525    return (same_tree_p (m_arg, other.m_arg) && m_kind == other.m_kind);
526  }
527
528  bool emit (rich_location *rich_loc) FINAL OVERRIDE
529  {
530    auto_diagnostic_group d;
531    diagnostic_metadata m;
532    m.add_cwe (590); /* CWE-590: Free of Memory not on the Heap.  */
533    switch (m_kind)
534      {
535      default:
536	gcc_unreachable ();
537      case KIND_UNKNOWN:
538	return warning_meta (rich_loc, m, OPT_Wanalyzer_free_of_non_heap,
539			     "%<free%> of %qE which points to memory"
540			     " not on the heap",
541			     m_arg);
542	break;
543      case KIND_ALLOCA:
544	return warning_meta (rich_loc, m, OPT_Wanalyzer_free_of_non_heap,
545			     "%<free%> of memory allocated on the stack by"
546			     " %qs (%qE) will corrupt the heap",
547			     "alloca", m_arg);
548	break;
549      }
550  }
551
552  label_text describe_state_change (const evdesc::state_change &change)
553    FINAL OVERRIDE
554  {
555    /* Attempt to reconstruct what kind of pointer it is.
556       (It seems neater for this to be a part of the state, though).  */
557    if (TREE_CODE (change.m_expr) == SSA_NAME)
558      {
559	gimple *def_stmt = SSA_NAME_DEF_STMT (change.m_expr);
560	if (gcall *call = dyn_cast <gcall *> (def_stmt))
561	  {
562	    if (is_special_named_call_p (call, "alloca", 1)
563		|| is_special_named_call_p (call, "__builtin_alloca", 1))
564	      {
565		m_kind = KIND_ALLOCA;
566		return label_text::borrow
567		  ("memory is allocated on the stack here");
568	      }
569	  }
570      }
571    return label_text::borrow ("pointer is from here");
572  }
573
574  label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
575  {
576    return ev.formatted_print ("call to %qs here", "free");
577  }
578
579private:
580  enum kind
581  {
582    KIND_UNKNOWN,
583    KIND_ALLOCA
584  };
585  enum kind m_kind;
586};
587
588/* malloc_state_machine's ctor.  */
589
590malloc_state_machine::malloc_state_machine (logger *logger)
591: state_machine ("malloc", logger)
592{
593  m_start = add_state ("start");
594  m_unchecked = add_state ("unchecked");
595  m_null = add_state ("null");
596  m_nonnull = add_state ("nonnull");
597  m_freed = add_state ("freed");
598  m_non_heap = add_state ("non-heap");
599  m_stop = add_state ("stop");
600}
601
602/* Implementation of state_machine::on_stmt vfunc for malloc_state_machine.  */
603
604bool
605malloc_state_machine::on_stmt (sm_context *sm_ctxt,
606			       const supernode *node,
607			       const gimple *stmt) const
608{
609  if (const gcall *call = dyn_cast <const gcall *> (stmt))
610    if (tree callee_fndecl = sm_ctxt->get_fndecl_for_call (call))
611      {
612	if (is_named_call_p (callee_fndecl, "malloc", call, 1)
613	    || is_named_call_p (callee_fndecl, "calloc", call, 2)
614	    || is_std_named_call_p (callee_fndecl, "malloc", call, 1)
615	    || is_std_named_call_p (callee_fndecl, "calloc", call, 2)
616	    || is_named_call_p (callee_fndecl, "__builtin_malloc", call, 1)
617	    || is_named_call_p (callee_fndecl, "__builtin_calloc", call, 2))
618	  {
619	    tree lhs = gimple_call_lhs (call);
620	    if (lhs)
621	      {
622		lhs = sm_ctxt->get_readable_tree (lhs);
623		sm_ctxt->on_transition (node, stmt, lhs, m_start, m_unchecked);
624	      }
625	    else
626	      {
627		/* TODO: report leak.  */
628	      }
629	    return true;
630	  }
631
632	if (is_named_call_p (callee_fndecl, "alloca", call, 1)
633	    || is_named_call_p (callee_fndecl, "__builtin_alloca", call, 1))
634	  {
635	    tree lhs = gimple_call_lhs (call);
636	    if (lhs)
637	      {
638		lhs = sm_ctxt->get_readable_tree (lhs);
639		sm_ctxt->on_transition (node, stmt, lhs, m_start, m_non_heap);
640	      }
641	    return true;
642	  }
643
644	if (is_named_call_p (callee_fndecl, "free", call, 1)
645	    || is_std_named_call_p (callee_fndecl, "free", call, 1)
646	    || is_named_call_p (callee_fndecl, "__builtin_free", call, 1))
647	  {
648	    tree arg = gimple_call_arg (call, 0);
649
650	    arg = sm_ctxt->get_readable_tree (arg);
651
652	    /* start/unchecked/nonnull -> freed.  */
653	    sm_ctxt->on_transition (node, stmt, arg, m_start, m_freed);
654	    sm_ctxt->on_transition (node, stmt, arg, m_unchecked, m_freed);
655	    sm_ctxt->on_transition (node, stmt, arg, m_nonnull, m_freed);
656
657	    /* Keep state "null" as-is, rather than transitioning to "free";
658	       we don't want to complain about double-free of NULL.  */
659
660	    /* freed -> stop, with warning.  */
661	    sm_ctxt->warn_for_state (node, stmt, arg, m_freed,
662				     new double_free (*this, arg));
663	    sm_ctxt->on_transition (node, stmt, arg, m_freed, m_stop);
664
665	    /* non-heap -> stop, with warning.  */
666	    sm_ctxt->warn_for_state (node, stmt, arg, m_non_heap,
667				     new free_of_non_heap (*this, arg));
668	    sm_ctxt->on_transition (node, stmt, arg, m_non_heap, m_stop);
669	    return true;
670	  }
671
672	/* Handle "__attribute__((nonnull))".   */
673	{
674	  tree fntype = TREE_TYPE (callee_fndecl);
675	  bitmap nonnull_args = get_nonnull_args (fntype);
676	  if (nonnull_args)
677	    {
678	      for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
679		{
680		  tree arg = gimple_call_arg (stmt, i);
681		  if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
682		    continue;
683		  /* If we have a nonnull-args, and either all pointers, or just
684		     the specified pointers.  */
685		  if (bitmap_empty_p (nonnull_args)
686		      || bitmap_bit_p (nonnull_args, i))
687		    {
688		      sm_ctxt->warn_for_state
689			(node, stmt, arg, m_unchecked,
690			 new possible_null_arg (*this, arg, callee_fndecl, i));
691		      sm_ctxt->on_transition (node, stmt, arg, m_unchecked,
692					      m_nonnull);
693
694		      sm_ctxt->warn_for_state
695			(node, stmt, arg, m_null,
696			 new null_arg (*this, arg, callee_fndecl, i));
697		      sm_ctxt->on_transition (node, stmt, arg, m_null, m_stop);
698		    }
699		}
700	      BITMAP_FREE (nonnull_args);
701	    }
702	}
703      }
704
705  if (tree lhs = is_zero_assignment (stmt))
706    if (any_pointer_p (lhs))
707      on_zero_assignment (sm_ctxt, node, stmt,lhs);
708
709  if (const gassign *assign_stmt = dyn_cast <const gassign *> (stmt))
710    {
711      enum tree_code op = gimple_assign_rhs_code (assign_stmt);
712      if (op == ADDR_EXPR)
713	{
714	  tree lhs = gimple_assign_lhs (assign_stmt);
715	  if (lhs)
716	    {
717	      lhs = sm_ctxt->get_readable_tree (lhs);
718	      sm_ctxt->on_transition (node, stmt, lhs, m_start, m_non_heap);
719	    }
720	}
721    }
722
723  /* Handle dereferences.  */
724  for (unsigned i = 0; i < gimple_num_ops (stmt); i++)
725    {
726      tree op = gimple_op (stmt, i);
727      if (!op)
728	continue;
729      if (TREE_CODE (op) == COMPONENT_REF)
730	op = TREE_OPERAND (op, 0);
731
732      if (TREE_CODE (op) == MEM_REF)
733	{
734	  tree arg = TREE_OPERAND (op, 0);
735	  arg = sm_ctxt->get_readable_tree (arg);
736
737	  sm_ctxt->warn_for_state (node, stmt, arg, m_unchecked,
738				   new possible_null_deref (*this, arg));
739	  sm_ctxt->on_transition (node, stmt, arg, m_unchecked, m_nonnull);
740
741	  sm_ctxt->warn_for_state (node, stmt, arg, m_null,
742				   new null_deref (*this, arg));
743	  sm_ctxt->on_transition (node, stmt, arg, m_null, m_stop);
744
745	  sm_ctxt->warn_for_state (node, stmt, arg, m_freed,
746				   new use_after_free (*this, arg));
747	  sm_ctxt->on_transition (node, stmt, arg, m_freed, m_stop);
748	}
749    }
750  return false;
751}
752
753/* Implementation of state_machine::on_phi vfunc for malloc_state_machine.  */
754
755void
756malloc_state_machine::on_phi (sm_context *sm_ctxt,
757			      const supernode *node,
758			      const gphi *phi,
759			      tree rhs) const
760{
761  if (zerop (rhs))
762    {
763      tree lhs = gimple_phi_result (phi);
764      on_zero_assignment (sm_ctxt, node, phi, lhs);
765    }
766}
767
768/* Implementation of state_machine::on_condition vfunc for malloc_state_machine.
769   Potentially transition state 'unchecked' to 'nonnull' or to 'null'.  */
770
771void
772malloc_state_machine::on_condition (sm_context *sm_ctxt,
773				    const supernode *node,
774				    const gimple *stmt,
775				    tree lhs,
776				    enum tree_code op,
777				    tree rhs) const
778{
779  if (!zerop (rhs))
780    return;
781
782  if (!any_pointer_p (lhs))
783    return;
784  if (!any_pointer_p (rhs))
785    return;
786
787  if (op == NE_EXPR)
788    {
789      log ("got 'ARG != 0' match");
790      sm_ctxt->on_transition (node, stmt,
791			      lhs, m_unchecked, m_nonnull);
792    }
793  else if (op == EQ_EXPR)
794    {
795      log ("got 'ARG == 0' match");
796      sm_ctxt->on_transition (node, stmt,
797			      lhs, m_unchecked, m_null);
798    }
799}
800
801/* Implementation of state_machine::can_purge_p vfunc for malloc_state_machine.
802   Don't allow purging of pointers in state 'unchecked' or 'nonnull'
803   (to avoid false leak reports).  */
804
805bool
806malloc_state_machine::can_purge_p (state_t s) const
807{
808  return s != m_unchecked && s != m_nonnull;
809}
810
811/* Implementation of state_machine::on_leak vfunc for malloc_state_machine
812   (for complaining about leaks of pointers in state 'unchecked' and
813   'nonnull').  */
814
815pending_diagnostic *
816malloc_state_machine::on_leak (tree var) const
817{
818  return new malloc_leak (*this, var);
819}
820
821/* Shared logic for handling GIMPLE_ASSIGNs and GIMPLE_PHIs that
822   assign zero to LHS.  */
823
824void
825malloc_state_machine::on_zero_assignment (sm_context *sm_ctxt,
826					  const supernode *node,
827					  const gimple *stmt,
828					  tree lhs) const
829{
830  sm_ctxt->on_transition (node, stmt, lhs, m_start, m_null);
831  sm_ctxt->on_transition (node, stmt, lhs, m_unchecked, m_null);
832  sm_ctxt->on_transition (node, stmt, lhs, m_nonnull, m_null);
833  sm_ctxt->on_transition (node, stmt, lhs, m_freed, m_null);
834}
835
836} // anonymous namespace
837
838/* Internal interface to this file. */
839
840state_machine *
841make_malloc_state_machine (logger *logger)
842{
843  return new malloc_state_machine (logger);
844}
845
846} // namespace ana
847
848#endif /* #if ENABLE_ANALYZER */
849