308 lines · c
1// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify -Wformat-nonliteral %s2 3// Test that -Wformat=0 works:4// RUN: %clang_cc1 -std=c11 -fsyntax-only -Werror -Wformat=0 %s5 6#include <stdarg.h>7typedef __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))15typedef __SSIZE_TYPE__ ssize_t;16 17typedef __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 26typedef struct _FILE FILE;27typedef __WCHAR_TYPE__ wchar_t;28 29int fscanf(FILE * restrict, const char * restrict, ...) ;30int scanf(const char * restrict, ...) ;31int sscanf(const char * restrict, const char * restrict, ...) ;32int my_scanf(const char * restrict, ...) __attribute__((__format__(__scanf__, 1, 2)));33int my_gnu_scanf(const char * restrict, ...) __attribute__((__format__(gnu_scanf, 1, 2)));34 35int vscanf(const char * restrict, va_list);36int vfscanf(FILE * restrict, const char * restrict, va_list);37int vsscanf(const char * restrict, const char * restrict, va_list);38 39void test(const char *s, int *i) {40 scanf(s, i); // expected-warning{{format string is not a string literal}}41 scanf("%0d", i); // expected-warning{{zero field width in scanf format string is unused}}42 scanf("%00d", i); // expected-warning{{zero field width in scanf format string is unused}}43 scanf("%d%[asdfasdfd", i, s); // expected-warning{{no closing ']' for '%[' in scanf format string}}44 scanf("%B", i); // expected-warning{{invalid conversion specifier 'B'}}45 46 unsigned short s_x;47 scanf ("%" "hu" "\n", &s_x); // no-warning48 scanf("%hb", &s_x);49 scanf("%y", i); // expected-warning{{invalid conversion specifier 'y'}}50 scanf("%%"); // no-warning51 scanf("%%%1$d", i); // no-warning52 scanf("%1$d%%", i); // no-warning53 scanf("%d", i, i); // expected-warning{{data argument not used by format string}}54 scanf("%*d", i); // // expected-warning{{data argument not used by format string}}55 scanf("%*d", i); // // expected-warning{{data argument not used by format string}}56 scanf("%*d%1$d", i); // no-warning57 58 scanf("%s", (char*)0); // no-warning59 scanf("%s", (volatile char*)0); // no-warning60 scanf("%s", (signed char*)0); // no-warning61 scanf("%s", (unsigned char*)0); // no-warning62 scanf("%hhu", (signed char*)0); // no-warning63 scanf("%hhb", (signed char*)0); // no-warning64}65 66void bad_length_modifiers(char *s, void *p, wchar_t *ws, long double *ld) {67 scanf("%hhs", "foo"); // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 's' conversion specifier}}68 scanf("%1$zp", &p); // expected-warning{{length modifier 'z' results in undefined behavior or no effect with 'p' conversion specifier}}69 scanf("%ls", ws); // no-warning70 scanf("%#.2Lf", ld); // expected-warning{{invalid conversion specifier '#'}}71}72 73void missing_argument_with_length_modifier() {74 char buf[30];75 scanf("%s:%900s", buf); // expected-warning{{more '%' conversions than data arguments}}76}77 78// Test that the scanf call site is where the warning is attached. If the79// format string is somewhere else, point to it in a note.80void pr9751(void) {81 int *i;82 char str[100];83 const char kFormat1[] = "%00d"; // expected-note{{format string is defined here}}}84 scanf(kFormat1, i); // expected-warning{{zero field width in scanf format string is unused}}85 scanf("%00d", i); // expected-warning{{zero field width in scanf format string is unused}}86 const char kFormat2[] = "%["; // expected-note{{format string is defined here}}}87 scanf(kFormat2, str); // expected-warning{{no closing ']' for '%[' in scanf format string}}88 scanf("%[", str); // expected-warning{{no closing ']' for '%[' in scanf format string}}89 const char kFormat3[] = "%hu"; // expected-note{{format string is defined here}}}90 scanf(kFormat3, &i); // expected-warning {{format specifies type 'unsigned short *' but the argument}}91 const char kFormat4[] = "%lp"; // expected-note{{format string is defined here}}}92 scanf(kFormat4, &i); // expected-warning {{length modifier 'l' results in undefined behavior or no effect with 'p' conversion specifier}}93}94 95void test_variants(int *i, const char *s, ...) {96 FILE *f = 0;97 char buf[100];98 99 fscanf(f, "%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}100 sscanf(buf, "%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}101 my_scanf("%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}102 my_gnu_scanf("%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}103 104 va_list ap;105 va_start(ap, s);106 107 vscanf("%[abc", ap); // expected-warning{{no closing ']' for '%[' in scanf format string}}108 vfscanf(f, "%[abc", ap); // expected-warning{{no closing ']' for '%[' in scanf format string}}109 vsscanf(buf, "%[abc", ap); // expected-warning{{no closing ']' for '%[' in scanf format string}}110}111 112void test_scanlist(int *ip, char *sp, wchar_t *ls) {113 scanf("%[abc]", ip); // expected-warning{{format specifies type 'char *' but the argument has type 'int *'}}114 scanf("%h[abc]", sp); // expected-warning{{length modifier 'h' results in undefined behavior or no effect with '[' conversion specifier}}115 scanf("%l[xyx]", ls); // no-warning116 scanf("%ll[xyx]", ls); // expected-warning {{length modifier 'll' results in undefined behavior or no effect with '[' conversion specifier}}117 118 // PR19559119 scanf("%[]% ]", sp); // no-warning120 scanf("%[^]% ]", sp); // no-warning121 scanf("%[a^]% ]", sp); // expected-warning {{invalid conversion specifier ' '}}122}123 124void test_alloc_extension(char **sp, wchar_t **lsp, float *fp) {125 /* Make sure "%a" gets parsed as a conversion specifier for float,126 * even when followed by an 's', 'S' or '[', which would cause it to be127 * parsed as a length modifier in C90. */128 scanf("%as", sp); // expected-warning{{format specifies type 'float *' but the argument has type 'char **'}}129 scanf("%aS", lsp); // expected-warning{{format specifies type 'float *' but the argument has type 'wchar_t **'}}130 scanf("%a[bcd]", sp); // expected-warning{{format specifies type 'float *' but the argument has type 'char **'}}131 132 // Test that the 'm' length modifier is only allowed with s, S, c, C or [.133 // TODO: Warn that 'm' is an extension.134 scanf("%ms", sp); // No warning.135 scanf("%mS", lsp); // No warning.136 scanf("%mc", sp); // No warning.137 scanf("%mC", lsp); // No warning.138 scanf("%m[abc]", sp); // No warning.139 scanf("%md", sp); // expected-warning{{length modifier 'm' results in undefined behavior or no effect with 'd' conversion specifier}}140 141 // Test argument type check for the 'm' length modifier.142 scanf("%ms", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}143 scanf("%mS", fp); // expected-warning-re{{format specifies type 'wchar_t **' (aka '{{[^']+}}') but the argument has type 'float *'}}144 scanf("%mc", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}145 scanf("%mC", fp); // expected-warning-re{{format specifies type 'wchar_t **' (aka '{{[^']+}}') but the argument has type 'float *'}}146 scanf("%m[abc]", fp); // expected-warning{{format specifies type 'char **' but the argument has type 'float *'}}147}148 149void test_quad(int *x, long long *llx) {150 scanf("%qd", x); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}151 scanf("%qd", llx); // no-warning152}153 154void test_writeback(int *x) {155 scanf("%n", (void*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'void *'}}156 scanf("%n %c", x, x); // expected-warning{{format specifies type 'char *' but the argument has type 'int *'}}157 158 scanf("%hhn", (signed char*)0); // no-warning159 scanf("%hhn", (char*)0); // no-warning160 scanf("%hhn", (unsigned char*)0); // no-warning161 scanf("%hhn", (int*)0); // expected-warning{{format specifies type 'signed char *' but the argument has type 'int *'}}162 163 scanf("%hn", (short*)0); // no-warning164 scanf("%hn", (unsigned short*)0); // no-warning165 scanf("%hn", (int*)0); // expected-warning{{format specifies type 'short *' but the argument has type 'int *'}}166 167 scanf("%n", (int*)0); // no-warning168 scanf("%n", (unsigned int*)0); // no-warning169 scanf("%n", (char*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}}170 171 scanf("%ln", (long*)0); // no-warning172 scanf("%ln", (unsigned long*)0); // no-warning173 scanf("%ln", (int*)0); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}174 175 scanf("%lln", (long long*)0); // no-warning176 scanf("%lln", (unsigned long long*)0); // no-warning177 scanf("%lln", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}178 179 scanf("%qn", (long long*)0); // no-warning180 scanf("%qn", (unsigned long long*)0); // no-warning181 scanf("%qn", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}182 183}184 185void test_qualifiers(const int *cip, volatile int* vip,186 const char *ccp, volatile char* vcp,187 const volatile int *cvip) {188 scanf("%d", cip); // expected-warning{{format specifies type 'int *' but the argument has type 'const int *'}}189 scanf("%n", cip); // expected-warning{{format specifies type 'int *' but the argument has type 'const int *'}}190 scanf("%s", ccp); // expected-warning{{format specifies type 'char *' but the argument has type 'const char *'}}191 scanf("%d", cvip); // expected-warning{{format specifies type 'int *' but the argument has type 'const volatile int *'}}192 193 scanf("%d", vip); // No warning.194 scanf("%n", vip); // No warning.195 scanf("%c", vcp); // No warning.196 197 typedef int* ip_t;198 typedef const int* cip_t;199 scanf("%d", (ip_t)0); // No warning.200 scanf("%d", (cip_t)0); // expected-warning{{format specifies type 'int *' but the argument has type 'cip_t' (aka 'const int *')}}201}202 203void test_size_types(void) {204 size_t s = 0;205 scanf("%zu", &s); // No warning.206 scanf("%zb", &s);207 208 double d1 = 0.;209 scanf("%zu", &d1); // expected-warning-re{{format specifies type 'size_t *' (aka '{{.+}}') but the argument has type 'double *'}}210 211 ssize_t ss = 0;212 scanf("%zd", &s); // No warning.213 214 double d2 = 0.;215 scanf("%zd", &d2); // expected-warning-re{{format specifies type 'signed size_t *' (aka '{{.+}}') but the argument has type 'double *'}}216 217 ssize_t sn = 0;218 scanf("%zn", &sn); // No warning.219 220 double d3 = 0.;221 scanf("%zn", &d3); // expected-warning-re{{format specifies type 'signed size_t *' (aka '{{.+}}') but the argument has type 'double *'}}222}223 224void test_ptrdiff_t_types(void) {225 __UNSIGNED_PTRDIFF_TYPE__ p1 = 0;226 scanf("%tu", &p1); // No warning.227 scanf("%tb", &p1);228 229 double d1 = 0.;230 scanf("%tu", &d1); // expected-warning-re{{format specifies type 'unsigned ptrdiff_t *' (aka '{{.+}}') but the argument has type 'double *'}}231 232 ptrdiff_t p2 = 0;233 scanf("%td", &p2); // No warning.234 235 double d2 = 0.;236 scanf("%td", &d2); // expected-warning-re{{format specifies type 'ptrdiff_t *' (aka '{{.+}}') but the argument has type 'double *'}}237 238 ptrdiff_t p3 = 0;239 scanf("%tn", &p3); // No warning.240 241 double d3 = 0.;242 scanf("%tn", &d3); // expected-warning-re{{format specifies type 'ptrdiff_t *' (aka '{{.+}}') but the argument has type 'double *'}}243}244 245void check_conditional_literal(char *s, int *i) {246 scanf(0 ? "%s" : "%d", i); // no warning247 scanf(1 ? "%s" : "%d", i); // expected-warning{{format specifies type 'char *'}}248 scanf(0 ? "%d %d" : "%d", i); // no warning249 scanf(1 ? "%d %d" : "%d", i); // expected-warning{{more '%' conversions than data arguments}}250 scanf(0 ? "%d %d" : "%d", i, s); // expected-warning{{data argument not used}}251 scanf(1 ? "%d %s" : "%d", i, s); // no warning252 scanf(i ? "%d %s" : "%d", i, s); // no warning253 scanf(i ? "%d" : "%d", i, s); // expected-warning{{data argument not used}}254 scanf(i ? "%s" : "%d", s); // expected-warning{{format specifies type 'int *'}}255}256 257void test_promotion(void) {258 // No promotions for *scanf pointers clarified in N2562259 // https://github.com/llvm/llvm-project/issues/57102260 // N2562: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2562.pdf261 int i;262 signed char sc;263 unsigned char uc;264 short ss;265 unsigned short us;266 267 // pointers could not be "promoted"268 scanf("%hhd", &i); // expected-warning{{format specifies type 'char *' but the argument has type 'int *'}}269 scanf("%hd", &i); // expected-warning{{format specifies type 'short *' but the argument has type 'int *'}}270 scanf("%d", &i); // no-warning271 // char & uchar272 scanf("%hhd", &sc); // no-warning273 scanf("%hhd", &uc); // no-warning274 scanf("%hd", &sc); // expected-warning{{format specifies type 'short *' but the argument has type 'signed char *'}}275 scanf("%hd", &uc); // expected-warning{{format specifies type 'short *' but the argument has type 'unsigned char *'}}276 scanf("%d", &sc); // expected-warning{{format specifies type 'int *' but the argument has type 'signed char *'}}277 scanf("%d", &uc); // expected-warning{{format specifies type 'int *' but the argument has type 'unsigned char *'}}278 // short & ushort279 scanf("%hhd", &ss); // expected-warning{{format specifies type 'char *' but the argument has type 'short *'}}280 scanf("%hhd", &us); // expected-warning{{format specifies type 'char *' but the argument has type 'unsigned short *'}}281 scanf("%hd", &ss); // no-warning282 scanf("%hd", &us); // no-warning283 scanf("%d", &ss); // expected-warning{{format specifies type 'int *' but the argument has type 'short *'}}284 scanf("%d", &us); // expected-warning{{format specifies type 'int *' but the argument has type 'unsigned short *'}}285 286 // long types287 scanf("%ld", &i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}288 scanf("%lld", &i); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}289 scanf("%ld", &sc); // expected-warning{{format specifies type 'long *' but the argument has type 'signed char *'}}290 scanf("%lld", &sc); // expected-warning{{format specifies type 'long long *' but the argument has type 'signed char *'}}291 scanf("%ld", &uc); // expected-warning{{format specifies type 'long *' but the argument has type 'unsigned char *'}}292 scanf("%lld", &uc); // expected-warning{{format specifies type 'long long *' but the argument has type 'unsigned char *'}}293 scanf("%llx", &i); // expected-warning{{format specifies type 'unsigned long long *' but the argument has type 'int *'}}294 295 // ill-formed floats296 scanf("%hf", // expected-warning{{length modifier 'h' results in undefined behavior or no effect with 'f' conversion specifier}}297 &sc);298 299 // pointers in scanf300 scanf("%s", i); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}301 302 // FIXME: does this match what the C committee allows or should it be pedantically warned on?303 char c;304 void *vp;305 scanf("%hhd", &c); // Pedantic warning?306 scanf("%hhd", vp); // expected-warning{{format specifies type 'char *' but the argument has type 'void *'}}307}308