1  /* Verify that -Wanalyzer-exposure-through-uninit-copy doesn't get confused
       2     if size argument to copy_to_user is an upper bound, rather than a
       3     constant.  */
       4  
       5  /* { dg-do compile } */
       6  /* { dg-options "-fanalyzer" } */
       7  /* { dg-require-effective-target analyzer } */
       8  
       9  #include "../analyzer/analyzer-decls.h"
      10  
      11  typedef __SIZE_TYPE__ size_t;
      12  
      13  #include "test-uaccess.h"
      14  
      15  typedef unsigned __INT32_TYPE__ u32;
      16  
      17  /* min_t adapted from include/linux/kernel.h.  */
      18  
      19  #define min_t(type, x, y) ({			\
      20  	type __min1 = (x);			\
      21  	type __min2 = (y);			\
      22  	__min1 < __min2 ? __min1: __min2; })
      23  
      24  struct st
      25  {
      26    u32 a;
      27    u32 b;
      28  };
      29  
      30  /* Verify that we cope with min_t.  */
      31  
      32  void test_1_full_init (void __user *dst, u32 x, u32 y, unsigned long in_sz)
      33  {
      34    struct st s;
      35    s.a = x;
      36    s.b = y;
      37    unsigned long copy_sz = min_t(unsigned long, in_sz, sizeof(s));
      38    copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */
      39  }
      40  
      41  void test_1_partial_init (void __user *dst, u32 x, u32 y, unsigned long in_sz)
      42  {
      43    struct st s;
      44    s.a = x;
      45    /* s.y not initialized.  */
      46    unsigned long copy_sz = min_t(unsigned long, in_sz, sizeof(s));
      47    copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" } */
      48  }
      49  
      50  /* Constant on LHS rather than RHS.  */
      51  
      52  void test_2_full_init (void __user *dst, u32 x, u32 y, unsigned long in_sz)
      53  {
      54    struct st s;
      55    s.a = x;
      56    s.b = y;
      57    unsigned long copy_sz = min_t(unsigned long, sizeof(s), in_sz);
      58    copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */
      59  }
      60  
      61  void test_2_partial_init (void __user *dst, u32 x, u32 y, unsigned long in_sz)
      62  {
      63    struct st s;
      64    s.a = x;
      65    /* s.y not initialized.  */
      66    unsigned long copy_sz = min_t(unsigned long, sizeof(s), in_sz);
      67    copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" } */
      68  }
      69  
      70  /* min_t with various casts.  */
      71  
      72  void test_3_full_init (void __user *dst, u32 x, u32 y, int in_sz)
      73  {
      74    struct st s;
      75    s.a = x;
      76    s.b = y;
      77    int copy_sz = min_t(unsigned int, in_sz, sizeof(s));
      78    copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */
      79  }
      80  
      81  void test_3_partial_init (void __user *dst, u32 x, u32 y, int in_sz)
      82  {
      83    struct st s;
      84    s.a = x;
      85    /* s.y not initialized.  */
      86    int copy_sz = min_t(unsigned int, in_sz, sizeof(s));
      87    copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" } */
      88  }
      89  
      90  /* Comparison against an upper bound.  */
      91  
      92  void test_4_full_init (void __user *dst, u32 x, u32 y, size_t in_sz)
      93  {
      94    struct st s;
      95    s.a = x;
      96    s.b = y;
      97    
      98    size_t copy_sz = in_sz;
      99    if (copy_sz > sizeof(s))
     100      copy_sz = sizeof(s);
     101  
     102    copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */
     103  }
     104  
     105  void test_4_partial_init (void __user *dst, u32 x, u32 y, size_t in_sz)
     106  {
     107    struct st s;
     108    s.a = x;
     109    /* s.y not initialized.  */
     110    
     111    size_t copy_sz = in_sz;
     112    if (copy_sz > sizeof(s))
     113      copy_sz = sizeof(s);
     114  
     115    copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" } */
     116  }
     117  
     118  /* Comparison against an upper bound with casts.  */
     119  
     120  void test_5_full_init (void __user *dst, u32 x, u32 y, int in_sz)
     121  {
     122    struct st s;
     123    s.a = x;
     124    s.b = y;
     125    
     126    int copy_sz = in_sz;
     127    if (copy_sz > sizeof(s))
     128      copy_sz = sizeof(s);
     129    copy_to_user(dst, &s, copy_sz); /* { dg-bogus "exposure" } */
     130  }
     131  
     132  /* Comparison against an upper bound with casts.  */
     133  
     134  void test_5_partial_init (void __user *dst, u32 x, u32 y, int in_sz)
     135  {
     136    struct st s;
     137    s.a = x;
     138    /* s.y not initialized.  */
     139    
     140    int copy_sz = in_sz;
     141    if (copy_sz > sizeof(s))
     142      copy_sz = sizeof(s);
     143  
     144    copy_to_user(dst, &s, copy_sz); /* { dg-warning "exposure" "" } */
     145  }