1 | // RUN: %clang_cc1 -std=c11 -fsyntax-only -verify -Wformat-nonliteral %s |
2 | |
3 | // Test that -Wformat=0 works: |
4 | // RUN: %clang_cc1 -std=c11 -fsyntax-only -Werror -Wformat=0 %s |
5 | |
6 | #include <stdarg.h> |
7 | typedef __SIZE_TYPE__ size_t; |
8 | #define __SSIZE_TYPE__ \ |
9 | __typeof__(_Generic((__SIZE_TYPE__)0, \ |
10 | unsigned long long int : (long long int)0, \ |
11 | unsigned long int : (long int)0, \ |
12 | unsigned int : (int)0, \ |
13 | unsigned short : (short)0, \ |
14 | unsigned char : (signed char)0)) |
15 | typedef __SSIZE_TYPE__ ssize_t; |
16 | |
17 | typedef __PTRDIFF_TYPE__ ptrdiff_t; |
18 | #define __UNSIGNED_PTRDIFF_TYPE__ \ |
19 | __typeof__(_Generic((__PTRDIFF_TYPE__)0, \ |
20 | long long int : (unsigned long long int)0, \ |
21 | long int : (unsigned long int)0, \ |
22 | int : (unsigned int)0, \ |
23 | short : (unsigned short)0, \ |
24 | signed char : (unsigned char)0)) |
25 | |
26 | typedef struct _FILE FILE; |
27 | typedef __WCHAR_TYPE__ wchar_t; |
28 | |
29 | int fscanf(FILE * restrict, const char * restrict, ...) ; |
30 | int scanf(const char * restrict, ...) ; |
31 | int sscanf(const char * restrict, const char * restrict, ...) ; |
32 | int my_scanf(const char * restrict, ...) __attribute__((__format__(__scanf__, 1, 2))); |
33 | |
34 | int vscanf(const char * restrict, va_list); |
35 | int vfscanf(FILE * restrict, const char * restrict, va_list); |
36 | int vsscanf(const char * restrict, const char * restrict, va_list); |
37 | |
38 | void test(const char *s, int *i) { |
39 | scanf(s, i); // expected-warning{{format string is not a string literal}} |
40 | scanf("%0d", i); // expected-warning{{zero field width in scanf format string is unused}} |
41 | scanf("%00d", i); // expected-warning{{zero field width in scanf format string is unused}} |
42 | scanf("%d%[asdfasdfd", i, s); // expected-warning{{no closing ']' for '%[' in scanf format string}} |
43 | |
44 | unsigned short s_x; |
45 | scanf ("%" "hu" "\n", &s_x); // no-warning |
46 | scanf("%y", i); // expected-warning{{invalid conversion specifier 'y'}} |
47 | scanf("%%"); // no-warning |
48 | scanf("%%%1$d", i); // no-warning |
49 | scanf("%1$d%%", i); // no-warning |
50 | scanf("%d", i, i); // expected-warning{{data argument not used by format string}} |
51 | scanf("%*d", i); // // expected-warning{{data argument not used by format string}} |
52 | scanf("%*d", i); // // expected-warning{{data argument not used by format string}} |
53 | scanf("%*d%1$d", i); // no-warning |
54 | |
55 | scanf("%s", (char*)0); // no-warning |
56 | scanf("%s", (volatile char*)0); // no-warning |
57 | scanf("%s", (signed char*)0); // no-warning |
58 | scanf("%s", (unsigned char*)0); // no-warning |
59 | scanf("%hhu", (signed char*)0); // no-warning |
60 | } |
61 | |
62 | void bad_length_modifiers(char *s, void *p, wchar_t *ws, long double *ld) { |
63 | scanf("%hhs", "foo"); // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 's' conversion specifier}} |
64 | scanf("%1$zp", &p); // expected-warning{{length modifier 'z' results in undefined behavior or no effect with 'p' conversion specifier}} |
65 | scanf("%ls", ws); // no-warning |
66 | scanf("%#.2Lf", ld); // expected-warning{{invalid conversion specifier '#'}} |
67 | } |
68 | |
69 | // Test that the scanf call site is where the warning is attached. If the |
70 | // format string is somewhere else, point to it in a note. |
71 | void pr9751() { |
72 | int *i; |
73 | char str[100]; |
74 | const char kFormat1[] = "%00d"; // expected-note{{format string is defined here}}} |
75 | scanf(kFormat1, i); // expected-warning{{zero field width in scanf format string is unused}} |
76 | scanf("%00d", i); // expected-warning{{zero field width in scanf format string is unused}} |
77 | const char kFormat2[] = "%["; // expected-note{{format string is defined here}}} |
78 | scanf(kFormat2, str); // expected-warning{{no closing ']' for '%[' in scanf format string}} |
79 | scanf("%[", str); // expected-warning{{no closing ']' for '%[' in scanf format string}} |
80 | const char kFormat3[] = "%hu"; // expected-note{{format string is defined here}}} |
81 | scanf(kFormat3, &i); // expected-warning {{format specifies type 'unsigned short *' but the argument}} |
82 | const char kFormat4[] = "%lp"; // expected-note{{format string is defined here}}} |
83 | scanf(kFormat4, &i); // expected-warning {{length modifier 'l' results in undefined behavior or no effect with 'p' conversion specifier}} |
84 | } |
85 | |
86 | void test_variants(int *i, const char *s, ...) { |
87 | FILE *f = 0; |
88 | char buf[100]; |
89 | |
90 | fscanf(f, "%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}} |
91 | sscanf(buf, "%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}} |
92 | my_scanf("%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}} |
93 | |
94 | va_list ap; |
95 | va_start(ap, s); |
96 | |
97 | vscanf("%[abc", ap); // expected-warning{{no closing ']' for '%[' in scanf format string}} |
98 | vfscanf(f, "%[abc", ap); // expected-warning{{no closing ']' for '%[' in scanf format string}} |
99 | vsscanf(buf, "%[abc", ap); // expected-warning{{no closing ']' for '%[' in scanf format string}} |
100 | } |
101 | |
102 | void test_scanlist(int *ip, char *sp, wchar_t *ls) { |
103 | scanf("%[abc]", ip); // expected-warning{{format specifies type 'char *' but the argument has type 'int *'}} |
104 | scanf("%h[abc]", sp); // expected-warning{{length modifier 'h' results in undefined behavior or no effect with '[' conversion specifier}} |
105 | scanf("%l[xyx]", ls); // no-warning |
106 | scanf("%ll[xyx]", ls); // expected-warning {{length modifier 'll' results in undefined behavior or no effect with '[' conversion specifier}} |
107 | |
108 | // PR19559 |
109 | scanf("%[]% ]", sp); // no-warning |
110 | scanf("%[^]% ]", sp); // no-warning |
111 | scanf("%[a^]% ]", sp); // expected-warning {{invalid conversion specifier ' '}} |
112 | } |
113 | |
114 | void test_alloc_extension(char **sp, wchar_t **lsp, float *fp) { |
115 | /* Make sure "%a" gets parsed as a conversion specifier for float, |
116 | * even when followed by an 's', 'S' or '[', which would cause it to be |
117 | * parsed as a length modifier in C90. */ |
118 | scanf("%as", sp); // expected-warning{{format specifies type 'float *' but the argument has type 'char **'}} |
119 | scanf("%aS", lsp); // expected-warning{{format specifies type 'float *' but the argument has type 'wchar_t **'}} |
120 | scanf("%a[bcd]", sp); // expected-warning{{format specifies type 'float *' but the argument has type 'char **'}} |
121 | |
122 | // Test that the 'm' length modifier is only allowed with s, S, c, C or [. |
123 | // TODO: Warn that 'm' is an extension. |
124 | scanf("%ms", sp); // No warning. |
125 | scanf("%mS", lsp); // No warning. |
126 | scanf("%mc", sp); // No warning. |
127 | scanf("%mC", lsp); // No warning. |
128 | scanf("%m[abc]", sp); // No warning. |
129 | scanf("%md", sp); // expected-warning{{length modifier 'm' results in undefined behavior or no effect with 'd' conversion specifier}} |
130 | |
131 | // Test argument type check for the 'm' length modifier. |
132 | scanf("%ms", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}} |
133 | scanf("%mS", fp); // expected-warning-re{{format specifies type 'wchar_t **' (aka '{{[^']+}}') but the argument has type 'float *'}} |
134 | scanf("%mc", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}} |
135 | scanf("%mC", fp); // expected-warning-re{{format specifies type 'wchar_t **' (aka '{{[^']+}}') but the argument has type 'float *'}} |
136 | scanf("%m[abc]", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}} |
137 | } |
138 | |
139 | void test_quad(int *x, long long *llx) { |
140 | scanf("%qd", x); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}} |
141 | scanf("%qd", llx); // no-warning |
142 | } |
143 | |
144 | void test_writeback(int *x) { |
145 | scanf("%n", (void*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'void *'}} |
146 | scanf("%n %c", x, x); // expected-warning{{format specifies type 'char *' but the argument has type 'int *'}} |
147 | |
148 | scanf("%hhn", (signed char*)0); // no-warning |
149 | scanf("%hhn", (char*)0); // no-warning |
150 | scanf("%hhn", (unsigned char*)0); // no-warning |
151 | scanf("%hhn", (int*)0); // expected-warning{{format specifies type 'signed char *' but the argument has type 'int *'}} |
152 | |
153 | scanf("%hn", (short*)0); // no-warning |
154 | scanf("%hn", (unsigned short*)0); // no-warning |
155 | scanf("%hn", (int*)0); // expected-warning{{format specifies type 'short *' but the argument has type 'int *'}} |
156 | |
157 | scanf("%n", (int*)0); // no-warning |
158 | scanf("%n", (unsigned int*)0); // no-warning |
159 | scanf("%n", (char*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}} |
160 | |
161 | scanf("%ln", (long*)0); // no-warning |
162 | scanf("%ln", (unsigned long*)0); // no-warning |
163 | scanf("%ln", (int*)0); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}} |
164 | |
165 | scanf("%lln", (long long*)0); // no-warning |
166 | scanf("%lln", (unsigned long long*)0); // no-warning |
167 | scanf("%lln", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}} |
168 | |
169 | scanf("%qn", (long long*)0); // no-warning |
170 | scanf("%qn", (unsigned long long*)0); // no-warning |
171 | scanf("%qn", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}} |
172 | |
173 | } |
174 | |
175 | void test_qualifiers(const int *cip, volatile int* vip, |
176 | const char *ccp, volatile char* vcp, |
177 | const volatile int *cvip) { |
178 | scanf("%d", cip); // expected-warning{{format specifies type 'int *' but the argument has type 'const int *'}} |
179 | scanf("%n", cip); // expected-warning{{format specifies type 'int *' but the argument has type 'const int *'}} |
180 | scanf("%s", ccp); // expected-warning{{format specifies type 'char *' but the argument has type 'const char *'}} |
181 | scanf("%d", cvip); // expected-warning{{format specifies type 'int *' but the argument has type 'const volatile int *'}} |
182 | |
183 | scanf("%d", vip); // No warning. |
184 | scanf("%n", vip); // No warning. |
185 | scanf("%c", vcp); // No warning. |
186 | |
187 | typedef int* ip_t; |
188 | typedef const int* cip_t; |
189 | scanf("%d", (ip_t)0); // No warning. |
190 | scanf("%d", (cip_t)0); // expected-warning{{format specifies type 'int *' but the argument has type 'cip_t' (aka 'const int *')}} |
191 | } |
192 | |
193 | void test_size_types() { |
194 | size_t s = 0; |
195 | scanf("%zu", &s); // No warning. |
196 | |
197 | double d1 = 0.; |
198 | scanf("%zu", &d1); // expected-warning-re{{format specifies type 'size_t *' (aka '{{.+}}') but the argument has type 'double *'}} |
199 | |
200 | ssize_t ss = 0; |
201 | scanf("%zd", &s); // No warning. |
202 | |
203 | double d2 = 0.; |
204 | scanf("%zd", &d2); // expected-warning-re{{format specifies type 'ssize_t *' (aka '{{.+}}') but the argument has type 'double *'}} |
205 | |
206 | ssize_t sn = 0; |
207 | scanf("%zn", &sn); // No warning. |
208 | |
209 | double d3 = 0.; |
210 | scanf("%zn", &d3); // expected-warning-re{{format specifies type 'ssize_t *' (aka '{{.+}}') but the argument has type 'double *'}} |
211 | } |
212 | |
213 | void test_ptrdiff_t_types() { |
214 | __UNSIGNED_PTRDIFF_TYPE__ p1 = 0; |
215 | scanf("%tu", &p1); // No warning. |
216 | |
217 | double d1 = 0.; |
218 | scanf("%tu", &d1); // expected-warning-re{{format specifies type 'unsigned ptrdiff_t *' (aka '{{.+}}') but the argument has type 'double *'}} |
219 | |
220 | ptrdiff_t p2 = 0; |
221 | scanf("%td", &p2); // No warning. |
222 | |
223 | double d2 = 0.; |
224 | scanf("%td", &d2); // expected-warning-re{{format specifies type 'ptrdiff_t *' (aka '{{.+}}') but the argument has type 'double *'}} |
225 | |
226 | ptrdiff_t p3 = 0; |
227 | scanf("%tn", &p3); // No warning. |
228 | |
229 | double d3 = 0.; |
230 | scanf("%tn", &d3); // expected-warning-re{{format specifies type 'ptrdiff_t *' (aka '{{.+}}') but the argument has type 'double *'}} |
231 | } |
232 | |
233 | void check_conditional_literal(char *s, int *i) { |
234 | scanf(0 ? "%s" : "%d", i); // no warning |
235 | scanf(1 ? "%s" : "%d", i); // expected-warning{{format specifies type 'char *'}} |
236 | scanf(0 ? "%d %d" : "%d", i); // no warning |
237 | scanf(1 ? "%d %d" : "%d", i); // expected-warning{{more '%' conversions than data arguments}} |
238 | scanf(0 ? "%d %d" : "%d", i, s); // expected-warning{{data argument not used}} |
239 | scanf(1 ? "%d %s" : "%d", i, s); // no warning |
240 | scanf(i ? "%d %s" : "%d", i, s); // no warning |
241 | scanf(i ? "%d" : "%d", i, s); // expected-warning{{data argument not used}} |
242 | scanf(i ? "%s" : "%d", s); // expected-warning{{format specifies type 'int *'}} |
243 | } |
244 | |