aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-16.c
blob: f975e16f36f7830addbd722d103486d2b888651a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/* PR middle-end/80364 - sanitizer detects signed integer overflow
   in gimple-ssa-sprintf.c
   { dg-do compile }
   { dg-options "-O2 -Wall -Wformat-overflow=1 -ftrack-macro-expansion=0" }
   { dg-require-effective-target int32plus } */

typedef __SIZE_TYPE__  size_t;
typedef __WCHAR_TYPE__ wchar_t;

void sink (void*);
void* get_value (void);

/* Return a random width as type T.  */
#define W(T) *(T*)get_value ()

/* Return a random precision as type T.  */
#define P(T) *(T*)get_value ()

/* Return a random value as type T.  */
#define V(T) *(T*)get_value ()

extern char buf[1];

/* Test convenience macro.  */
#define T(fmt, ...)					\
  __builtin_sprintf (buf + 1, fmt, __VA_ARGS__);	\
  sink (buf)

typedef signed char         schar_t;
typedef unsigned char       uchar_t;
typedef signed short        sshort_t;
typedef unsigned short      ushort_t;
typedef signed int          sint_t;
typedef unsigned int        uint_t;
typedef signed long         slong_t;
typedef unsigned long       ulong_t;
typedef signed long long    sllong_t;
typedef unsigned long long  ullong_t;

#if __SIZEOF_INT128__
typedef __int128_t          sint128_t;
typedef __uint128_t         uint128_t;
#else
/* When __int128_t is not available, repeat the same tests with long long.
   This is to avoid having to guard the tests below and to avoid making
   the dg-warning directives conditional.  */
typedef signed long long    sint128_t;
typedef unsigned long long  uint128_t;
#endif

const sint128_t sint128_max
  = (sint128_t)1 << (sizeof sint128_max * __CHAR_BIT__ - 2);
const sint128_t uint128_max = (uint128_t)-1;

void test_width_cst (void)
{
  T ("%*i", W (schar_t), 1);     /* { dg-warning "between 1 and 128 " } */
  T ("%*i", W (uchar_t), 12);    /* { dg-warning "between 2 and 255 " } */

  T ("%*i", W (sshort_t), 123);  /* { dg-warning "between 3 and 32768 " } */
  T ("%*i", W (ushort_t), 1234); /* { dg-warning "between 4 and 65535 " } */

  T ("%*i", W (sint_t), 12345);  /* { dg-warning "between 5 and 2147483648 " } */
  T ("%*i", W (uint_t), 123456); /* { dg-warning "between 6 and 2147483648 " } */

  /* Exercise calls with invalid arguments (to verify there is no ICE).  */
  T ("%*li", W (slong_t), 1234567L);  /* { dg-warning "between 7 and 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  T ("%*li", W (ulong_t), 12345678L); /* { dg-warning "between 8 and 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */

  T ("%*lli", W (sllong_t), 123456789LL);  /* { dg-warning "between 9 and 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  T ("%*lli", W (ullong_t), 1234567890LL); /* { dg-warning "between 10 and 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */

  T ("%*i", W (sint128_t), 0);  /* { dg-warning "between 1 and 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  T ("%*i", W (uint128_t), 1); /* { dg-warning "between 1 and 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */

  {
    extern sint128_t si128;
    if (si128 < sint128_max / 2 || sint128_max - 8 < si128)
      si128 = sint128_max / 2;

    T ("%*i", si128, 0);  /* { dg-warning "between 1 and 2147483648 " } */
    /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */

    extern uint128_t ui128;
    if (ui128 < uint128_max / 2 || uint128_max - 8 < ui128)
      ui128 = uint128_max / 2;

    T ("%*i", ui128, 0);  /* { dg-warning "between 1 and 2147483648 " } */
    /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  }

  T ("%*i", W (float), 2);  /* { dg-warning "between 1 and 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  T ("%*i", W (double), 3); /* { dg-warning "between 1 and 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
}

void test_width_var (void)
{
  T ("%*i", W (schar_t), V (schar_t));     /* { dg-warning "between 1 and 128 " } */
  T ("%*i", W (uchar_t), V (uchar_t));    /* { dg-warning "between 1 and 255 " } */

  T ("%*i", W (sshort_t), V (sshort_t));  /* { dg-warning "between 1 and 32768 " } */
  T ("%*i", W (ushort_t), V (ushort_t)); /* { dg-warning "between 1 and 65535 " } */

  T ("%*i", W (sint_t), V (sint_t));  /* { dg-warning "between 1 and 2147483648 " } */
  T ("%*i", W (uint_t), V (uint_t)); /* { dg-warning "between 1 and 2147483648 " } */

  /* Exercise calls with invalid arguments (to verify there is no ICE).  */
  T ("%*li", W (slong_t), V (slong_t));  /* { dg-warning "between 1 and 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  T ("%*li", W (ulong_t), V (ulong_t)); /* { dg-warning "between 1 and 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */

  T ("%*lli", W (sllong_t), V (sllong_t));  /* { dg-warning "between 1 and 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  T ("%*lli", W (ullong_t), V (ullong_t)); /* { dg-warning "between 1 and 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */

  T ("%*i", W (float), V (int));  /* { dg-warning "between 1 and 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  T ("%*i", W (double), V (int)); /* { dg-warning "between 1 and 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */

  {
    /* Create an unsigned range with a lower bound greater than 1 and
       an upper bound in excess of INT_MAX and verify that after conversion
       to signed int the lower bound isn't used as the minimum output (since
       the excessive upper bound wraps around zero).  Passing the precision
       as unsigned, without the cast to signed int, is undedined.
       It's possible to constrain the upper bound on the output more, based
       on the upper bound of the width here, but not worth the trouble.  */
    unsigned w = W (unsigned);
    if (w < 5 || (unsigned)-1 - 7 < w)
      w = 5;
    int val = V (int);

    T ("%*u", (int)w, val);   /* { dg-warning "between 1 and 2147483648 " } */
  }

  {
    /* Verify that enums are correctly handled (i.e., that the warning
       doesn't just test for TREE_CODE(type) == INTEGER_TYPE but instead
       uses INTEGRAL_TYPE_P() or some equivalent.  */
    enum WidthEnum { e7 = 7, e9 = 9 };
    enum WidthEnum w = V (enum WidthEnum);
    if (w < e7 || e9 < w)
      w = e7;

    T ("%*hu", w, V (int));   /* { dg-warning "between 7 and 9 " } */
  }
}

void test_precision_cst (void)
{
  T ("%.*i", P (schar_t), 1);     /* { dg-warning "between 1 and 127 " } */
  T ("%.*i", P (uchar_t), 12);    /* { dg-warning "between 2 and 255 " } */

  T ("%.*i", P (sshort_t), 123);  /* { dg-warning "between 3 and 32767 " } */
  T ("%.*i", P (ushort_t), 1234); /* { dg-warning "between 4 and 65535 " } */

  T ("%.*i", P (sint_t), 12345);  /* { dg-warning "between 5 and 2147483647 " } */
  T ("%.*i", P (uint_t), 123456); /* { dg-warning "between 6 and 2147483647 " } */

  /* Exercise calls with invalid arguments (to verify there is no ICE).  */
  T ("%.*li", P (slong_t), 1234567L);  /* { dg-warning "between 7 and 2147483647 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  T ("%.*li", P (ulong_t), 12345678L); /* { dg-warning "between 8 and 2147483647 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */

  T ("%.*lli", P (sllong_t), 123456789LL);  /* { dg-warning "between 9 and 2147483647 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  T ("%.*lli", P (ullong_t), 1234567890LL); /* { dg-warning "between 10 and 2147483647 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */

  T ("%.*i", P (sint128_t), 0);  /* { dg-warning "up to 2147483647 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  T ("%.*i", P (uint128_t), 1); /* { dg-warning "between 1 and 2147483647 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */

  {
    extern sint128_t si128;
    if (si128 < sint128_max / 2 || sint128_max - 8 < si128)
      si128 = sint128_max / 2;

    T ("%.*i", si128, 0);  /* { dg-warning "up to 2147483647 " } */
    /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */

    extern uint128_t ui128;
    if (ui128 < uint128_max / 2 || uint128_max - 8 < ui128)
      ui128 = uint128_max / 2;

    T ("%.*i", ui128, 0);  /* { dg-warning "up to 2147483647 " } */
    /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  }

  T ("%.*i", P (float), 0);  /* { dg-warning "up to 2147483647 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  T ("%.*i", P (double), 1); /* { dg-warning "between 1 and 2147483647 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
}

void test_precision_var (void)
{
  T ("%.*i", P (schar_t), V (schar_t));     /* { dg-warning "up to 128 " } */
  T ("%.*i", P (uchar_t), V (uchar_t));    /* { dg-warning "up to 255 " } */

  T ("%.*i", P (sshort_t), V (sshort_t));  /* { dg-warning "up to 32768 " } */
  T ("%.*i", P (ushort_t), V (ushort_t)); /* { dg-warning "up to 65535 " } */

  T ("%.*i", P (sint_t), V (sint_t));  /* { dg-warning "up to 2147483648 " } */
  T ("%.*i", P (uint_t), V (uint_t)); /* { dg-warning "up to 2147483648 " } */

  /* Exercise calls with invalid arguments (to verify there is no ICE).  */
  T ("%.*li", P (slong_t), V (slong_t));  /* { dg-warning "up to 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  T ("%.*li", P (ulong_t), V (ulong_t)); /* { dg-warning "up to 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */

  T ("%.*lli", P (sllong_t), V (sllong_t));  /* { dg-warning "up to 2147483648" } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  T ("%.*lli", P (ullong_t), V (ullong_t)); /* { dg-warning "up to 2147483648" } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */

  T ("%.*i", P (float), V (int));  /* { dg-warning "up to 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */
  T ("%.*i", P (double), V (int)); /* { dg-warning "up to 2147483648 " } */
  /* { dg-warning "expects argument of type .int." "" { target *-*-* } .-1 } */

  {
    /* Similar to the corresponding width case, create an unsigned range
       with a lower bound greater than 1 and an upper bound in excess of
       INT_MAX and verify that after conversion to int the lower bound isn't
       used as the minimum output (since the excessive upper bound wraps
       around zero).  Passing the precision as unsigned, without a cast to
       signed int, is undefined.  */
    unsigned p = V (unsigned);
    if (p < 7 || (unsigned)-1 - 9 < p)
      p = 7;

    int val = V (int);

    T ("%.*u", (int)p, val);   /* { dg-warning "up to 2147483647 " } */
  }

  {
    /* Verify that enums are correctly handled.  */
    enum PrecEnum { e9 = 9, e17 = 17 };
    enum PrecEnum p = V (enum PrecEnum);
    if (p < e9 || e17 < p)
      p = e9;

    T ("%.*u", p, V (int));   /* { dg-warning "between 9 and 17 " } */
  }
}