1  /* As per stdarg-1.c, but using <stdarg.h>, rather than hardcoded builtins.  */
       2  
       3  #include <stdarg.h>
       4  #include "analyzer-decls.h"
       5  
       6  /* Unpacking a va_list.  */
       7  
       8  static void __attribute__((noinline))
       9  __analyzer_called_by_test_1 (int placeholder, ...)
      10  {
      11    const char *s;
      12    int i;
      13    char c;
      14    
      15    va_list ap;
      16    va_start (ap, placeholder);
      17  
      18    s = va_arg (ap, char *);
      19    __analyzer_eval (s[0] == 'f'); /* { dg-warning "TRUE" } */
      20  
      21    i = va_arg (ap, int);
      22    __analyzer_eval (i == 1066); /* { dg-warning "TRUE" } */
      23  
      24    c = (char)va_arg (ap, int);
      25    __analyzer_eval (c == '@'); /* { dg-warning "TRUE" } */
      26  
      27    va_end (ap);
      28  }
      29  
      30  void test_1 (void)
      31  {
      32    __analyzer_called_by_test_1 (42, "foo", 1066, '@');
      33  }
      34  
      35  /* Unpacking a va_list passed from an intermediate function.  */
      36  
      37  static void __attribute__((noinline))
      38  __analyzer_test_2_inner (va_list ap)
      39  {
      40    const char *s;
      41    int i;
      42    char c;
      43    
      44    s = va_arg (ap, char *);
      45    __analyzer_eval (s[0] == 'f'); /* { dg-warning "TRUE" } */
      46  
      47    i = va_arg (ap, int);
      48    __analyzer_eval (i == 1066); /* { dg-warning "TRUE" } */
      49  
      50    c = (char)va_arg (ap, int);
      51    __analyzer_eval (c == '@'); /* { dg-warning "TRUE" } */
      52  }
      53  
      54  static void __attribute__((noinline))
      55  __analyzer_test_2_middle (int placeholder, ...)
      56  {
      57    va_list ap;
      58    va_start (ap, placeholder);
      59    __analyzer_test_2_inner (ap);
      60    va_end (ap);
      61  }
      62  
      63  void test_2 (void)
      64  {
      65    __analyzer_test_2_middle (42, "foo", 1066, '@');
      66  }
      67  
      68  /* Not enough args.  */
      69  
      70  static void __attribute__((noinline))
      71  __analyzer_called_by_test_not_enough_args (int placeholder, ...)
      72  {
      73    const char *s;
      74    int i;
      75    
      76    va_list ap;
      77    va_start (ap, placeholder);
      78  
      79    s = va_arg (ap, char *);
      80    __analyzer_eval (s[0] == 'f'); /* { dg-warning "TRUE" } */
      81  
      82    i = va_arg (ap, int); /* { dg-warning "'ap' has no more arguments \\(1 consumed\\)" } */
      83  
      84    va_end (ap);
      85  }
      86  
      87  void test_not_enough_args (void)
      88  {
      89    __analyzer_called_by_test_not_enough_args (42, "foo");
      90  }
      91  
      92  /* Not enough args, with an intermediate function.  */
      93  
      94  static void __attribute__((noinline))
      95  __analyzer_test_not_enough_args_2_inner (va_list ap)
      96  {
      97    const char *s;
      98    int i;
      99    
     100    s = va_arg (ap, char *);
     101    __analyzer_eval (s[0] == 'f'); /* { dg-warning "TRUE" } */
     102  
     103    i = va_arg (ap, int); /* { dg-warning "'ap' has no more arguments \\(1 consumed\\)" } */
     104  }
     105  
     106  static void __attribute__((noinline))
     107  __analyzer_test_not_enough_args_2_middle (int placeholder, ...)
     108  {
     109    va_list ap;
     110    va_start (ap, placeholder);
     111    __analyzer_test_not_enough_args_2_inner (ap);
     112    va_end (ap);
     113  }
     114  
     115  void test_not_enough_args_2 (void)
     116  {
     117    __analyzer_test_not_enough_args_2_middle (42, "foo");
     118  }
     119  
     120  /* Excess args (not a problem).  */
     121  
     122  static void __attribute__((noinline))
     123  __analyzer_called_by_test_excess_args (int placeholder, ...)
     124  {
     125    const char *s;
     126    
     127    va_list ap;
     128    va_start (ap, placeholder);
     129  
     130    s = va_arg (ap, char *);
     131    __analyzer_eval (s[0] == 'f'); /* { dg-warning "TRUE" } */
     132  
     133    va_end (ap);
     134  }
     135  
     136  void test_excess_args (void)
     137  {
     138    __analyzer_called_by_test_excess_args (42, "foo", "bar");
     139  }
     140  
     141  /* Missing va_start.  */
     142  
     143  void test_missing_va_start (int placeholder, ...)
     144  {
     145    va_list ap; /* { dg-message "region created on stack here" } */
     146    int i = va_arg (ap, int); /* { dg-warning "use of uninitialized value 'ap'" } */
     147  }
     148  
     149  /* Missing va_end.  */
     150  
     151  void test_missing_va_end (int placeholder, ...)
     152  {
     153    int i;
     154    va_list ap;
     155    va_start (ap, placeholder); /* { dg-message "\\(1\\) 'va_start' called here" } */
     156    i = va_arg (ap, int);
     157  } /* { dg-warning "missing call to 'va_end'" "warning" } */
     158  /* { dg-message "\\(2\\) missing call to 'va_end' to match 'va_start' at \\(1\\)" "final event" { target *-*-* } .-1 } */
     159  
     160  /* Missing va_end due to error-handling.  */
     161  
     162  int test_missing_va_end_2 (int placeholder, ...)
     163  {
     164    int i, j;
     165    va_list ap;
     166    va_start (ap, placeholder); /* { dg-message "\\(1\\) 'va_start' called here" } */
     167    i = va_arg (ap, int);
     168    if (i == 42)
     169      {
     170        va_end (ap);
     171        return -1;
     172      }
     173    j = va_arg (ap, int);
     174    if (j == 1066) /* { dg-message "branch" } */
     175      return -1; /* { dg-message "here" } */
     176    va_end (ap);
     177    return 0;
     178  } /* { dg-warning "missing call to 'va_end'" "warning" } */
     179  
     180  /* va_arg after va_end.  */
     181  
     182  void test_va_arg_after_va_end (int placeholder, ...)
     183  {
     184    int i;
     185    va_list ap;
     186    va_start (ap, placeholder);
     187    va_end (ap); /* { dg-message "'va_end' called here" } */
     188    i = va_arg (ap, int); /* { dg-warning "'va_arg' after 'va_end'" } */
     189  }
     190  
     191  /* Type mismatch: expect int, but passed a char *.  */
     192  
     193  static void __attribute__((noinline))
     194  __analyzer_called_by_test_type_mismatch_1 (int placeholder, ...)
     195  {
     196    int i;
     197    
     198    va_list ap;
     199    va_start (ap, placeholder);
     200  
     201    i = va_arg (ap, int); /* { dg-warning "'va_arg' expected 'int' but received '\[^\n\r\]*' for variadic argument 1 of 'ap'" } */
     202  
     203    va_end (ap);
     204  }
     205  
     206  void test_type_mismatch_1 (void)
     207  {
     208    __analyzer_called_by_test_type_mismatch_1 (42, "foo");
     209  }
     210  
     211  /* Type mismatch: expect char *, but passed an int.  */
     212  
     213  static void __attribute__((noinline))
     214  __analyzer_called_by_test_type_mismatch_2 (int placeholder, ...)
     215  {
     216    const char *str;
     217    
     218    va_list ap;
     219    va_start (ap, placeholder);
     220  
     221    str = va_arg (ap, const char *); /* { dg-warning "'va_arg' expected 'const char \\*' but received 'int' for variadic argument 1 of 'ap'" } */
     222  
     223    va_end (ap);
     224  }
     225  
     226  void test_type_mismatch_2 (void)
     227  {
     228    __analyzer_called_by_test_type_mismatch_2 (42, 1066);
     229  }
     230  
     231  /* As above, but with an intermediate function.  */
     232  
     233  static void __attribute__((noinline))
     234  __analyzer_test_type_mismatch_3_inner (va_list ap)
     235  {
     236    const char *str;
     237    
     238    str = va_arg (ap, const char *); /* { dg-warning "'va_arg' expected 'const char \\*' but received 'int' for variadic argument 1 of 'ap'" } */
     239  }
     240  
     241  static void __attribute__((noinline))
     242  __analyzer_test_type_mismatch_3_middle (int placeholder, ...)
     243  {
     244    va_list ap;
     245    va_start (ap, placeholder);
     246  
     247    __analyzer_test_type_mismatch_3_inner (ap);
     248  
     249    va_end (ap);
     250  }
     251  
     252  void test_type_mismatch_3 (void)
     253  {
     254    __analyzer_test_type_mismatch_3_middle (42, 1066);
     255  }
     256  
     257  /* Multiple traversals of the args.  */
     258  
     259  static void __attribute__((noinline))
     260  __analyzer_called_by_test_multiple_traversals (int placeholder, ...)
     261  {
     262    va_list ap;
     263  
     264    /* First traversal.  */
     265    {
     266      int i, j;
     267  
     268      va_start (ap, placeholder);
     269  
     270      i = va_arg (ap, int);
     271      __analyzer_eval (i == 1066); /* { dg-warning "TRUE" } */
     272  
     273      j = va_arg (ap, int);
     274      __analyzer_eval (j == 42); /* { dg-warning "TRUE" } */
     275  
     276      va_end (ap);
     277    }
     278  
     279    /* Second traversal.  */
     280    {
     281      int i, j;
     282  
     283      va_start (ap, placeholder);
     284  
     285      i = va_arg (ap, int);
     286      __analyzer_eval (i == 1066); /* { dg-warning "TRUE" } */
     287  
     288      j = va_arg (ap, int);
     289      __analyzer_eval (j == 42); /* { dg-warning "TRUE" } */
     290  
     291      va_end (ap);
     292    }
     293  }
     294  
     295  void test_multiple_traversals (void)
     296  {
     297    __analyzer_called_by_test_multiple_traversals (0, 1066, 42);
     298  }
     299  
     300  /* Multiple traversals, using va_copy.  */
     301  
     302  static void __attribute__((noinline))
     303  __analyzer_called_by_test_multiple_traversals_2 (int placeholder, ...)
     304  {
     305    int i, j;
     306    va_list args1;
     307    va_list args2;
     308  
     309    va_start (args1, placeholder);
     310    va_copy (args2, args1);
     311  
     312    /* First traversal.  */
     313    i = va_arg (args1, int);
     314    __analyzer_eval (i == 1066); /* { dg-warning "TRUE" } */
     315    j = va_arg (args1, int);
     316    __analyzer_eval (j == 42); /* { dg-warning "TRUE" } */
     317    va_end (args1);
     318  
     319    /* Traversal of copy.  */
     320    i = va_arg (args2, int);
     321    __analyzer_eval (i == 1066); /* { dg-warning "TRUE" } */
     322    j = va_arg (args2, int);
     323    __analyzer_eval (j == 42); /* { dg-warning "TRUE" } */
     324    va_end (args2);
     325  }
     326  
     327  void test_multiple_traversals_2 (void)
     328  {
     329    __analyzer_called_by_test_multiple_traversals_2 (0, 1066, 42);
     330  }
     331  
     332  /* Multiple traversals, using va_copy after a va_arg.  */
     333  
     334  static void __attribute__((noinline))
     335  __analyzer_called_by_test_multiple_traversals_3 (int placeholder, ...)
     336  {
     337    int i, j;
     338    va_list args1;
     339    va_list args2;
     340  
     341    va_start (args1, placeholder);
     342  
     343    /* First traversal.  */
     344    i = va_arg (args1, int);
     345    __analyzer_eval (i == 1066); /* { dg-warning "TRUE" } */
     346  
     347    /* va_copy after the first va_arg. */
     348    va_copy (args2, args1);
     349  
     350    j = va_arg (args1, int);
     351    __analyzer_eval (j == 42); /* { dg-warning "TRUE" } */
     352    va_end (args1);
     353  
     354    /* Traversal of copy.  */
     355    j = va_arg (args2, int);
     356    __analyzer_eval (j == 42); /* { dg-warning "TRUE" } */
     357    va_end (args2);
     358  }
     359  
     360  void test_multiple_traversals_3 (void)
     361  {
     362    __analyzer_called_by_test_multiple_traversals_3 (0, 1066, 42);
     363  }
     364  
     365  /* va_copy after va_end.  */
     366  
     367  void test_va_copy_after_va_end (int placeholder, ...)
     368  {
     369    va_list ap1, ap2;
     370    va_start (ap1, placeholder);
     371    va_end (ap1); /* { dg-message "'va_end' called here" } */
     372    va_copy (ap2, ap1); /* { dg-warning "'va_copy' after 'va_end'" } */
     373    va_end (ap2);
     374  }
     375  
     376  /* leak of va_copy.  */
     377  
     378  void test_leak_of_va_copy (int placeholder, ...)
     379  {
     380    va_list ap1, ap2;
     381    va_start (ap1, placeholder); 
     382    va_copy (ap2, ap1);  /* { dg-message "'va_copy' called here" } */
     383    va_end (ap1);
     384  } /* { dg-warning "missing call to 'va_end'" "warning" } */
     385    /* { dg-message "missing call to 'va_end' to match 'va_copy' at \\(1\\)" "final event" { target *-*-* } .-1 } */
     386  
     387  /* double va_end.  */
     388  
     389  void test_double_va_end (int placeholder, ...)
     390  {
     391    va_list ap;
     392    va_start (ap, placeholder);
     393    va_end (ap); /* { dg-message "'va_end' called here" } */
     394    va_end (ap); /* { dg-warning "'va_end' after 'va_end'" } */
     395  }
     396  
     397  /* double va_start.  */
     398  
     399  void test_double_va_start (int placeholder, ...)
     400  {
     401    int i;
     402    va_list ap;
     403    va_start (ap, placeholder); /* { dg-message "'va_start' called here" } */
     404    va_start (ap, placeholder);  /* { dg-warning "missing call to 'va_end'" "warning" } */
     405    /* { dg-message "missing call to 'va_end' to match 'va_start' at \\(1\\)" "final event" { target *-*-* } .-1 } */
     406    va_end (ap);
     407  }
     408  
     409  /* va_copy before va_start.  */
     410  
     411  void test_va_copy_before_va_start (int placeholder, ...)
     412  {
     413    va_list ap1; /* { dg-message "region created on stack here" } */
     414    va_list ap2;
     415    va_copy (ap2, ap1); /* { dg-warning "use of uninitialized value 'ap1'" } */
     416    va_end (ap2);
     417  }
     418  
     419  /* Verify that we complain about uses of a va_list after the function 
     420     in which va_start was called has returned.  */
     421  
     422  va_list global_ap;
     423  
     424  static void __attribute__((noinline))
     425  __analyzer_called_by_test_va_arg_after_return (int placeholder, ...)
     426  {
     427    va_start (global_ap, placeholder);
     428    va_end (global_ap);
     429  }
     430  
     431  void test_va_arg_after_return (void)
     432  {
     433    int i;
     434    __analyzer_called_by_test_va_arg_after_return (42, 1066);
     435    i = va_arg (global_ap, int); /* { dg-warning "dereferencing pointer 'global_ap' to within stale stack frame" } */
     436  }