1 /* PR middle-end/83859 - attribute to establish relation between parameters
2    for buffer and its size
3    Test to verify that with optimization enabled, -Wstringop-overflow
4    warnings are issued for calls to user-defined functions with attribute
5    access and with non-constant out-of-bounds arguments.
6    { dg-do compile }
7    { dg-options "-O2 -Wall" } */
8 
9 #include "range.h"
10 
11 #define INT_MAX   __INT_MAX__
12 #define INT_MIN   (-INT_MAX - 1)
13 
14 #define RDONLY(...)  __attribute__ ((access (read_only, __VA_ARGS__)))
15 #define WRONLY(...)  __attribute__ ((access (write_only, __VA_ARGS__)))
16 #define RDWR(...)  __attribute__ ((access (read_write, __VA_ARGS__)))
17 
18 typedef __INT32_TYPE__ int32_t;
19 
20 /* Exercise null pointer detection.  */
21 
22 RDONLY (2, 1) void
23 rd2_1 (int, const void*);       // { dg-message "in a call to function 'rd2_1' declared with attribute 'read_only \\\(2, 1\\\)" }
24 
test_rd2_1(void)25 void test_rd2_1 (void)
26 {
27   {
28     void *null = 0;
29     void *p = &null;
30 
31     rd2_1 (0, null);
32     rd2_1 (1, p);
33   }
34 
35   {
36     void *null = 0;
37     rd2_1 (1, null);            // { dg-warning "argument 2 is null but the corresponding size argument 1 value is 1" }
38   }
39 
40   {
41     void *null = 0;
42     rd2_1 (SR (1, 2), null);    // { dg-warning "argument 2 is null but the corresponding size argument 1 range is \\\[1, 2]" }
43   }
44 }
45 
46 WRONLY (3, 1) void
47 wr3_1 (int, int, void*);        // { dg-message "in a call to function 'wr3_1' declared with attribute 'write_only \\\(3, 1\\\)" }
48 
test_wr3_1(void)49 void test_wr3_1 (void)
50 {
51   {
52     void *null = 0;
53     void *p = &null;
54 
55     wr3_1 (SR (0, 1), 0, null);
56     wr3_1 (SR (1, 1), 0, p);
57   }
58 
59   void *null = 0;
60 
61   wr3_1 (SR (1, 2), 1, null);   // { dg-warning "argument 3 is null but the corresponding size argument 1 range is \\\[1, 2]" }
62 }
63 
64 
65 WRONLY (2, 1) void
66 wr2_1 (int, void*);
67 
test_wrd2_1(int n)68 void test_wrd2_1 (int n)
69 {
70   wr2_1 (0, 0);
71   wr2_1 (SR (-1, 1), 0);
72   wr2_1 (SR (0, 1), 0);
73   wr2_1 (SR (1, 2), 0);         // { dg-warning "argument 2 is null but the corresponding size argument 1 range is \\\[1, 2]" }
74 
75   /* This should probably be diagnosed but to avoid false positives
76      caused by jump threading and such it would have to be done
77      earlier than it is now.  */
78   wr2_1 (n, 0);                 // { dg-warning "argument 2 is null" "unimplemented" { xfail *-*-* } }
79 }
80 
81 
82 /* Exercise pointer to an incomplete type other than void.  */
83 
84 struct Incomplete;
85 extern struct Incomplete inc;
86 
87 extern char ax[];
88 
89 WRONLY (1, 2) void
90 wr1_2_inc (struct Incomplete*, unsigned);
91 
test_wr1_2_inc(struct Incomplete * pinc,unsigned n)92 void test_wr1_2_inc (struct Incomplete *pinc, unsigned n)
93 {
94   wr1_2_inc (0, 0);
95   wr1_2_inc (0, 1);         // { dg-warning "argument 1 is null but the corresponding size argument 2 value is 1" }
96 
97   wr1_2_inc (pinc, 1);
98   wr1_2_inc (&inc, 1);
99 
100   wr1_2_inc (pinc, 123);
101   wr1_2_inc (&inc, 456);
102 
103   char a3[3];
104   pinc = (struct Incomplete*)a3;
105   wr1_2_inc (pinc, SR (3, 4));
106   wr1_2_inc (pinc, SR (4, 5));
107   // { dg-warning "'wr1_2_inc' writing between 4 and 5 bytes into a region of size 3" "small buffer cast to incomplete" { target *-*-* } .-1 }
108 
109   pinc = (struct Incomplete*)ax;
110   wr1_2_inc (pinc, SR (123, 456));
111 
112   char vla[n];
113   pinc = (struct Incomplete*)vla;
114   wr1_2_inc (pinc, SR (345, 456));
115 }
116 
117 
118 RDONLY (1, 3) WRONLY (2, 4) void
119 rd1_3_wr2_4 (const void*, void*, int, int);
120 
test_rd1_3_wr2_4(const void * s,void * d,int n1,int n2)121 void test_rd1_3_wr2_4 (const void *s, void *d, int n1, int n2)
122 {
123   rd1_3_wr2_4 (s, d, 1, 2);
124   rd1_3_wr2_4 (s, d, 123, 456);
125   rd1_3_wr2_4 (s, d, INT_MAX, INT_MAX);
126   rd1_3_wr2_4 (s, d, -1, 2);    // { dg-warning "argument 3 value -1 is negative" }
127 
128   const int ir_min_m1 = SR (INT_MIN, -1);
129   rd1_3_wr2_4 (s, d, ir_min_m1, 2);   // { dg-warning "argument 3 range \\\[-\[0-9\]+, -1] is negative" }
130 
131   rd1_3_wr2_4 (s, d, SR (-1, 0), 2);
132   rd1_3_wr2_4 (s, d, SR (INT_MIN, INT_MAX), 2);
133 
134   rd1_3_wr2_4 (s, d, n1, n2);
135 
136 
137   const char s11[11] = "0123456789";
138 
139   rd1_3_wr2_4 (s11, d, 11, n2);
140   rd1_3_wr2_4 (s11, d, 12, n2);   // { dg-warning "'rd1_3_wr2_4' reading 12 bytes from a region of size 11" }
141 
142   rd1_3_wr2_4 (s11, d, SR (0, 11), n2);
143   rd1_3_wr2_4 (s11, d, SR (0, 12), n2);
144   rd1_3_wr2_4 (s11, d, SR (11, 12), n2);
145   rd1_3_wr2_4 (s11, d, SR (11, INT_MAX), n2);
146   rd1_3_wr2_4 (s11, d, SR (12, 13), n2);  // { dg-warning "'rd1_3_wr2_4' reading between 12 and 13 bytes from a region of size 11" }
147 
148   char d4[4];
149   rd1_3_wr2_4 (s, d4, n1, 4);
150   rd1_3_wr2_4 (s, d4, n1, 5);     // { dg-warning "'rd1_3_wr2_4' writing 5 bytes into a region of size 4" }
151 
152   rd1_3_wr2_4 (s11, d4, SR (12, 13), SR (5, 6));
153   // { dg-warning "'rd1_3_wr2_4' reading between 12 and 13 bytes from a region of size 11" "read" { target *-*-* } .-1 }
154   // { dg-warning "'rd1_3_wr2_4' writing between 5 and 6 bytes into a region of size 4" "read" { target *-*-* } .-2 }
155 }
156 
157 
158 /* Verify that function pointers are handled.  */
159 
160 RDONLY (1) void (*pfrd1)(const void*, const void*);
161 
test_pfrd1(void)162 void test_pfrd1 (void)
163 {
164   pfrd1 ("" + SR (0, 9), "" + SR (1, 9));
165   pfrd1 ("" + SR (1, 2), "");   // { dg-warning "reading 1 byte from a region of size 0" }
166 }
167 
168 
169 WRONLY (4, 3) void (*pfwr4_3)(int, const char*, int, int32_t*);
170 
test_pfwr4_3(void)171 void test_pfwr4_3 (void)
172 {
173   int32_t i;
174   pfwr4_3 (3, "", 0, &i + SR (0, 9));
175   pfwr4_3 (5, "", 1, &i + SR (1, 2));   // { dg-warning "writing 4 bytes into a region of size 0" }
176 }
177