1 /* PR middle-end/95667 - unintended warning for memset writing across multiple
2    members
3    { dg-do compile }
4    { dg-options "-O2 -Wall" }
5    { dg-require-effective-target alloca } */
6 
7 extern void sink (void*);
8 
9 struct S1 { char a[3], b[5]; };
10 
warn_strcpy_s1(void)11 void warn_strcpy_s1 (void)
12 {
13   struct S1 *p = __builtin_malloc (sizeof *p);
14   char s[] = "1234567";
15   __builtin_strcpy (p->a, s);         // { dg-warning "\\\[-Wstringop-overflow" }
16   sink (p);
17 }
18 
nowarn_memset_s1(void)19 void nowarn_memset_s1 (void)
20 {
21   struct S1 *p = __builtin_malloc (sizeof *p);
22   __builtin_memset (p->a, 0, 8);      // { dg-bogus "\\\[-Wstringop-overflow" }
23   sink (p);
24 }
25 
26 struct S2 { char a[2], b[2][2], c[3]; };
27 
nowarn_memset_s2(void)28 void nowarn_memset_s2 (void)
29 {
30   struct S2 *p = __builtin_malloc (sizeof *p);
31 
32   __builtin_memset (p->a, 0, sizeof *p);
33   sink (p);
34 
35   __builtin_memset (p->b, 0, 7);
36   sink (p);
37 
38   __builtin_memset (&p->b[0], 0, 7);
39   sink (p);
40 
41   __builtin_memset (&p->b[1], 0, 5);
42   sink (p);
43 
44   __builtin_memset (&p->b[0][0], 0, 7);
45   sink (p);
46 
47   __builtin_memset (&p->b[0][1], 0, 6);
48   sink (p);
49 
50   __builtin_memset (&p->b[1][0], 0, 5);
51   sink (p);
52 
53   __builtin_memset (&p->b[1][1], 0, 4);
54   sink (p);
55 }
56 
warn_memset_s2(void)57 void warn_memset_s2 (void)
58 {
59   const unsigned n = sizeof (struct S2);
60   struct S2 *p = __builtin_malloc (n);
61 
62   /* These should trigger -Wstringop-overflow rather than -Warray-bounds
63      but the main purpose of the test is to verify the absence of warnings
64      above so the exact warning for these overflwing calls isn't important
65      here.  */
66 
67   __builtin_memset (p->a, 0, n + 1);  // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
68   sink (p);
69 
70   __builtin_memset (p->b, 0, 8);      // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
71   sink (p);
72 
73   __builtin_memset (&p->b[0], 0, 8);  // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
74   sink (p);
75 
76   __builtin_memset (&p->b[0][0], 0, 8); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
77   sink (p);
78 
79   __builtin_memset (&p->b[1], 0, 6);  // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
80   sink (p);
81 
82   __builtin_memset (&p->b[0][1], 0, 7); // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
83   sink (p);
84 }
85 
nowarn_vl_struct(unsigned n)86 void nowarn_vl_struct (unsigned n)
87 {
88   if (n < 3 || 5 < n)
89     n = 3;
90 
91   struct V { char a[3], b[n], c[7]; } v;
92 
93   __builtin_memset (v.a, 0, 15);
94   sink (&v);
95 
96   __builtin_memset (v.b, 0, 12);
97   sink (&v);
98 
99   __builtin_memset (v.c, 0, 7);
100   sink (&v);
101 
102   __builtin_memset (v.a, 0, 16);      // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
103   sink (&v);
104 
105   __builtin_memset (v.b, 0, 13);      // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
106   sink (&v);
107 
108   /* The &V.C argument is represented as a variable offset from
109      the beginning of the allocated object and there's no good
110      way to figure out from its variable offset that it's base
111      is the C member:
112        s.1_12 = __builtin_alloca_with_align (prephitmp_24, 8);
113        _9 = s.1_12 + prephitmp_27;
114        __builtin_memset (_9, 0, 2);
115   */
116 
117   __builtin_memset (v.c, 0, 8);       // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "pr?????" { xfail *-*-* } }
118   sink (&v);
119 }
120