analyzer: add heuristics for switch on enum type [PR105273]
[platform/upstream/gcc.git] / gcc / analyzer / sm-taint.cc
1 /* An experimental state machine, for tracking "taint": unsanitized uses
2    of data potentially under an attacker's control.
3
4    Copyright (C) 2019-2022 Free Software Foundation, Inc.
5    Contributed by David Malcolm <dmalcolm@redhat.com>.
6
7 This file is part of GCC.
8
9 GCC is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3, or (at your option)
12 any later version.
13
14 GCC is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING3.  If not see
21 <http://www.gnu.org/licenses/>.  */
22
23 #include "config.h"
24 #define INCLUDE_MEMORY
25 #include "system.h"
26 #include "coretypes.h"
27 #include "make-unique.h"
28 #include "tree.h"
29 #include "function.h"
30 #include "basic-block.h"
31 #include "gimple.h"
32 #include "options.h"
33 #include "diagnostic-path.h"
34 #include "diagnostic-metadata.h"
35 #include "analyzer/analyzer.h"
36 #include "analyzer/analyzer-logging.h"
37 #include "gimple-iterator.h"
38 #include "ordered-hash-map.h"
39 #include "cgraph.h"
40 #include "cfg.h"
41 #include "digraph.h"
42 #include "stringpool.h"
43 #include "attribs.h"
44 #include "analyzer/supergraph.h"
45 #include "analyzer/call-string.h"
46 #include "analyzer/program-point.h"
47 #include "analyzer/store.h"
48 #include "analyzer/region-model.h"
49 #include "analyzer/sm.h"
50 #include "analyzer/program-state.h"
51 #include "analyzer/pending-diagnostic.h"
52 #include "analyzer/constraint-manager.h"
53
54 #if ENABLE_ANALYZER
55
56 namespace ana {
57
58 namespace {
59
60 /* An enum for describing tainted values.  */
61
62 enum bounds
63 {
64   /* This tainted value has no upper or lower bound.  */
65   BOUNDS_NONE,
66
67   /* This tainted value has an upper bound but not lower bound.  */
68   BOUNDS_UPPER,
69
70   /* This tainted value has a lower bound but no upper bound.  */
71   BOUNDS_LOWER
72 };
73
74 /* An experimental state machine, for tracking "taint": unsanitized uses
75    of data potentially under an attacker's control.  */
76
77 class taint_state_machine : public state_machine
78 {
79 public:
80   taint_state_machine (logger *logger);
81
82   bool inherited_state_p () const final override { return true; }
83
84   state_t alt_get_inherited_state (const sm_state_map &map,
85                                    const svalue *sval,
86                                    const extrinsic_state &ext_state)
87     const final override;
88
89   bool on_stmt (sm_context *sm_ctxt,
90                 const supernode *node,
91                 const gimple *stmt) const final override;
92
93   void on_condition (sm_context *sm_ctxt,
94                      const supernode *node,
95                      const gimple *stmt,
96                      const svalue *lhs,
97                      enum tree_code op,
98                      const svalue *rhs) const final override;
99   void on_bounded_ranges (sm_context *sm_ctxt,
100                           const supernode *node,
101                           const gimple *stmt,
102                           const svalue &sval,
103                           const bounded_ranges &ranges) const final override;
104
105   bool can_purge_p (state_t s) const final override;
106
107   bool get_taint (state_t s, tree type, enum bounds *out) const;
108
109   state_t combine_states (state_t s0, state_t s1) const;
110
111 private:
112   void check_control_flow_arg_for_taint (sm_context *sm_ctxt,
113                                          const gimple *stmt,
114                                          tree expr) const;
115
116   void check_for_tainted_size_arg (sm_context *sm_ctxt,
117                                    const supernode *node,
118                                    const gcall *call,
119                                    tree callee_fndecl) const;
120   void check_for_tainted_divisor (sm_context *sm_ctxt,
121                                   const supernode *node,
122                                   const gassign *assign) const;
123
124 public:
125   /* State for a "tainted" value: unsanitized data potentially under an
126      attacker's control.  */
127   state_t m_tainted;
128
129   /* State for a "tainted" value that has a lower bound.  */
130   state_t m_has_lb;
131
132   /* State for a "tainted" value that has an upper bound.  */
133   state_t m_has_ub;
134
135   /* Stop state, for a value we don't want to track any more.  */
136   state_t m_stop;
137
138   /* Global state, for when the last condition had tainted arguments.  */
139   state_t m_tainted_control_flow;
140 };
141
142 /* Class for diagnostics relating to taint_state_machine.  */
143
144 class taint_diagnostic : public pending_diagnostic
145 {
146 public:
147   taint_diagnostic (const taint_state_machine &sm, tree arg,
148                     enum bounds has_bounds)
149   : m_sm (sm), m_arg (arg), m_has_bounds (has_bounds)
150   {}
151
152   bool subclass_equal_p (const pending_diagnostic &base_other) const override
153   {
154     const taint_diagnostic &other = (const taint_diagnostic &)base_other;
155     return (same_tree_p (m_arg, other.m_arg)
156             && m_has_bounds == other.m_has_bounds);
157   }
158
159   label_text describe_state_change (const evdesc::state_change &change) override
160   {
161     if (change.m_new_state == m_sm.m_tainted)
162       {
163         if (change.m_origin)
164           return change.formatted_print ("%qE has an unchecked value here"
165                                          " (from %qE)",
166                                          change.m_expr, change.m_origin);
167         else
168           return change.formatted_print ("%qE gets an unchecked value here",
169                                          change.m_expr);
170       }
171     else if (change.m_new_state == m_sm.m_has_lb)
172       return change.formatted_print ("%qE has its lower bound checked here",
173                                      change.m_expr);
174     else if (change.m_new_state == m_sm.m_has_ub)
175       return change.formatted_print ("%qE has its upper bound checked here",
176                                      change.m_expr);
177     return label_text ();
178   }
179
180   diagnostic_event::meaning
181   get_meaning_for_state_change (const evdesc::state_change &change)
182     const final override
183   {
184     if (change.m_new_state == m_sm.m_tainted)
185       return diagnostic_event::meaning (diagnostic_event::VERB_acquire,
186                                         diagnostic_event::NOUN_taint);
187     return diagnostic_event::meaning ();
188   }
189
190 protected:
191   const taint_state_machine &m_sm;
192   tree m_arg;
193   enum bounds m_has_bounds;
194 };
195
196 /* Concrete taint_diagnostic subclass for reporting attacker-controlled
197    array index.  */
198
199 class tainted_array_index : public taint_diagnostic
200 {
201 public:
202   tainted_array_index (const taint_state_machine &sm, tree arg,
203                        enum bounds has_bounds)
204   : taint_diagnostic (sm, arg, has_bounds)
205   {}
206
207   const char *get_kind () const final override { return "tainted_array_index"; }
208
209   int get_controlling_option () const final override
210   {
211     return OPT_Wanalyzer_tainted_array_index;
212   }
213
214   bool emit (rich_location *rich_loc) final override
215   {
216     diagnostic_metadata m;
217     /* CWE-129: "Improper Validation of Array Index".  */
218     m.add_cwe (129);
219     if (m_arg)
220       switch (m_has_bounds)
221         {
222         default:
223           gcc_unreachable ();
224         case BOUNDS_NONE:
225           return warning_meta (rich_loc, m, get_controlling_option (),
226                                "use of attacker-controlled value %qE"
227                                " in array lookup without bounds checking",
228                                m_arg);
229           break;
230         case BOUNDS_UPPER:
231           return warning_meta (rich_loc, m, get_controlling_option (),
232                                "use of attacker-controlled value %qE"
233                                " in array lookup without checking for negative",
234                                m_arg);
235           break;
236         case BOUNDS_LOWER:
237           return warning_meta (rich_loc, m, get_controlling_option (),
238                                "use of attacker-controlled value %qE"
239                                " in array lookup without upper-bounds checking",
240                                m_arg);
241           break;
242         }
243     else
244       switch (m_has_bounds)
245         {
246         default:
247           gcc_unreachable ();
248         case BOUNDS_NONE:
249           return warning_meta (rich_loc, m, get_controlling_option (),
250                                "use of attacker-controlled value"
251                                " in array lookup without bounds checking");
252           break;
253         case BOUNDS_UPPER:
254           return warning_meta (rich_loc, m, get_controlling_option (),
255                                "use of attacker-controlled value"
256                                " in array lookup without checking for"
257                                " negative");
258           break;
259         case BOUNDS_LOWER:
260           return warning_meta (rich_loc, m, get_controlling_option (),
261                                "use of attacker-controlled value"
262                                " in array lookup without upper-bounds"
263                                " checking");
264           break;
265         }
266   }
267
268   label_text describe_final_event (const evdesc::final_event &ev) final override
269   {
270     if (m_arg)
271       switch (m_has_bounds)
272         {
273         default:
274           gcc_unreachable ();
275         case BOUNDS_NONE:
276           return ev.formatted_print
277             ("use of attacker-controlled value %qE in array lookup"
278              " without bounds checking",
279              m_arg);
280         case BOUNDS_UPPER:
281           return ev.formatted_print
282             ("use of attacker-controlled value %qE"
283              " in array lookup without checking for negative",
284              m_arg);
285         case BOUNDS_LOWER:
286           return ev.formatted_print
287             ("use of attacker-controlled value %qE"
288              " in array lookup without upper-bounds checking",
289              m_arg);
290         }
291     else
292       switch (m_has_bounds)
293         {
294         default:
295           gcc_unreachable ();
296         case BOUNDS_NONE:
297           return ev.formatted_print
298             ("use of attacker-controlled value in array lookup"
299              " without bounds checking");
300         case BOUNDS_UPPER:
301           return ev.formatted_print
302             ("use of attacker-controlled value"
303              " in array lookup without checking for negative");
304         case BOUNDS_LOWER:
305           return ev.formatted_print
306             ("use of attacker-controlled value"
307              " in array lookup without upper-bounds checking");
308         }
309   }
310 };
311
312 /* Concrete taint_diagnostic subclass for reporting attacker-controlled
313    pointer offset.  */
314
315 class tainted_offset : public taint_diagnostic
316 {
317 public:
318   tainted_offset (const taint_state_machine &sm, tree arg,
319                        enum bounds has_bounds)
320   : taint_diagnostic (sm, arg, has_bounds)
321   {}
322
323   const char *get_kind () const final override { return "tainted_offset"; }
324
325   int get_controlling_option () const final override
326   {
327     return OPT_Wanalyzer_tainted_offset;
328   }
329
330   bool emit (rich_location *rich_loc) final override
331   {
332     diagnostic_metadata m;
333     /* CWE-823: "Use of Out-of-range Pointer Offset".  */
334     m.add_cwe (823);
335     if (m_arg)
336       switch (m_has_bounds)
337         {
338         default:
339           gcc_unreachable ();
340         case BOUNDS_NONE:
341           return warning_meta (rich_loc, m, get_controlling_option (),
342                                "use of attacker-controlled value %qE as offset"
343                                " without bounds checking",
344                                m_arg);
345           break;
346         case BOUNDS_UPPER:
347           return warning_meta (rich_loc, m, get_controlling_option (),
348                                "use of attacker-controlled value %qE as offset"
349                                " without lower-bounds checking",
350                                m_arg);
351           break;
352         case BOUNDS_LOWER:
353           return warning_meta (rich_loc, m, get_controlling_option (),
354                                "use of attacker-controlled value %qE as offset"
355                                " without upper-bounds checking",
356                                m_arg);
357           break;
358         }
359     else
360       switch (m_has_bounds)
361         {
362         default:
363           gcc_unreachable ();
364         case BOUNDS_NONE:
365           return warning_meta (rich_loc, m, get_controlling_option (),
366                                "use of attacker-controlled value as offset"
367                                " without bounds checking");
368           break;
369         case BOUNDS_UPPER:
370           return warning_meta (rich_loc, m, get_controlling_option (),
371                                "use of attacker-controlled value as offset"
372                                " without lower-bounds checking");
373           break;
374         case BOUNDS_LOWER:
375           return warning_meta (rich_loc, m, get_controlling_option (),
376                                "use of attacker-controlled value as offset"
377                                " without upper-bounds checking");
378           break;
379         }
380   }
381
382   label_text describe_final_event (const evdesc::final_event &ev) final override
383   {
384     if (m_arg)
385       switch (m_has_bounds)
386         {
387         default:
388           gcc_unreachable ();
389         case BOUNDS_NONE:
390           return ev.formatted_print ("use of attacker-controlled value %qE"
391                                      " as offset without bounds checking",
392                                      m_arg);
393         case BOUNDS_UPPER:
394           return ev.formatted_print ("use of attacker-controlled value %qE"
395                                      " as offset without lower-bounds checking",
396                                      m_arg);
397         case BOUNDS_LOWER:
398           return ev.formatted_print ("use of attacker-controlled value %qE"
399                                      " as offset without upper-bounds checking",
400                                      m_arg);
401         }
402     else
403       switch (m_has_bounds)
404         {
405         default:
406           gcc_unreachable ();
407         case BOUNDS_NONE:
408           return ev.formatted_print ("use of attacker-controlled value"
409                                      " as offset without bounds checking");
410         case BOUNDS_UPPER:
411           return ev.formatted_print ("use of attacker-controlled value"
412                                      " as offset without lower-bounds"
413                                      " checking");
414         case BOUNDS_LOWER:
415           return ev.formatted_print ("use of attacker-controlled value"
416                                      " as offset without upper-bounds"
417                                      " checking");
418         }
419   }
420 };
421
422 /* Concrete taint_diagnostic subclass for reporting attacker-controlled
423    size.  */
424
425 class tainted_size : public taint_diagnostic
426 {
427 public:
428   tainted_size (const taint_state_machine &sm, tree arg,
429                 enum bounds has_bounds)
430   : taint_diagnostic (sm, arg, has_bounds)
431   {}
432
433   const char *get_kind () const override { return "tainted_size"; }
434
435   int get_controlling_option () const final override
436   {
437     return OPT_Wanalyzer_tainted_size;
438   }
439
440   bool emit (rich_location *rich_loc) override
441   {
442     /* "CWE-129: Improper Validation of Array Index".  */
443     diagnostic_metadata m;
444     m.add_cwe (129);
445     if (m_arg)
446       switch (m_has_bounds)
447         {
448         default:
449           gcc_unreachable ();
450         case BOUNDS_NONE:
451           return warning_meta (rich_loc, m, get_controlling_option (),
452                                "use of attacker-controlled value %qE as size"
453                                " without bounds checking",
454                                m_arg);
455           break;
456         case BOUNDS_UPPER:
457           return warning_meta (rich_loc, m, get_controlling_option (),
458                                "use of attacker-controlled value %qE as size"
459                                " without lower-bounds checking",
460                                m_arg);
461           break;
462         case BOUNDS_LOWER:
463           return warning_meta (rich_loc, m, get_controlling_option (),
464                                "use of attacker-controlled value %qE as size"
465                                " without upper-bounds checking",
466                                m_arg);
467           break;
468         }
469     else
470       switch (m_has_bounds)
471         {
472         default:
473           gcc_unreachable ();
474         case BOUNDS_NONE:
475           return warning_meta (rich_loc, m, get_controlling_option (),
476                                "use of attacker-controlled value as size"
477                                " without bounds checking");
478           break;
479         case BOUNDS_UPPER:
480           return warning_meta (rich_loc, m, get_controlling_option (),
481                                "use of attacker-controlled value as size"
482                                " without lower-bounds checking");
483           break;
484         case BOUNDS_LOWER:
485           return warning_meta (rich_loc, m, get_controlling_option (),
486                                "use of attacker-controlled value as size"
487                                " without upper-bounds checking");
488           break;
489         }
490   }
491
492   label_text describe_final_event (const evdesc::final_event &ev) final override
493   {
494     if (m_arg)
495       switch (m_has_bounds)
496         {
497         default:
498           gcc_unreachable ();
499         case BOUNDS_NONE:
500           return ev.formatted_print ("use of attacker-controlled value %qE"
501                                      " as size without bounds checking",
502                                      m_arg);
503         case BOUNDS_UPPER:
504           return ev.formatted_print ("use of attacker-controlled value %qE"
505                                      " as size without lower-bounds checking",
506                                      m_arg);
507         case BOUNDS_LOWER:
508           return ev.formatted_print ("use of attacker-controlled value %qE"
509                                      " as size without upper-bounds checking",
510                                      m_arg);
511         }
512     else
513       switch (m_has_bounds)
514         {
515         default:
516           gcc_unreachable ();
517         case BOUNDS_NONE:
518           return ev.formatted_print ("use of attacker-controlled value"
519                                      " as size without bounds checking");
520         case BOUNDS_UPPER:
521           return ev.formatted_print ("use of attacker-controlled value"
522                                      " as size without lower-bounds checking");
523         case BOUNDS_LOWER:
524           return ev.formatted_print ("use of attacker-controlled value"
525                                      " as size without upper-bounds checking");
526         }
527   }
528 };
529
530 /* Subclass of tainted_size for reporting on tainted size values
531    passed to an external function annotated with attribute "access".  */
532
533 class tainted_access_attrib_size : public tainted_size
534 {
535 public:
536   tainted_access_attrib_size (const taint_state_machine &sm, tree arg,
537                               enum bounds has_bounds, tree callee_fndecl,
538                               unsigned size_argno, const char *access_str)
539   : tainted_size (sm, arg, has_bounds),
540     m_callee_fndecl (callee_fndecl),
541     m_size_argno (size_argno), m_access_str (access_str)
542   {
543   }
544
545   const char *get_kind () const override
546   {
547     return "tainted_access_attrib_size";
548   }
549
550   bool emit (rich_location *rich_loc) final override
551   {
552     bool warned = tainted_size::emit (rich_loc);
553     if (warned)
554       {
555         inform (DECL_SOURCE_LOCATION (m_callee_fndecl),
556                 "parameter %i of %qD marked as a size via attribute %qs",
557                 m_size_argno + 1, m_callee_fndecl, m_access_str);
558       }
559     return warned;
560   }
561
562 private:
563   tree m_callee_fndecl;
564   unsigned m_size_argno;
565   const char *m_access_str;
566 };
567
568 /* Concrete taint_diagnostic subclass for reporting attacker-controlled
569    divisor (so that an attacker can trigger a divide by zero).  */
570
571 class tainted_divisor : public taint_diagnostic
572 {
573 public:
574   tainted_divisor (const taint_state_machine &sm, tree arg,
575                    enum bounds has_bounds)
576   : taint_diagnostic (sm, arg, has_bounds)
577   {}
578
579   const char *get_kind () const final override { return "tainted_divisor"; }
580
581   int get_controlling_option () const final override
582   {
583     return OPT_Wanalyzer_tainted_divisor;
584   }
585
586   bool emit (rich_location *rich_loc) final override
587   {
588     diagnostic_metadata m;
589     /* CWE-369: "Divide By Zero".  */
590     m.add_cwe (369);
591     if (m_arg)
592       return warning_meta (rich_loc, m, get_controlling_option (),
593                            "use of attacker-controlled value %qE as divisor"
594                            " without checking for zero",
595                            m_arg);
596     else
597       return warning_meta (rich_loc, m, get_controlling_option (),
598                            "use of attacker-controlled value as divisor"
599                            " without checking for zero");
600   }
601
602   label_text describe_final_event (const evdesc::final_event &ev) final override
603   {
604     if (m_arg)
605       return ev.formatted_print
606         ("use of attacker-controlled value %qE as divisor"
607          " without checking for zero",
608          m_arg);
609     else
610       return ev.formatted_print
611         ("use of attacker-controlled value as divisor"
612          " without checking for zero");
613   }
614 };
615
616 /* Concrete taint_diagnostic subclass for reporting attacker-controlled
617    size of a dynamic allocation.  */
618
619 class tainted_allocation_size : public taint_diagnostic
620 {
621 public:
622   tainted_allocation_size (const taint_state_machine &sm, tree arg,
623                            enum bounds has_bounds, enum memory_space mem_space)
624   : taint_diagnostic (sm, arg, has_bounds),
625     m_mem_space (mem_space)
626   {
627   }
628
629   const char *get_kind () const final override
630   {
631     return "tainted_allocation_size";
632   }
633
634   bool subclass_equal_p (const pending_diagnostic &base_other) const override
635   {
636     if (!taint_diagnostic::subclass_equal_p (base_other))
637       return false;
638     const tainted_allocation_size &other
639       = (const tainted_allocation_size &)base_other;
640     return m_mem_space == other.m_mem_space;
641   }
642
643   int get_controlling_option () const final override
644   {
645     return OPT_Wanalyzer_tainted_allocation_size;
646   }
647
648   bool emit (rich_location *rich_loc) final override
649   {
650     diagnostic_metadata m;
651     /* "CWE-789: Memory Allocation with Excessive Size Value".  */
652     m.add_cwe (789);
653
654     bool warned;
655     if (m_arg)
656       switch (m_has_bounds)
657         {
658         default:
659           gcc_unreachable ();
660         case BOUNDS_NONE:
661           warned = warning_meta (rich_loc, m, get_controlling_option (),
662                                  "use of attacker-controlled value %qE as"
663                                  " allocation size without bounds checking",
664                                  m_arg);
665           break;
666         case BOUNDS_UPPER:
667           warned = warning_meta (rich_loc, m, get_controlling_option (),
668                                  "use of attacker-controlled value %qE as"
669                                  " allocation size without"
670                                  " lower-bounds checking",
671                                  m_arg);
672           break;
673         case BOUNDS_LOWER:
674           warned = warning_meta (rich_loc, m, get_controlling_option (),
675                                  "use of attacker-controlled value %qE as"
676                                  " allocation size without"
677                                  " upper-bounds checking",
678                                  m_arg);
679           break;
680         }
681     else
682       switch (m_has_bounds)
683         {
684         default:
685           gcc_unreachable ();
686         case BOUNDS_NONE:
687           warned = warning_meta (rich_loc, m, get_controlling_option (),
688                                  "use of attacker-controlled value as"
689                                  " allocation size without bounds"
690                                  " checking");
691           break;
692         case BOUNDS_UPPER:
693           warned = warning_meta (rich_loc, m, get_controlling_option (),
694                                  "use of attacker-controlled value as"
695                                  " allocation size without"
696                                  " lower-bounds checking");
697           break;
698         case BOUNDS_LOWER:
699           warned = warning_meta (rich_loc, m, get_controlling_option (),
700                                  "use of attacker-controlled value as"
701                                  " allocation size without"
702                                  " upper-bounds checking");
703           break;
704         }
705     if (warned)
706       {
707         location_t loc = rich_loc->get_loc ();
708         switch (m_mem_space)
709           {
710           default:
711             break;
712           case MEMSPACE_STACK:
713             inform (loc, "stack-based allocation");
714             break;
715           case MEMSPACE_HEAP:
716             inform (loc, "heap-based allocation");
717             break;
718           }
719       }
720     return warned;
721   }
722
723   label_text describe_final_event (const evdesc::final_event &ev) final override
724   {
725     if (m_arg)
726       switch (m_has_bounds)
727         {
728         default:
729           gcc_unreachable ();
730         case BOUNDS_NONE:
731           return ev.formatted_print
732             ("use of attacker-controlled value %qE as allocation size"
733              " without bounds checking",
734              m_arg);
735         case BOUNDS_UPPER:
736           return ev.formatted_print
737             ("use of attacker-controlled value %qE as allocation size"
738              " without lower-bounds checking",
739              m_arg);
740         case BOUNDS_LOWER:
741           return ev.formatted_print
742             ("use of attacker-controlled value %qE as allocation size"
743              " without upper-bounds checking",
744              m_arg);
745         }
746     else
747       switch (m_has_bounds)
748         {
749         default:
750           gcc_unreachable ();
751         case BOUNDS_NONE:
752           return ev.formatted_print
753             ("use of attacker-controlled value as allocation size"
754              " without bounds checking");
755         case BOUNDS_UPPER:
756           return ev.formatted_print
757             ("use of attacker-controlled value as allocation size"
758              " without lower-bounds checking");
759         case BOUNDS_LOWER:
760           return ev.formatted_print
761             ("use of attacker-controlled value as allocation size"
762              " without upper-bounds checking");
763         }
764   }
765
766 private:
767   enum memory_space m_mem_space;
768 };
769
770 /* Concrete taint_diagnostic subclass for reporting attacker-controlled
771    value being used as part of the condition of an assertion.  */
772
773 class tainted_assertion : public taint_diagnostic
774 {
775 public:
776   tainted_assertion (const taint_state_machine &sm, tree arg,
777                      tree assert_failure_fndecl)
778   : taint_diagnostic (sm, arg, BOUNDS_NONE),
779     m_assert_failure_fndecl (assert_failure_fndecl)
780   {
781     gcc_assert (m_assert_failure_fndecl);
782   }
783
784   const char *get_kind () const final override
785   {
786     return "tainted_assertion";
787   }
788
789   bool subclass_equal_p (const pending_diagnostic &base_other) const override
790   {
791     if (!taint_diagnostic::subclass_equal_p (base_other))
792       return false;
793     const tainted_assertion &other
794       = (const tainted_assertion &)base_other;
795     return m_assert_failure_fndecl == other.m_assert_failure_fndecl;
796   }
797
798   int get_controlling_option () const final override
799   {
800     return OPT_Wanalyzer_tainted_assertion;
801   }
802
803   bool emit (rich_location *rich_loc) final override
804   {
805     diagnostic_metadata m;
806     /* "CWE-617: Reachable Assertion".  */
807     m.add_cwe (617);
808
809     return warning_meta (rich_loc, m, get_controlling_option (),
810                          "use of attacked-controlled value in"
811                          " condition for assertion");
812   }
813
814   location_t fixup_location (location_t loc,
815                              bool primary) const final override
816   {
817     if (primary)
818       /* For the primary location we want to avoid being in e.g. the
819          <assert.h> system header, since this would suppress the
820          diagnostic.  */
821       return expansion_point_location_if_in_system_header (loc);
822     else if (in_system_header_at (loc))
823       /* For events, we want to show the implemenation of the assert
824          macro when we're describing them.  */
825       return linemap_resolve_location (line_table, loc,
826                                        LRK_SPELLING_LOCATION,
827                                        NULL);
828     else
829       return pending_diagnostic::fixup_location (loc, primary);
830   }
831
832   label_text describe_state_change (const evdesc::state_change &change) override
833   {
834     if (change.m_new_state == m_sm.m_tainted_control_flow)
835       return change.formatted_print
836         ("use of attacker-controlled value for control flow");
837     return taint_diagnostic::describe_state_change (change);
838   }
839
840   label_text describe_final_event (const evdesc::final_event &ev) final override
841   {
842     if (mention_noreturn_attribute_p ())
843       return ev.formatted_print
844         ("treating %qE as an assertion failure handler"
845          " due to %<__attribute__((__noreturn__))%>",
846          m_assert_failure_fndecl);
847     else
848       return ev.formatted_print
849         ("treating %qE as an assertion failure handler",
850          m_assert_failure_fndecl);
851   }
852
853 private:
854   bool mention_noreturn_attribute_p () const
855   {
856     if (fndecl_built_in_p (m_assert_failure_fndecl, BUILT_IN_UNREACHABLE))
857       return false;
858     return true;
859   }
860
861   tree m_assert_failure_fndecl;
862 };
863
864 /* taint_state_machine's ctor.  */
865
866 taint_state_machine::taint_state_machine (logger *logger)
867 : state_machine ("taint", logger)
868 {
869   m_tainted = add_state ("tainted");
870   m_has_lb = add_state ("has_lb");
871   m_has_ub = add_state ("has_ub");
872   m_stop = add_state ("stop");
873   m_tainted_control_flow = add_state ("tainted-control-flow");
874 }
875
876 state_machine::state_t
877 taint_state_machine::alt_get_inherited_state (const sm_state_map &map,
878                                               const svalue *sval,
879                                               const extrinsic_state &ext_state)
880   const
881 {
882   switch (sval->get_kind ())
883     {
884     default:
885       break;
886     case SK_UNARYOP:
887       {
888         const unaryop_svalue *unaryop_sval
889           = as_a <const unaryop_svalue *> (sval);
890         enum tree_code op = unaryop_sval->get_op ();
891         const svalue *arg = unaryop_sval->get_arg ();
892         switch (op)
893           {
894           case NOP_EXPR:
895             {
896               state_t arg_state = map.get_state (arg, ext_state);
897               return arg_state;
898             }
899           default:
900             break;
901           }
902       }
903       break;
904     case SK_BINOP:
905       {
906         const binop_svalue *binop_sval = as_a <const binop_svalue *> (sval);
907         enum tree_code op = binop_sval->get_op ();
908         const svalue *arg0 = binop_sval->get_arg0 ();
909         const svalue *arg1 = binop_sval->get_arg1 ();
910         switch (op)
911           {
912           default:
913             break;
914
915           case EQ_EXPR:
916           case GE_EXPR:
917           case LE_EXPR:
918           case NE_EXPR:
919           case GT_EXPR:
920           case LT_EXPR:
921           case UNORDERED_EXPR:
922           case ORDERED_EXPR:
923           case PLUS_EXPR:
924           case MINUS_EXPR:
925           case MULT_EXPR:
926           case POINTER_PLUS_EXPR:
927           case TRUNC_DIV_EXPR:
928           case TRUNC_MOD_EXPR:
929             {
930               state_t arg0_state = map.get_state (arg0, ext_state);
931               state_t arg1_state = map.get_state (arg1, ext_state);
932               return combine_states (arg0_state, arg1_state);
933             }
934             break;
935
936           case BIT_AND_EXPR:
937           case RSHIFT_EXPR:
938             return NULL;
939           }
940       }
941       break;
942     }
943   return NULL;
944 }
945
946 /* Return true iff FNDECL should be considered to be an assertion failure
947    handler by -Wanalyzer-tainted-assertion. */
948
949 static bool
950 is_assertion_failure_handler_p (tree fndecl)
951 {
952   // i.e. "noreturn"
953   if (TREE_THIS_VOLATILE (fndecl))
954     return true;
955
956   return false;
957 }
958
959 /* Implementation of state_machine::on_stmt vfunc for taint_state_machine.  */
960
961 bool
962 taint_state_machine::on_stmt (sm_context *sm_ctxt,
963                                const supernode *node,
964                                const gimple *stmt) const
965 {
966   if (const gcall *call = dyn_cast <const gcall *> (stmt))
967     if (tree callee_fndecl = sm_ctxt->get_fndecl_for_call (call))
968       {
969         if (is_named_call_p (callee_fndecl, "fread", call, 4))
970           {
971             tree arg = gimple_call_arg (call, 0);
972
973             sm_ctxt->on_transition (node, stmt, arg, m_start, m_tainted);
974
975             /* Dereference an ADDR_EXPR.  */
976             // TODO: should the engine do this?
977             if (TREE_CODE (arg) == ADDR_EXPR)
978               sm_ctxt->on_transition (node, stmt, TREE_OPERAND (arg, 0),
979                                       m_start, m_tainted);
980             return true;
981           }
982
983         /* External function with "access" attribute. */
984         if (sm_ctxt->unknown_side_effects_p ())
985           check_for_tainted_size_arg (sm_ctxt, node, call, callee_fndecl);
986
987         if (is_assertion_failure_handler_p (callee_fndecl)
988             && sm_ctxt->get_global_state () == m_tainted_control_flow)
989           {
990             sm_ctxt->warn (node, call, NULL_TREE,
991                            make_unique<tainted_assertion> (*this, NULL_TREE,
992                                                            callee_fndecl));
993           }
994       }
995   // TODO: ...etc; many other sources of untrusted data
996
997   if (const gassign *assign = dyn_cast <const gassign *> (stmt))
998     {
999       enum tree_code op = gimple_assign_rhs_code (assign);
1000
1001       switch (op)
1002         {
1003         default:
1004           break;
1005         case TRUNC_DIV_EXPR:
1006         case CEIL_DIV_EXPR:
1007         case FLOOR_DIV_EXPR:
1008         case ROUND_DIV_EXPR:
1009         case TRUNC_MOD_EXPR:
1010         case CEIL_MOD_EXPR:
1011         case FLOOR_MOD_EXPR:
1012         case ROUND_MOD_EXPR:
1013         case RDIV_EXPR:
1014         case EXACT_DIV_EXPR:
1015           check_for_tainted_divisor (sm_ctxt, node, assign);
1016           break;
1017         }
1018     }
1019
1020   if (const gcond *cond = dyn_cast <const gcond *> (stmt))
1021     {
1022       /* Reset the state of "tainted-control-flow" before each
1023          control flow statement, so that only the last one before
1024          an assertion-failure-handler counts.  */
1025       sm_ctxt->set_global_state (m_start);
1026       check_control_flow_arg_for_taint (sm_ctxt, cond, gimple_cond_lhs (cond));
1027       check_control_flow_arg_for_taint (sm_ctxt, cond, gimple_cond_rhs (cond));
1028     }
1029
1030   if (const gswitch *switch_ = dyn_cast <const gswitch *> (stmt))
1031     {
1032       /* Reset the state of "tainted-control-flow" before each
1033          control flow statement, so that only the last one before
1034          an assertion-failure-handler counts.  */
1035       sm_ctxt->set_global_state (m_start);
1036       check_control_flow_arg_for_taint (sm_ctxt, switch_,
1037                                         gimple_switch_index (switch_));
1038     }
1039
1040   return false;
1041 }
1042
1043 /* If EXPR is tainted, mark this execution path with the
1044    "tainted-control-flow" global state, in case we're about
1045    to call an assertion-failure-handler.  */
1046
1047 void
1048 taint_state_machine::check_control_flow_arg_for_taint (sm_context *sm_ctxt,
1049                                                        const gimple *stmt,
1050                                                        tree expr) const
1051 {
1052   const region_model *old_model = sm_ctxt->get_old_region_model ();
1053   const svalue *sval = old_model->get_rvalue (expr, NULL);
1054   state_t state = sm_ctxt->get_state (stmt, sval);
1055   enum bounds b;
1056   if (get_taint (state, TREE_TYPE (expr), &b))
1057     sm_ctxt->set_global_state (m_tainted_control_flow);
1058 }
1059
1060 /* Implementation of state_machine::on_condition vfunc for taint_state_machine.
1061    Potentially transition state 'tainted' to 'has_ub' or 'has_lb',
1062    and states 'has_ub' and 'has_lb' to 'stop'.  */
1063
1064 void
1065 taint_state_machine::on_condition (sm_context *sm_ctxt,
1066                                    const supernode *node,
1067                                    const gimple *stmt,
1068                                    const svalue *lhs,
1069                                    enum tree_code op,
1070                                    const svalue *rhs) const
1071 {
1072   if (stmt == NULL)
1073     return;
1074
1075   // TODO
1076   switch (op)
1077     {
1078       //case NE_EXPR:
1079       //case EQ_EXPR:
1080     case GE_EXPR:
1081     case GT_EXPR:
1082       {
1083         /* (LHS >= RHS) or (LHS > RHS)
1084            LHS gains a lower bound
1085            RHS gains an upper bound.  */
1086         sm_ctxt->on_transition (node, stmt, lhs, m_tainted,
1087                                 m_has_lb);
1088         sm_ctxt->on_transition (node, stmt, lhs, m_has_ub,
1089                                 m_stop);
1090         sm_ctxt->on_transition (node, stmt, rhs, m_tainted,
1091                                 m_has_ub);
1092         sm_ctxt->on_transition (node, stmt, rhs, m_has_lb,
1093                                 m_stop);
1094       }
1095       break;
1096     case LE_EXPR:
1097     case LT_EXPR:
1098       {
1099         /* Detect where build_range_check has optimized
1100            (c>=low) && (c<=high)
1101            into
1102            (c-low>=0) && (c-low<=high-low)
1103            and thus into:
1104            (unsigned)(c - low) <= (unsigned)(high-low).  */
1105         if (const binop_svalue *binop_sval
1106               = lhs->dyn_cast_binop_svalue ())
1107           {
1108             const svalue *inner_lhs = binop_sval->get_arg0 ();
1109             enum tree_code inner_op = binop_sval->get_op ();
1110             const svalue *inner_rhs = binop_sval->get_arg1 ();
1111             if (const svalue *before_cast = inner_lhs->maybe_undo_cast ())
1112               inner_lhs = before_cast;
1113             if (tree outer_rhs_cst = rhs->maybe_get_constant ())
1114               if (tree inner_rhs_cst = inner_rhs->maybe_get_constant ())
1115                 if (inner_op == PLUS_EXPR
1116                     && TREE_CODE (inner_rhs_cst) == INTEGER_CST
1117                     && TREE_CODE (outer_rhs_cst) == INTEGER_CST
1118                     && TYPE_UNSIGNED (TREE_TYPE (inner_rhs_cst))
1119                     && TYPE_UNSIGNED (TREE_TYPE (outer_rhs_cst)))
1120                   {
1121                     /* We have
1122                        (unsigned)(INNER_LHS + CST_A) </<= UNSIGNED_CST_B
1123                        and thus an optimized test of INNER_LHS (before any
1124                        cast to unsigned) against a range.
1125                        Transition any of the tainted states to the stop state.
1126                        We have to special-case this here rather than in
1127                        region_model::on_condition since we can't apply
1128                        both conditions simultaneously (we'd have a transition
1129                        from the old state to has_lb, then a transition from
1130                        the old state *again* to has_ub).  */
1131                     state_t old_state
1132                       = sm_ctxt->get_state (stmt, inner_lhs);
1133                     if (old_state == m_tainted
1134                         || old_state == m_has_lb
1135                         || old_state == m_has_ub)
1136                       sm_ctxt->set_next_state (stmt, inner_lhs, m_stop);
1137                     return;
1138                   }
1139           }
1140
1141         /* (LHS <= RHS) or (LHS < RHS)
1142            LHS gains an upper bound
1143            RHS gains a lower bound.  */
1144         sm_ctxt->on_transition (node, stmt, lhs, m_tainted,
1145                                 m_has_ub);
1146         sm_ctxt->on_transition (node, stmt, lhs, m_has_lb,
1147                                 m_stop);
1148         sm_ctxt->on_transition (node, stmt, rhs, m_tainted,
1149                                 m_has_lb);
1150         sm_ctxt->on_transition (node, stmt, rhs, m_has_ub,
1151                                 m_stop);
1152       }
1153       break;
1154     default:
1155       break;
1156     }
1157 }
1158
1159 /* Implementation of state_machine::on_bounded_ranges vfunc for
1160    taint_state_machine, for handling switch statement cases.
1161    Potentially transition state 'tainted' to 'has_ub' or 'has_lb',
1162    and states 'has_ub' and 'has_lb' to 'stop'.  */
1163
1164 void
1165 taint_state_machine::on_bounded_ranges (sm_context *sm_ctxt,
1166                                         const supernode *,
1167                                         const gimple *stmt,
1168                                         const svalue &sval,
1169                                         const bounded_ranges &ranges) const
1170 {
1171   gcc_assert (!ranges.empty_p ());
1172   gcc_assert (ranges.get_count () > 0);
1173
1174   /* We have one or more ranges; this could be a "default:", or one or
1175      more single or range cases.
1176
1177      Look at the overall endpoints to see if the ranges impose any lower
1178      bounds or upper bounds beyond those of the underlying numeric type.  */
1179
1180   tree lowest_bound = ranges.get_range (0).m_lower;
1181   tree highest_bound = ranges.get_range (ranges.get_count () - 1).m_upper;
1182   gcc_assert (lowest_bound);
1183   gcc_assert (highest_bound);
1184
1185   bool ranges_have_lb
1186     = (lowest_bound != TYPE_MIN_VALUE (TREE_TYPE (lowest_bound)));
1187   bool ranges_have_ub
1188     = (highest_bound != TYPE_MAX_VALUE (TREE_TYPE (highest_bound)));
1189
1190   if (!ranges_have_lb && !ranges_have_ub)
1191     return;
1192
1193   /* We have new bounds from the ranges; combine them with any
1194      existing bounds on SVAL.  */
1195   state_t old_state = sm_ctxt->get_state (stmt, &sval);
1196   if (old_state == m_tainted)
1197     {
1198       if (ranges_have_lb && ranges_have_ub)
1199         sm_ctxt->set_next_state (stmt, &sval, m_stop);
1200       else if (ranges_have_lb)
1201         sm_ctxt->set_next_state (stmt, &sval, m_has_lb);
1202       else if (ranges_have_ub)
1203         sm_ctxt->set_next_state (stmt, &sval, m_has_ub);
1204     }
1205   else if (old_state == m_has_ub && ranges_have_lb)
1206     sm_ctxt->set_next_state (stmt, &sval, m_stop);
1207   else if (old_state == m_has_lb && ranges_have_ub)
1208     sm_ctxt->set_next_state (stmt, &sval, m_stop);
1209 }
1210
1211 bool
1212 taint_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
1213 {
1214   return true;
1215 }
1216
1217 /* If STATE is a tainted state, write the bounds to *OUT and return true.
1218    Otherwise return false.
1219    Use the signedness of TYPE to determine if "has_ub" is tainted.  */
1220
1221 bool
1222 taint_state_machine::get_taint (state_t state, tree type,
1223                                 enum bounds *out) const
1224 {
1225   /* Unsigned types have an implicit lower bound.  */
1226   bool is_unsigned = false;
1227   if (type)
1228     if (INTEGRAL_TYPE_P (type))
1229       is_unsigned = TYPE_UNSIGNED (type);
1230
1231   /* Can't use a switch as the states are non-const.  */
1232   if (state == m_tainted)
1233     {
1234       *out = is_unsigned ? BOUNDS_LOWER : BOUNDS_NONE;
1235       return true;
1236     }
1237   else if (state == m_has_lb)
1238     {
1239       *out = BOUNDS_LOWER;
1240       return true;
1241     }
1242   else if (state == m_has_ub && !is_unsigned)
1243     {
1244       /* Missing lower bound.  */
1245       *out = BOUNDS_UPPER;
1246       return true;
1247     }
1248   return false;
1249 }
1250
1251 /* Find the most tainted state of S0 and S1.  */
1252
1253 state_machine::state_t
1254 taint_state_machine::combine_states (state_t s0, state_t s1) const
1255 {
1256   gcc_assert (s0);
1257   gcc_assert (s1);
1258   if (s0 == s1)
1259     return s0;
1260   if (s0 == m_tainted || s1 == m_tainted)
1261     return m_tainted;
1262   if (s0 == m_start)
1263     return s1;
1264   if (s1 == m_start)
1265     return s0;
1266   if (s0 == m_stop)
1267     return s1;
1268   if (s1 == m_stop)
1269     return s0;
1270   /* The only remaining combinations are one of has_ub and has_lb
1271      (in either order).  */
1272   gcc_assert ((s0 == m_has_lb && s1 == m_has_ub)
1273               || (s0 == m_has_ub && s1 == m_has_lb));
1274   return m_tainted;
1275 }
1276
1277 /* Check for calls to external functions marked with
1278    __attribute__((access)) with a size-index: complain about
1279    tainted values passed as a size to such a function.  */
1280
1281 void
1282 taint_state_machine::check_for_tainted_size_arg (sm_context *sm_ctxt,
1283                                                  const supernode *node,
1284                                                  const gcall *call,
1285                                                  tree callee_fndecl) const
1286 {
1287   tree fntype = TREE_TYPE (callee_fndecl);
1288   if (!fntype)
1289     return;
1290
1291   if (!TYPE_ATTRIBUTES (fntype))
1292     return;
1293
1294   /* Initialize a map of attribute access specifications for arguments
1295      to the function call.  */
1296   rdwr_map rdwr_idx;
1297   init_attr_rdwr_indices (&rdwr_idx, TYPE_ATTRIBUTES (fntype));
1298
1299   unsigned argno = 0;
1300
1301   for (tree iter = TYPE_ARG_TYPES (fntype); iter;
1302        iter = TREE_CHAIN (iter), ++argno)
1303     {
1304       const attr_access* access = rdwr_idx.get (argno);
1305       if (!access)
1306         continue;
1307
1308       /* Ignore any duplicate entry in the map for the size argument.  */
1309       if (access->ptrarg != argno)
1310         continue;
1311
1312       if (access->sizarg == UINT_MAX)
1313         continue;
1314
1315       tree size_arg = gimple_call_arg (call, access->sizarg);
1316
1317       state_t state = sm_ctxt->get_state (call, size_arg);
1318       enum bounds b;
1319       if (get_taint (state, TREE_TYPE (size_arg), &b))
1320         {
1321           const char* const access_str =
1322             TREE_STRING_POINTER (access->to_external_string ());
1323           tree diag_size = sm_ctxt->get_diagnostic_tree (size_arg);
1324           sm_ctxt->warn (node, call, size_arg,
1325                          make_unique<tainted_access_attrib_size>
1326                            (*this, diag_size, b,
1327                             callee_fndecl,
1328                             access->sizarg,
1329                             access_str));
1330         }
1331     }
1332 }
1333
1334 /* Complain if ASSIGN (a division operation) has a tainted divisor
1335    that could be zero.  */
1336
1337 void
1338 taint_state_machine::check_for_tainted_divisor (sm_context *sm_ctxt,
1339                                                 const supernode *node,
1340                                                 const gassign *assign) const
1341 {
1342   const region_model *old_model = sm_ctxt->get_old_region_model ();
1343   if (!old_model)
1344     return;
1345
1346   tree divisor_expr = gimple_assign_rhs2 (assign);;
1347   const svalue *divisor_sval = old_model->get_rvalue (divisor_expr, NULL);
1348
1349   state_t state = sm_ctxt->get_state (assign, divisor_sval);
1350   enum bounds b;
1351   if (get_taint (state, TREE_TYPE (divisor_expr), &b))
1352     {
1353       const svalue *zero_sval
1354         = old_model->get_manager ()->get_or_create_int_cst
1355             (TREE_TYPE (divisor_expr), 0);
1356       tristate ts
1357         = old_model->eval_condition (divisor_sval, NE_EXPR, zero_sval);
1358       if (ts.is_true ())
1359         /* The divisor is known to not equal 0: don't warn.  */
1360         return;
1361
1362       tree diag_divisor = sm_ctxt->get_diagnostic_tree (divisor_expr);
1363       sm_ctxt->warn (node, assign, divisor_expr,
1364                      make_unique <tainted_divisor> (*this, diag_divisor, b));
1365       sm_ctxt->set_next_state (assign, divisor_sval, m_stop);
1366     }
1367 }
1368
1369 } // anonymous namespace
1370
1371 /* Internal interface to this file. */
1372
1373 state_machine *
1374 make_taint_state_machine (logger *logger)
1375 {
1376   return new taint_state_machine (logger);
1377 }
1378
1379 /* Complain to CTXT if accessing REG leads could lead to arbitrary
1380    memory access under an attacker's control (due to taint).  */
1381
1382 void
1383 region_model::check_region_for_taint (const region *reg,
1384                                       enum access_direction,
1385                                       region_model_context *ctxt) const
1386 {
1387   gcc_assert (reg);
1388   gcc_assert (ctxt);
1389
1390   LOG_SCOPE (ctxt->get_logger ());
1391
1392   sm_state_map *smap;
1393   const state_machine *sm;
1394   unsigned sm_idx;
1395   if (!ctxt->get_taint_map (&smap, &sm, &sm_idx))
1396     return;
1397
1398   gcc_assert (smap);
1399   gcc_assert (sm);
1400
1401   const taint_state_machine &taint_sm = (const taint_state_machine &)*sm;
1402
1403   const extrinsic_state *ext_state = ctxt->get_ext_state ();
1404   if (!ext_state)
1405     return;
1406
1407   const region *iter_region = reg;
1408   while (iter_region)
1409     {
1410       switch (iter_region->get_kind ())
1411         {
1412         default:
1413           break;
1414
1415         case RK_ELEMENT:
1416           {
1417             const element_region *element_reg
1418               = (const element_region *)iter_region;
1419             const svalue *index = element_reg->get_index ();
1420             const state_machine::state_t
1421               state = smap->get_state (index, *ext_state);
1422             gcc_assert (state);
1423             enum bounds b;
1424             if (taint_sm.get_taint (state, index->get_type (), &b))
1425             {
1426               tree arg = get_representative_tree (index);
1427               ctxt->warn (make_unique<tainted_array_index> (taint_sm, arg, b));
1428             }
1429           }
1430           break;
1431
1432         case RK_OFFSET:
1433           {
1434             const offset_region *offset_reg
1435               = (const offset_region *)iter_region;
1436             const svalue *offset = offset_reg->get_byte_offset ();
1437             const state_machine::state_t
1438               state = smap->get_state (offset, *ext_state);
1439             gcc_assert (state);
1440             /* Handle implicit cast to sizetype.  */
1441             tree effective_type = offset->get_type ();
1442             if (const svalue *cast = offset->maybe_undo_cast ())
1443               if (cast->get_type ())
1444                 effective_type = cast->get_type ();
1445             enum bounds b;
1446             if (taint_sm.get_taint (state, effective_type, &b))
1447               {
1448                 tree arg = get_representative_tree (offset);
1449                 ctxt->warn (make_unique<tainted_offset> (taint_sm, arg, b));
1450               }
1451           }
1452           break;
1453
1454         case RK_CAST:
1455           {
1456             const cast_region *cast_reg
1457               = as_a <const cast_region *> (iter_region);
1458             iter_region = cast_reg->get_original_region ();
1459             continue;
1460           }
1461
1462         case RK_SIZED:
1463           {
1464             const sized_region *sized_reg
1465               = (const sized_region *)iter_region;
1466             const svalue *size_sval = sized_reg->get_byte_size_sval (m_mgr);
1467             const state_machine::state_t
1468               state = smap->get_state (size_sval, *ext_state);
1469             gcc_assert (state);
1470             enum bounds b;
1471             if (taint_sm.get_taint (state, size_sval->get_type (), &b))
1472               {
1473                 tree arg = get_representative_tree (size_sval);
1474                 ctxt->warn (make_unique<tainted_size> (taint_sm, arg, b));
1475               }
1476           }
1477           break;
1478         }
1479
1480       iter_region = iter_region->get_parent_region ();
1481     }
1482 }
1483
1484 /* Complain to CTXT about a tainted allocation size if SIZE_IN_BYTES is
1485    under an attacker's control (due to taint), where the allocation
1486    is happening within MEM_SPACE.  */
1487
1488 void
1489 region_model::check_dynamic_size_for_taint (enum memory_space mem_space,
1490                                             const svalue *size_in_bytes,
1491                                             region_model_context *ctxt) const
1492 {
1493   gcc_assert (size_in_bytes);
1494   gcc_assert (ctxt);
1495
1496   LOG_SCOPE (ctxt->get_logger ());
1497
1498   sm_state_map *smap;
1499   const state_machine *sm;
1500   unsigned sm_idx;
1501   if (!ctxt->get_taint_map (&smap, &sm, &sm_idx))
1502     return;
1503
1504   gcc_assert (smap);
1505   gcc_assert (sm);
1506
1507   const taint_state_machine &taint_sm = (const taint_state_machine &)*sm;
1508
1509   const extrinsic_state *ext_state = ctxt->get_ext_state ();
1510   if (!ext_state)
1511     return;
1512
1513   const state_machine::state_t
1514     state = smap->get_state (size_in_bytes, *ext_state);
1515   gcc_assert (state);
1516   enum bounds b;
1517   if (taint_sm.get_taint (state, size_in_bytes->get_type (), &b))
1518     {
1519       tree arg = get_representative_tree (size_in_bytes);
1520       ctxt->warn (make_unique<tainted_allocation_size>
1521                     (taint_sm, arg, b, mem_space));
1522     }
1523 }
1524
1525 /* Mark SVAL as TAINTED.  CTXT must be non-NULL.  */
1526
1527 void
1528 region_model::mark_as_tainted (const svalue *sval,
1529                                region_model_context *ctxt)
1530 {
1531   gcc_assert (sval);
1532   gcc_assert (ctxt);
1533
1534   sm_state_map *smap;
1535   const state_machine *sm;
1536   unsigned sm_idx;
1537   if (!ctxt->get_taint_map (&smap, &sm, &sm_idx))
1538     return;
1539
1540   gcc_assert (smap);
1541   gcc_assert (sm);
1542
1543   const taint_state_machine &taint_sm = (const taint_state_machine &)*sm;
1544
1545   const extrinsic_state *ext_state = ctxt->get_ext_state ();
1546   if (!ext_state)
1547     return;
1548
1549   smap->set_state (this, sval, taint_sm.m_tainted, NULL, *ext_state);
1550 }
1551
1552 /* Return true if SVAL could possibly be attacker-controlled.  */
1553
1554 bool
1555 region_model_context::possibly_tainted_p (const svalue *sval)
1556 {
1557   sm_state_map *smap;
1558   const state_machine *sm;
1559   unsigned sm_idx;
1560   if (!get_taint_map (&smap, &sm, &sm_idx))
1561       return false;
1562
1563   const taint_state_machine &taint_sm = (const taint_state_machine &)*sm;
1564
1565   const extrinsic_state *ext_state = get_ext_state ();
1566   if (!ext_state)
1567     return false;
1568
1569   const state_machine::state_t state = smap->get_state (sval, *ext_state);
1570   gcc_assert (state);
1571
1572   return (state == taint_sm.m_tainted
1573           || state == taint_sm.m_has_lb
1574           || state == taint_sm.m_has_ub);
1575 }
1576
1577 } // namespace ana
1578
1579 #endif /* #if ENABLE_ANALYZER */