| 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 | |