1  // TODO: remove need for this option
       2  /* { dg-additional-options "-fanalyzer-checker=taint" } */
       3  
       4  /* We need this, otherwise the warnings are emitted inside the macros, which
       5     makes it hard to write the DejaGnu directives.  */
       6  /* { dg-additional-options " -ftrack-macro-expansion=0" } */
       7  
       8  #include "analyzer-decls.h"
       9  
      10  /* An assertion macro that has a call to a __noreturn__ function.  */
      11  
      12  extern void my_assert_fail (const char *expr, const char *file, int line)
      13    __attribute__ ((__noreturn__));
      14  
      15  #define MY_ASSERT_1(EXPR) \
      16    do { if (!(EXPR)) my_assert_fail (#EXPR, __FILE__, __LINE__); } while (0)
      17  
      18  int
      19  test_not_tainted_MY_ASSERT_1 (int n)
      20  {
      21    MY_ASSERT_1 (n > 0); /* { dg-bogus "-Wanalyzer-tainted-assertion" } */
      22    return n * n;
      23  }
      24  
      25  int __attribute__((tainted_args))
      26  test_tainted_MY_ASSERT_1 (int n)
      27  {
      28    MY_ASSERT_1 (n > 0); /* { dg-warning "use of attacked-controlled value in condition for assertion \\\[CWE-617\\\] \\\[-Wanalyzer-tainted-assertion\\\]" "warning" } */
      29    /* { dg-message "treating 'my_assert_fail' as an assertion failure handler due to '__attribute__\\(\\(__noreturn__\\)\\)'" "final event" { target *-*-* } .-1 } */
      30    return n * n;
      31  }
      32  
      33  
      34  /* An assertion macro that has a call to __builtin_unreachable.  */
      35  
      36  #define MY_ASSERT_2(EXPR)					\
      37    do { if (!(EXPR)) __builtin_unreachable (); } while (0)
      38  
      39  int
      40  test_not_tainted_MY_ASSERT_2 (int n)
      41  {
      42    MY_ASSERT_2 (n > 0); /* { dg-bogus "-Wanalyzer-tainted-assertion" } */
      43    return n * n;
      44  }
      45  
      46  int __attribute__((tainted_args))
      47  test_tainted_MY_ASSERT_2 (int n)
      48  {
      49    MY_ASSERT_2 (n > 0); /* { dg-warning "-Wanalyzer-tainted-assertion" "warning" } */
      50    /* { dg-message "treating '__builtin_unreachable' as an assertion failure handler" "final event" { target *-*-* } .-1 } */
      51    return n * n;
      52  }
      53  
      54  
      55  /* An assertion macro that's preprocessed away.
      56     The analyzer doesn't see this, so can't warn.  */
      57  
      58  #define MY_ASSERT_3(EXPR)  do { } while (0)
      59  
      60  int
      61  test_not_tainted_MY_ASSERT_3 (int n)
      62  {
      63    MY_ASSERT_3 (n > 0); /* { dg-bogus "-Wanalyzer-tainted-assertion" } */
      64    return n * n;
      65  }
      66  
      67  int __attribute__((tainted_args))
      68  test_tainted_MY_ASSERT_3 (int n)
      69  {
      70    MY_ASSERT_3 (n > 0); /* { dg-bogus "-Wanalyzer-tainted-assertion" } */
      71    return n * n;
      72  }
      73  
      74  
      75  /* A macro that isn't an assertion.  */
      76  
      77  extern void do_something_benign ();
      78  
      79  #define NOT_AN_ASSERT(EXPR) \
      80    do { if (!(EXPR)) do_something_benign (); } while (0)
      81  
      82  int
      83  test_not_tainted_NOT_AN_ASSERT (int n)
      84  {
      85    NOT_AN_ASSERT (n > 0); /* { dg-bogus "-Wanalyzer-tainted-assertion" } */
      86    return n * n;
      87  }
      88  
      89  int __attribute__((tainted_args))
      90  test_tainted_NOT_AN_ASSERT (int n)
      91  {
      92    NOT_AN_ASSERT (n > 0); /* { dg-bogus "-Wanalyzer-tainted-assertion" } */
      93    return n * n;
      94  }
      95  
      96  
      97  /* A condition that isn't an assertion.  */
      98  
      99  int __attribute__((tainted_args))
     100  test_tainted_condition (int n)
     101  {
     102    if (n > 0) /* { dg-bogus "-Wanalyzer-tainted-assertion" } */
     103      return 1;
     104    else
     105      return -1;
     106  }
     107  
     108  
     109  /* More complicated expressions in assertions.  */
     110  
     111  int g;
     112  
     113  void __attribute__((tainted_args))
     114  test_compound_condition_in_assert_1 (int n)
     115  {
     116    MY_ASSERT_1 ((n * 2) < (g + 3)); /* { dg-warning "-Wanalyzer-tainted-assertion" } */
     117  }
     118  
     119  void __attribute__((tainted_args))
     120  test_compound_condition_in_assert_2 (int x, int y)
     121  {
     122    MY_ASSERT_1 (x < 100 && y < 100); /* { dg-warning "-Wanalyzer-tainted-assertion" } */
     123  }
     124  
     125  void __attribute__((tainted_args))
     126  test_compound_condition_in_assert_3 (int x, int y)
     127  {
     128    MY_ASSERT_1 (x < 100 || y < 100); /* { dg-warning "-Wanalyzer-tainted-assertion" } */
     129  }
     130  
     131  void __attribute__((tainted_args))
     132  test_sanitized_expression_in_assert (int n)
     133  {
     134    __analyzer_dump_state ("taint", n); /* { dg-warning "state: 'tainted'" } */
     135    if (n < 0 || n >= 100)
     136      return;
     137    __analyzer_dump_state ("taint", n); /* { dg-warning "state: 'stop'" } */  
     138    MY_ASSERT_1 (n < 200); /* { dg-bogus "-Wanalyzer-tainted-assertion" } */
     139  }
     140  
     141  void __attribute__((tainted_args))
     142  test_sanitization_then_ok_assertion (unsigned n)
     143  {
     144    if (n >= 100)
     145      return;
     146  
     147    /* Shouldn't warn here, as g isn't attacker-controlled.  */
     148    MY_ASSERT_1 (g > 42); /* { dg-bogus "-Wanalyzer-tainted-assertion" } */
     149  }
     150  
     151  void __attribute__((tainted_args))
     152  test_good_assert_then_bad_assert (unsigned n)
     153  {
     154    /* Shouldn't warn here, as g isn't attacker-controlled.  */
     155    MY_ASSERT_1 (g > 42); /* { dg-bogus "-Wanalyzer-tainted-assertion" } */
     156  
     157    /* ...but n is: */
     158    MY_ASSERT_1 (n < 100); /* { dg-warning "-Wanalyzer-tainted-assertion" } */
     159  }
     160  
     161  void __attribute__((tainted_args))
     162  test_bad_assert_then_good_assert (unsigned n)
     163  {
     164    MY_ASSERT_1 (n < 100); /* { dg-warning "-Wanalyzer-tainted-assertion" } */
     165    MY_ASSERT_1 (g > 42); /* { dg-bogus "-Wanalyzer-tainted-assertion" } */
     166  }
     167  
     168  
     169  /* */
     170  
     171  void __attribute__((tainted_args))
     172  test_zero_MY_ASSERT_1 (unsigned n)
     173  {
     174    if (n >= 100)
     175      MY_ASSERT_1 (0); /* { dg-warning "-Wanalyzer-tainted-assertion" } */
     176  }
     177  
     178  void __attribute__((tainted_args))
     179  test_nonzero_MY_ASSERT_1 (unsigned n)
     180  {
     181    if (n >= 100)
     182      MY_ASSERT_1 (1); /* { dg-bogus "-Wanalyzer-tainted-assertion" } */
     183  }
     184  
     185  void __attribute__((tainted_args))
     186  test_zero_MY_ASSERT_2 (unsigned n)
     187  {
     188    if (n >= 100)
     189      MY_ASSERT_2 (0); /* { dg-warning "-Wanalyzer-tainted-assertion" } */
     190  }
     191  
     192  void __attribute__((tainted_args))
     193  test_nonzero_MY_ASSERT_2 (unsigned n)
     194  {
     195    if (n >= 100)
     196      MY_ASSERT_2 (1); /* { dg-bogus "-Wanalyzer-tainted-assertion" } */
     197  }
     198  
     199  
     200  /* Assertions that call a subroutine to do validity checking.  */
     201   
     202  static int
     203  __analyzer_valid_1 (int x)
     204  {
     205    return x < 100;
     206  }
     207  
     208  void __attribute__((tainted_args))
     209  test_assert_calling_valid_1 (int n)
     210  {
     211    MY_ASSERT_1 (__analyzer_valid_1 (n)); /* { dg-warning "-Wanalyzer-tainted-assertion" } */
     212  }
     213   
     214  static int
     215  __analyzer_valid_2 (int x)
     216  {
     217    return x < 100;
     218  }
     219  
     220  void __attribute__((tainted_args))
     221  test_assert_calling_valid_2 (int n)
     222  {
     223    MY_ASSERT_1 (__analyzer_valid_2 (n)); /* { dg-warning "-Wanalyzer-tainted-assertion" } */
     224  }
     225  
     226  static int
     227  __analyzer_valid_3 (int x, int y)
     228  {
     229    if (x >= 100)
     230      return 0;
     231    if (y >= 100)
     232      return 0;
     233    return 1;
     234  }
     235  
     236  void __attribute__((tainted_args))
     237  test_assert_calling_valid_3 (int a, int b)
     238  {
     239    MY_ASSERT_1 (__analyzer_valid_3 (a, b)); /* { dg-warning "-Wanalyzer-tainted-assertion" "TODO" { xfail *-*-* } } */
     240  }
     241  
     242  
     243  /* 'switch' statements with supposedly unreachable cases/defaults.  */
     244  
     245  int __attribute__((tainted_args))
     246  test_switch_default (int n)
     247  {
     248    switch (n) /* { dg-message "use of attacker-controlled value for control flow" "why" } */
     249               /* { dg-message "following 'default:' branch" "dest" { target *-*-* } .-1 } */
     250      {
     251      case 0:
     252        return 5;
     253      case 1:
     254        return 22;
     255      case 2:
     256        return -1;
     257      default:
     258        /* The wording is rather inaccurate here.  */
     259        __builtin_unreachable (); /* { dg-warning "use of attacked-controlled value in condition for assertion" } */
     260      }
     261  }
     262  
     263  int __attribute__((tainted_args))
     264  test_switch_unhandled_case (int n)
     265  {
     266    switch (n) /* { dg-message "use of attacker-controlled value for control flow" "why" } */
     267               /* { dg-message "following 'default:' branch" "dest" { target *-*-* } .-1 } */
     268      {
     269      case 0:
     270        return 5;
     271      case 1:
     272        return 22;
     273      case 2:
     274        return -1;
     275      }
     276  
     277    /* The wording is rather inaccurate here.  */
     278    __builtin_unreachable (); /* { dg-warning "use of attacked-controlled value in condition for assertion" } */
     279  }
     280  
     281  int __attribute__((tainted_args))
     282  test_switch_bogus_case_MY_ASSERT_1 (int n)
     283  {
     284    switch (n)
     285      {
     286      default:
     287      case 0:
     288        return 5;
     289      case 1:
     290        return 22;
     291      case 2:
     292        return -1;
     293      case 42:
     294        MY_ASSERT_1 (0); /* { dg-warning "-Wanalyzer-tainted-assertion" } */
     295      }
     296  }
     297  
     298  int __attribute__((tainted_args))
     299  test_switch_bogus_case_MY_ASSERT_2 (int n)
     300  {
     301    switch (n)
     302      {
     303      default:
     304      case 0:
     305        return 5;
     306      case 1:
     307        return 22;
     308      case 2:
     309        return -1;
     310      case 42:
     311        MY_ASSERT_2 (0); /* { dg-warning "-Wanalyzer-tainted-assertion" } */
     312      }
     313  }
     314  
     315  int __attribute__((tainted_args))
     316  test_switch_bogus_case_unreachable (int n)
     317  {
     318    switch (n)
     319      {
     320      default:
     321      case 0:
     322        return 5;
     323      case 1:
     324        return 22;
     325      case 2:
     326        return -1;
     327      case 42:
     328        /* This case gets optimized away before we see it.  */
     329        __builtin_unreachable ();
     330      }
     331  }
     332  
     333  
     334  /* Contents of a struct.  */
     335  
     336  struct s
     337  {
     338    int x;
     339    int y;
     340  };
     341  
     342  int __attribute__((tainted_args))
     343  test_assert_struct (struct s *p)
     344  {
     345    MY_ASSERT_1 (p->x < p->y); /* { dg-warning "-Wanalyzer-tainted-assertion" } */
     346  }