909 lines · c
1// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs %s2// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs -fno-signed-char %s3// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs -triple=x86_64-unknown-fuchsia %s4// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs -triple=x86_64-linux-android %s5 6#include <stdarg.h>7#include <stddef.h>8#define __need_wint_t9#include <stddef.h> // For wint_t and wchar_t10 11typedef struct _FILE FILE;12int fprintf(FILE *, const char *restrict, ...);13int printf(const char *restrict, ...); // expected-note{{passing argument to parameter here}}14int snprintf(char *restrict, size_t, const char *restrict, ...);15int sprintf(char *restrict, const char *restrict, ...);16int vasprintf(char **, const char *, va_list);17int asprintf(char **, const char *, ...);18int vfprintf(FILE *, const char *restrict, va_list);19int vprintf(const char *restrict, va_list);20int vsnprintf(char *, size_t, const char *, va_list);21int vsprintf(char *restrict, const char *restrict, va_list); // expected-note{{passing argument to parameter here}}22 23int vscanf(const char *restrict format, va_list arg);24 25char * global_fmt;26 27void check_string_literal( FILE* fp, const char* s, char *buf, ... ) {28 29 char * b;30 va_list ap;31 va_start(ap,buf);32 33 printf(s); // expected-warning {{format string is not a string literal}}34 // expected-note@-1{{treat the string as an argument to avoid this}}35 vprintf(s,ap); // expected-warning {{format string is not a string literal}}36 fprintf(fp,s); // expected-warning {{format string is not a string literal}}37 // expected-note@-1{{treat the string as an argument to avoid this}}38 vfprintf(fp,s,ap); // expected-warning {{format string is not a string literal}}39 asprintf(&b,s); // expected-warning {{format string is not a string lit}}40 // expected-note@-1{{treat the string as an argument to avoid this}}41 vasprintf(&b,s,ap); // expected-warning {{format string is not a string literal}}42 sprintf(buf,s); // expected-warning {{format string is not a string literal}}43 // expected-note@-1{{treat the string as an argument to avoid this}}44 snprintf(buf,2,s); // expected-warning {{format string is not a string lit}}45 // expected-note@-1{{treat the string as an argument to avoid this}}46 __builtin___sprintf_chk(buf,0,-1,s); // expected-warning {{format string is not a string literal}}47 // expected-note@-1{{treat the string as an argument to avoid this}}48 __builtin___snprintf_chk(buf,2,0,-1,s); // expected-warning {{format string is not a string lit}}49 // expected-note@-1{{treat the string as an argument to avoid this}}50 vsprintf(buf,s,ap); // expected-warning {{format string is not a string lit}}51 vsnprintf(buf,2,s,ap); // expected-warning {{format string is not a string lit}}52 vsnprintf(buf,2,global_fmt,ap); // expected-warning {{format string is not a string literal}}53 __builtin___vsnprintf_chk(buf,2,0,-1,s,ap); // expected-warning {{format string is not a string lit}}54 __builtin___vsnprintf_chk(buf,2,0,-1,global_fmt,ap); // expected-warning {{format string is not a string literal}}55 56 vscanf(s, ap); // expected-warning {{format string is not a string literal}}57 58 const char *const fmt = "%d"; // FIXME -- defined here59 printf(fmt, 1, 2); // expected-warning{{data argument not used}}60 61 printf("abc"62 "%*d", 1, 1); // no-warning63 printf("abc\64def"65 "%*d", 1, 1); // no-warning66 67 // Allow 'unsigned' (instead of 'int') to be used for both the field width68 // and precision. This deviates from C99, but is reasonably safe and is also69 // accepted by GCC.70 printf("%*d", (unsigned) 1, 1); // no-warning71}72 73// When calling a non-variadic format function (vprintf, vscanf, NSLogv, ...),74// warn only if the format string argument is a parameter that is not itself75// declared as a format string with compatible format.76__attribute__((__format__ (__printf__, 2, 4)))77void check_string_literal2( FILE* fp, const char* s, char *buf, ... ) {78 char * b;79 va_list ap;80 va_start(ap,buf);81 82 printf(s); // expected-warning {{format string is not a string literal}}83 // expected-note@-1{{treat the string as an argument to avoid this}}84 vprintf(s,ap); // no-warning85 fprintf(fp,s); // expected-warning {{format string is not a string literal}}86 // expected-note@-1{{treat the string as an argument to avoid this}}87 vfprintf(fp,s,ap); // no-warning88 asprintf(&b,s); // expected-warning {{format string is not a string lit}}89 // expected-note@-1{{treat the string as an argument to avoid this}}90 vasprintf(&b,s,ap); // no-warning91 sprintf(buf,s); // expected-warning {{format string is not a string literal}}92 // expected-note@-1{{treat the string as an argument to avoid this}}93 snprintf(buf,2,s); // expected-warning {{format string is not a string lit}}94 // expected-note@-1{{treat the string as an argument to avoid this}}95 __builtin___vsnprintf_chk(buf,2,0,-1,s,ap); // no-warning96 97 vscanf(s, ap); // expected-warning {{passing 'printf' format string where 'scanf' format string is expected}}98}99 100void check_conditional_literal(const char* s, int i) {101 printf(i == 1 ? "yes" : "no"); // no-warning102 printf(i == 0 ? (i == 1 ? "yes" : "no") : "dont know"); // no-warning103 printf(i == 0 ? (i == 1 ? s : "no") : "dont know"); // expected-warning{{format string is not a string literal}}104 // expected-note@-1{{treat the string as an argument to avoid this}}105 printf("yes" ?: "no %d", 1); // expected-warning{{data argument not used by format string}}106 printf(0 ? "yes %s" : "no %d", 1); // no-warning107 printf(0 ? "yes %d" : "no %s", 1); // expected-warning{{format specifies type 'char *'}}108 109 printf(0 ? "yes" : "no %d", 1); // no-warning110 printf(0 ? "yes %d" : "no", 1); // expected-warning{{data argument not used by format string}}111 printf(1 ? "yes" : "no %d", 1); // expected-warning{{data argument not used by format string}}112 printf(1 ? "yes %d" : "no", 1); // no-warning113 printf(i ? "yes" : "no %d", 1); // no-warning114 printf(i ? "yes %s" : "no %d", 1); // expected-warning{{format specifies type 'char *'}}115 printf(i ? "yes" : "no %d", 1, 2); // expected-warning{{data argument not used by format string}}116 117 printf(i ? "%*s" : "-", i, s); // no-warning118 printf(i ? "yes" : 0 ? "no %*d" : "dont know %d", 1, 2); // expected-warning{{data argument not used by format string}}119 printf(i ? "%i\n" : "%i %s %s\n", i, s); // expected-warning{{more '%' conversions than data arguments}}120}121 122#if !defined(__ANDROID__) && !defined(__Fuchsia__)123 124void check_writeback_specifier(void)125{126 int x;127 char *b;128 printf("%n", b); // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}}129 printf("%n", &x); // no-warning130 131 printf("%hhn", (signed char*)0); // no-warning132 printf("%hhn", (char*)0); // no-warning133 printf("%hhn", (unsigned char*)0); // no-warning134 printf("%hhn", (int*)0); // expected-warning{{format specifies type 'signed char *' but the argument has type 'int *'}}135 136 printf("%hn", (short*)0); // no-warning137 printf("%hn", (unsigned short*)0); // no-warning138 printf("%hn", (int*)0); // expected-warning{{format specifies type 'short *' but the argument has type 'int *'}}139 140 printf("%n", (int*)0); // no-warning141 printf("%n", (unsigned int*)0); // no-warning142 printf("%n", (char*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}}143 144 printf("%ln", (long*)0); // no-warning145 printf("%ln", (unsigned long*)0); // no-warning146 printf("%ln", (int*)0); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}147 148 printf("%lln", (long long*)0); // no-warning149 printf("%lln", (unsigned long long*)0); // no-warning150 printf("%lln", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}151 152 printf("%qn", (long long*)0); // no-warning153 printf("%qn", (unsigned long long*)0); // no-warning154 printf("%qn", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}155 156 printf("%Ln", 0); // expected-warning{{length modifier 'L' results in undefined behavior or no effect with 'n' conversion specifier}}157 // expected-note@-1{{did you mean to use 'll'?}}158}159 160#else161 162void check_writeback_specifier(void)163{164 int x;165 printf("%n", &x); // expected-warning{{'%n' specifier not supported on this platform}}166 167 printf("%hhn", (signed char*)0); // expected-warning{{'%n' specifier not supported on this platform}}168 printf("%hhn", (char*)0); // expected-warning{{'%n' specifier not supported on this platform}}169 printf("%hhn", (unsigned char*)0); // expected-warning{{'%n' specifier not supported on this platform}}170 printf("%hhn", (int*)0); // expected-warning{{format specifies type 'signed char *' but the argument has type 'int *'}}171 // expected-warning@-1 {{'%n' specifier not supported on this platform}}172 173 printf("%hn", (short*)0); // expected-warning{{'%n' specifier not supported on this platform}}174 printf("%hn", (unsigned short*)0); // expected-warning{{'%n' specifier not supported on this platform}}175 printf("%hn", (int*)0); // expected-warning{{format specifies type 'short *' but the argument has type 'int *'}}176 // expected-warning@-1 {{'%n' specifier not supported on this platform}}177 178 printf("%n", (int*)0); // expected-warning{{'%n' specifier not supported on this platform}}179 printf("%n", (unsigned int*)0); // expected-warning{{'%n' specifier not supported on this platform}}180 printf("%n", (char*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}}181 // expected-warning@-1 {{'%n' specifier not supported on this platform}}182 183 printf("%ln", (long*)0); // expected-warning{{'%n' specifier not supported on this platform}}184 printf("%ln", (unsigned long*)0); // expected-warning{{'%n' specifier not supported on this platform}}185 printf("%ln", (int*)0); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}186 // expected-warning@-1 {{'%n' specifier not supported on this platform}}187 188 printf("%lln", (long long*)0); // expected-warning{{'%n' specifier not supported on this platform}}189 printf("%lln", (unsigned long long*)0); // expected-warning{{'%n' specifier not supported on this platform}}190 printf("%lln", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}191 // expected-warning@-1 {{'%n' specifier not supported on this platform}}192 193 printf("%qn", (long long*)0); // expected-warning{{'%n' specifier not supported on this platform}}194 printf("%qn", (unsigned long long*)0); // expected-warning{{'%n' specifier not supported on this platform}}195}196 197#endif // !defined(__ANDROID__) && !defined(__Fuchsia__)198 199void check_invalid_specifier(FILE* fp, char *buf)200{201 printf("%s%lv%d","unix",10,20); // expected-warning {{invalid conversion specifier 'v'}} expected-warning {{data argument not used by format string}}202 fprintf(fp,"%%%l"); // expected-warning {{incomplete format specifier}}203 sprintf(buf,"%%%%%ld%d%d", 1, 2, 3); // expected-warning{{format specifies type 'long' but the argument has type 'int'}}204 snprintf(buf, 2, "%%%%%ld%;%d", 1, 2, 3); // expected-warning{{format specifies type 'long' but the argument has type 'int'}} expected-warning {{invalid conversion specifier ';'}} expected-warning {{data argument not used by format string}} \205 // expected-warning{{'snprintf' will always be truncated; specified size is 2, but format string expands to at least 7}}206}207 208void check_null_char_string(char* b)209{210 printf("\0this is bogus%d",1); // expected-warning {{string contains '\0'}}211 snprintf(b,10,"%%%%%d\0%d",1,2); // expected-warning {{string contains '\0'}}212 printf("%\0d",1); // expected-warning {{string contains '\0'}}213}214 215void check_empty_format_string(char* buf, ...)216{217 va_list ap;218 va_start(ap,buf);219 vprintf("",ap); // expected-warning {{format string is empty}}220 sprintf(buf, "", 1); // expected-warning {{format string is empty}}221 222 // Don't warn about empty format strings when there are no data arguments.223 // This can arise from macro expansions and non-standard format string224 // functions.225 sprintf(buf, ""); // no-warning226}227 228void check_wide_string(char* b, ...)229{230 va_list ap;231 va_start(ap,b);232 233 printf(L"foo %d",2); // expected-error {{incompatible pointer types}}, expected-warning {{should not be a wide string}}234 vsprintf(b,L"bar %d",ap); // expected-error {{incompatible pointer types}}, expected-warning {{should not be a wide string}}235}236 237void check_asterisk_precision_width(int x) {238 printf("%*d"); // expected-warning {{'*' specified field width is missing a matching 'int' argument}}239 printf("%.*d"); // expected-warning {{'.*' specified field precision is missing a matching 'int' argument}}240 printf("%*d",12,x); // no-warning241 printf("%*d","foo",x); // expected-warning {{field width should have type 'int', but argument has type 'char *'}}242 printf("%.*d","foo",x); // expected-warning {{field precision should have type 'int', but argument has type 'char *'}}243}244 245void __attribute__((format(printf,1,3))) myprintf(const char*, int blah, ...);246 247void test_myprintf(void) {248 myprintf("%d", 17, 18); // okay249}250 251void test_constant_bindings(void) {252 const char * const s1 = "hello";253 const char s2[] = "hello";254 const char *s3 = "hello";255 char * const s4 = "hello";256 extern const char s5[];257 258 printf(s1); // no-warning259 printf(s2); // no-warning260 printf(s3); // expected-warning{{not a string literal}}261 // expected-note@-1{{treat the string as an argument to avoid this}}262 printf(s4); // expected-warning{{not a string literal}}263 // expected-note@-1{{treat the string as an argument to avoid this}}264 printf(s5); // expected-warning{{not a string literal}}265 // expected-note@-1{{treat the string as an argument to avoid this}}266}267 268 269// Test what happens when -Wformat-security only.270#pragma GCC diagnostic ignored "-Wformat-nonliteral"271#pragma GCC diagnostic warning "-Wformat-security"272 273void test9(char *P) {274 int x;275 printf(P); // expected-warning {{format string is not a string literal (potentially insecure)}}276 // expected-note@-1{{treat the string as an argument to avoid this}}277 printf(P, 42);278}279 280void torture(va_list v8) {281 vprintf ("%*.*d", v8); // no-warning282 283}284 285void test10(int x, float f, int i, long long lli) {286 printf("%s"); // expected-warning{{more '%' conversions than data arguments}}287 printf("%@", 12); // expected-warning{{invalid conversion specifier '@'}}288 printf("\0"); // expected-warning{{format string contains '\0' within the string body}}289 printf("xs\0"); // expected-warning{{format string contains '\0' within the string body}}290 printf("%*d\n"); // expected-warning{{'*' specified field width is missing a matching 'int' argument}}291 printf("%*.*d\n", x); // expected-warning{{'.*' specified field precision is missing a matching 'int' argument}}292 printf("%*d\n", f, x); // expected-warning{{field width should have type 'int', but argument has type 'double'}}293 printf("%*.*d\n", x, f, x); // expected-warning{{field precision should have type 'int', but argument has type 'double'}}294 printf("%**\n"); // expected-warning{{invalid conversion specifier '*'}}295 printf("%d%d\n", x); // expected-warning{{more '%' conversions than data arguments}}296 printf("%d\n", x, x); // expected-warning{{data argument not used by format string}}297 printf("%W%d\n", x, x); // expected-warning{{invalid conversion specifier 'W'}} expected-warning {{data argument not used by format string}}298 printf("%"); // expected-warning{{incomplete format specifier}}299 printf("%.d", x); // no-warning300 printf("%.", x); // expected-warning{{incomplete format specifier}}301 printf("%f", 4); // expected-warning{{format specifies type 'double' but the argument has type 'int'}}302 printf("%qd", lli); // no-warning303 printf("%qd", x); // expected-warning{{format specifies type 'long long' but the argument has type 'int'}}304 printf("%qp", (void *)0); // expected-warning{{length modifier 'q' results in undefined behavior or no effect with 'p' conversion specifier}}305 printf("hhX %hhX", (unsigned char)10); // no-warning306 printf("llX %llX", (long long) 10); // no-warning307 printf("%lb %lB", (long) 10, (long) 10); // no-warning308 printf("%llb %llB", (long long) 10, (long long) 10); // no-warning309 // This is fine, because there is an implicit conversion to an int.310 printf("%d", (unsigned char) 10); // no-warning311 printf("%d", (long long) 10); // expected-warning{{format specifies type 'int' but the argument has type 'long long'}}312 printf("%Lf\n", (long double) 1.0); // no-warning313 printf("%f\n", (long double) 1.0); // expected-warning{{format specifies type 'double' but the argument has type 'long double'}}314 // The man page says that a zero precision is okay.315 printf("%.0Lf", (long double) 1.0); // no-warning316 printf("%c\n", "x"); // expected-warning{{format specifies type 'int' but the argument has type 'char *'}}317 printf("%c\n", 1.23); // expected-warning{{format specifies type 'int' but the argument has type 'double'}}318 printf("Format %d, is %! %f", 1, 4.4); // expected-warning{{invalid conversion specifier '!'}}319}320 321typedef unsigned char uint8_t;322 323void should_understand_small_integers(void) {324 printf("%hhu", (short) 10); // expected-warning{{format specifies type 'unsigned char' but the argument has type 'short'}}325 printf("%hu\n", (unsigned char)1); // warning with -Wformat-pedantic only326 printf("%hu\n", (uint8_t)1); // warning with -Wformat-pedantic only327}328 329void test11(void *p, char *s) {330 printf("%p", p); // no-warning331 printf("%p", 123); // expected-warning{{format specifies type 'void *' but the argument has type 'int'}}332 printf("%.4p", p); // expected-warning{{precision used with 'p' conversion specifier, resulting in undefined behavior}}333 printf("%+p", p); // expected-warning{{flag '+' results in undefined behavior with 'p' conversion specifier}}334 printf("% p", p); // expected-warning{{flag ' ' results in undefined behavior with 'p' conversion specifier}}335 printf("%0p", p); // expected-warning{{flag '0' results in undefined behavior with 'p' conversion specifier}}336 printf("%s", s); // no-warning337 printf("%+s", p); // expected-warning{{flag '+' results in undefined behavior with 's' conversion specifier}}338 // expected-warning@-1 {{format specifies type 'char *' but the argument has type 'void *'}}339 printf("% s", p); // expected-warning{{flag ' ' results in undefined behavior with 's' conversion specifier}}340 // expected-warning@-1 {{format specifies type 'char *' but the argument has type 'void *'}}341 printf("%0s", p); // expected-warning{{flag '0' results in undefined behavior with 's' conversion specifier}}342 // expected-warning@-1 {{format specifies type 'char *' but the argument has type 'void *'}}343}344 345void test12(char *b) {346 unsigned char buf[4];347 printf ("%.4s\n", buf); // no-warning348 printf ("%.4s\n", &buf); // expected-warning{{format specifies type 'char *' but the argument has type 'unsigned char (*)[4]'}}349 350 // Verify that we are checking asprintf351 asprintf(&b, "%d", "asprintf"); // expected-warning{{format specifies type 'int' but the argument has type 'char *'}}352}353 354void test13(short x) {355 char bel = 007;356 printf("bel: '0%hhd'\n", bel); // no-warning357 printf("x: '0%hhd'\n", x); // expected-warning {{format specifies type 'char' but the argument has type 'short'}}358}359 360typedef struct __aslclient *aslclient;361typedef struct __aslmsg *aslmsg;362int asl_log(aslclient asl, aslmsg msg, int level, const char *format, ...) __attribute__((__format__ (__printf__, 4, 5)));363void test_asl(aslclient asl) {364 asl_log(asl, 0, 3, "Error: %m"); // no-warning365 asl_log(asl, 0, 3, "Error: %W"); // expected-warning{{invalid conversion specifier 'W'}}366}367 368typedef enum { A } int_t;369void f0(int_t x) { printf("%d\n", x); }370 371// Unicode test cases. These are possibly specific to Mac OS X. If so, they should372// eventually be moved into a separate test.373 374void test_unicode_conversions(wchar_t *s) {375 printf("%S", s); // no-warning376 printf("%s", s); // expected-warning{{format specifies type 'char *' but the argument has type 'wchar_t *'}}377 printf("%C", s[0]); // no-warning378#if defined(__sun) && !defined(__LP64__)379 printf("%c", s[0]); // expected-warning{{format specifies type 'int' but the argument has type 'wchar_t' (aka 'long')}}380#else381 printf("%c", s[0]);382#endif383 // FIXME: This test reports inconsistent results. On Windows, '%C' expects384 // 'unsigned short'.385 // printf("%C", 10);386 printf("%S", "hello"); // expected-warning{{but the argument has type 'char *'}}387}388 389// Mac OS X supports positional arguments in format strings.390// This is an IEEE extension (IEEE Std 1003.1).391// FIXME: This is probably not portable everywhere.392void test_positional_arguments(void) {393 printf("%0$", (int)2); // expected-warning{{position arguments in format strings start counting at 1 (not 0)}}394 printf("%1$*0$d", (int) 2); // expected-warning{{position arguments in format strings start counting at 1 (not 0)}}395 printf("%1$d", (int) 2); // no-warning396 printf("%1$d", (int) 2, 2); // expected-warning{{data argument not used by format string}}397 printf("%1$d%1$f", (int) 2); // expected-warning{{format specifies type 'double' but the argument has type 'int'}}398 printf("%1$2.2d", (int) 2); // no-warning399 printf("%2$*1$.2d", (int) 2, (int) 3); // no-warning400 printf("%2$*8$d", (int) 2, (int) 3); // expected-warning{{specified field width is missing a matching 'int' argument}}401 printf("%%%1$d", (int) 2); // no-warning402 printf("%1$d%%", (int) 2); // no-warning403}404 405// PR 6697 - Handle format strings where the data argument is not adjacent to the format string406void myprintf_PR_6697(const char *format, int x, ...) __attribute__((__format__(printf,1, 3)));407void test_pr_6697(void) {408 myprintf_PR_6697("%s\n", 1, "foo"); // no-warning409 myprintf_PR_6697("%s\n", 1, (int)0); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}410 // FIXME: Not everything should clearly support positional arguments,411 // but we need a way to identify those cases.412 myprintf_PR_6697("%1$s\n", 1, "foo"); // no-warning413 myprintf_PR_6697("%2$s\n", 1, "foo"); // expected-warning{{data argument position '2' exceeds the number of data arguments (1)}}414 myprintf_PR_6697("%18$s\n", 1, "foo"); // expected-warning{{data argument position '18' exceeds the number of data arguments (1)}}415 myprintf_PR_6697("%1$s\n", 1, (int) 0); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}416}417 418void rdar8026030(FILE *fp) {419 fprintf(fp, "\%"); // expected-warning{{incomplete format specifier}}420}421 422void bug7377_bad_length_mod_usage(void) {423 // Bad length modifiers424 printf("%hhs", "foo"); // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 's' conversion specifier}}425 printf("%1$zp", (void *)0); // expected-warning{{length modifier 'z' results in undefined behavior or no effect with 'p' conversion specifier}}426 printf("%ls", L"foo"); // no-warning427 printf("%#.2Lf", (long double)1.234); // no-warning428 429 // Bad flag usage430 printf("%#p", (void *) 0); // expected-warning{{flag '#' results in undefined behavior with 'p' conversion specifier}}431 printf("%0d", -1); // no-warning432 printf("%0b%0B", -1u, -1u); // no-warning433 printf("%-p", (void *) 0); // no-warning434#if !defined(__ANDROID__) && !defined(__Fuchsia__)435 printf("%#n", (int *) 0); // expected-warning{{flag '#' results in undefined behavior with 'n' conversion specifier}}436 printf("%-n", (int *) 0); // expected-warning{{flag '-' results in undefined behavior with 'n' conversion specifier}}437#else438 printf("%#n", (int *) 0); // expected-warning{{flag '#' results in undefined behavior with 'n' conversion specifier}}439 // expected-warning@-1 {{'%n' specifier not supported on this platform}}440 printf("%-n", (int *) 0); // expected-warning{{flag '-' results in undefined behavior with 'n' conversion specifier}}441 // expected-warning@-1 {{'%n' specifier not supported on this platform}}442#endif // !defined(__ANDROID__) && !defined(__Fuchsia__)443 444 // Bad optional amount use445 printf("%.2c", 'a'); // expected-warning{{precision used with 'c' conversion specifier, resulting in undefined behavior}}446#if !defined(__ANDROID__) && !defined(__Fuchsia__)447 printf("%1n", (int *) 0); // expected-warning{{field width used with 'n' conversion specifier, resulting in undefined behavior}}448 printf("%.9n", (int *) 0); // expected-warning{{precision used with 'n' conversion specifier, resulting in undefined behavior}}449#else450 printf("%1n", (int *) 0); // expected-warning{{field width used with 'n' conversion specifier, resulting in undefined behavior}}451 // expected-warning@-1 {{'%n' specifier not supported on this platform}}452 printf("%.9n", (int *) 0); // expected-warning{{precision used with 'n' conversion specifier, resulting in undefined behavior}}453 // expected-warning@-1 {{'%n' specifier not supported on this platform}}454#endif // #if !defined(__ANDROID__) && !defined(__Fuchsia__)455 456 // Ignored flags457 printf("% +f", 1.23); // expected-warning{{flag ' ' is ignored when flag '+' is present}}458 printf("%+ f", 1.23); // expected-warning{{flag ' ' is ignored when flag '+' is present}}459 printf("%0-f", 1.23); // expected-warning{{flag '0' is ignored when flag '-' is present}}460 printf("%-0f", 1.23); // expected-warning{{flag '0' is ignored when flag '-' is present}}461 printf("%-+f", 1.23); // no-warning462}463 464// PR 7981 - handle '%lc' (wint_t)465 466void pr7981(wint_t c, wchar_t c2) {467 printf("%lc", c); // no-warning468 printf("%lc", 1.0); // expected-warning{{the argument has type 'double'}}469#if __WINT_WIDTH__ == 32 && !(defined(__sun) && !defined(__LP64__))470 printf("%lc", (char) 1); // no-warning471#else472 printf("%lc", (char) 1); // expected-warning{{the argument has type 'char'}}473#endif474 printf("%lc", &c); // expected-warning{{the argument has type 'wint_t *'}}475 // If wint_t and wchar_t are the same width and wint_t is signed where476 // wchar_t is unsigned, an implicit conversion isn't possible.477#if defined(__WINT_UNSIGNED__) || !defined(__WCHAR_UNSIGNED__) || \478 __WINT_WIDTH__ > __WCHAR_WIDTH__479 printf("%lc", c2); // no-warning480#endif481}482 483// -Wformat-security says NULL is not a string literal484void rdar8269537(void) {485 // This is likely to crash in most cases, but -Wformat-nonliteral technically486 // doesn't warn in this case.487 printf(0); // no-warning488}489 490// Handle functions with multiple format attributes.491extern void rdar8332221_vprintf_scanf(const char *, va_list, const char *, ...)492 __attribute__((__format__(__printf__, 1, 0)))493 __attribute__((__format__(__scanf__, 3, 4)));494 495void rdar8332221(va_list ap, int *x, long *y) {496 rdar8332221_vprintf_scanf("%", ap, "%d", x); // expected-warning{{incomplete format specifier}}497}498 499void rdar8332221_vprintf_scanf(const char *p, va_list ap, const char *s, ...) {500 vprintf(p, ap);501 502 va_list vs;503 va_start(vs, s);504 vscanf(s, vs);505 va_end(vs);506}507 508__attribute__((__format__(__printf__, 1, 0)))509__attribute__((__format__(__scanf__, 3, 4)))510void vprintf_scanf_bad(const char *p, va_list ap, const char *s, ...) {511 vscanf(p, ap); // expected-warning{{passing 'printf' format string where 'scanf' format string is expected}}512 513 va_list vs;514 va_start(vs, s);515 vprintf(s, vs); // expected-warning{{passing 'scanf' format string where 'printf' format string is expected}}516 va_end(vs);517}518 519// PR8641520void pr8641(void) {521 printf("%#x\n", 10);522 printf("%#X\n", 10);523 printf("%#b %#15.8B\n", 10, 10u);524}525 526void posix_extensions(void) {527 // Test %'d, "thousands grouping".528 printf("%'d\n", 123456789); // no-warning529 printf("%'i\n", 123456789); // no-warning530 printf("%'f\n", (float) 1.0); // no-warning531 printf("%'p\n", (void*) 0); // expected-warning{{results in undefined behavior with 'p' conversion specifier}}532 printf("%'b\n", 123456789); // expected-warning{{results in undefined behavior with 'b' conversion specifier}}533 printf("%'B\n", 123456789); // expected-warning{{results in undefined behavior with 'B' conversion specifier}}534}535 536// PR8486537//538// Test what happens when -Wformat is on, but -Wformat-security is off.539#pragma GCC diagnostic warning "-Wformat"540#pragma GCC diagnostic ignored "-Wformat-security"541 542void pr8486(void) {543 printf("%s", 1); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}544}545 546// PR9314547// Don't warn about string literals that are PreDefinedExprs, e.g. __func__.548void pr9314(void) {549 printf(__PRETTY_FUNCTION__); // no-warning550 printf(__func__); // no-warning551}552 553int printf(const char * restrict, ...) __attribute__((__format__ (__printf__, 1, 2)));554 555void rdar9612060(void) {556 printf("%s", 2); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}557}558 559void check_char(unsigned char x, signed char y) {560 printf("%c", y); // no-warning561 printf("%hhu", x); // no-warning562 printf("%hhi", y); // no-warning563 printf("%hhi", x); // no-warning564 printf("%c", x); // no-warning565 printf("%hhu", y); // no-warning566 printf("%hhb %hhB", x, x); // no-warning567}568 569// Test suppression of individual warnings.570 571void test_suppress_invalid_specifier(void) {572#pragma clang diagnostic push573#pragma clang diagnostic ignored "-Wformat-invalid-specifier"574 printf("%@", 12); // no-warning575#pragma clang diagnostic pop576}577 578// Make sure warnings are on for next test.579#pragma GCC diagnostic warning "-Wformat"580#pragma GCC diagnostic warning "-Wformat-security"581 582// Test that the printf call site is where the warning is attached. If the583// format string is somewhere else, point to it in a note.584void pr9751(void) {585 const char kFormat1[] = "%d %d \n"; // expected-note{{format string is defined here}}}586 printf(kFormat1, 0); // expected-warning{{more '%' conversions than data arguments}}587 printf("%d %s\n", 0); // expected-warning{{more '%' conversions than data arguments}}588 589 const char kFormat2[] = "%18$s\n"; // expected-note{{format string is defined here}}590 printf(kFormat2, 1, "foo"); // expected-warning{{data argument position '18' exceeds the number of data arguments (2)}}591 printf("%18$s\n", 1, "foo"); // expected-warning{{data argument position '18' exceeds the number of data arguments (2)}}592 593 const char kFormat4[] = "%y"; // expected-note{{format string is defined here}}594 printf(kFormat4, 5); // expected-warning{{invalid conversion specifier 'y'}}595 printf("%y", 5); // expected-warning{{invalid conversion specifier 'y'}}596 597 const char kFormat5[] = "%."; // expected-note{{format string is defined here}}598 printf(kFormat5, 5); // expected-warning{{incomplete format specifier}}599 printf("%.", 5); // expected-warning{{incomplete format specifier}}600 601 const char kFormat6[] = "%s"; // expected-note{{format string is defined here}}602 printf(kFormat6, 5); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}603 printf("%s", 5); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}604 605 const char kFormat7[] = "%0$"; // expected-note{{format string is defined here}}606 printf(kFormat7, 5); // expected-warning{{position arguments in format strings start counting at 1 (not 0)}}607 printf("%0$", 5); // expected-warning{{position arguments in format strings start counting at 1 (not 0)}}608 609 const char kFormat8[] = "%1$d %d"; // expected-note{{format string is defined here}}610 printf(kFormat8, 4, 4); // expected-warning{{cannot mix positional and non-positional arguments in format string}}611 printf("%1$d %d", 4, 4); // expected-warning{{cannot mix positional and non-positional arguments in format string}}612 613 const char kFormat9[] = ""; // expected-note{{format string is defined here}}614 printf(kFormat9, 4, 4); // expected-warning{{format string is empty}}615 printf("", 4, 4); // expected-warning{{format string is empty}}616 617 const char kFormat10[] = "\0%d"; // expected-note{{format string is defined here}}618 printf(kFormat10, 4); // expected-warning{{format string contains '\0' within the string body}}619 printf("\0%d", 4); // expected-warning{{format string contains '\0' within the string body}}620 621 const char kFormat11[] = "%*d"; // expected-note{{format string is defined here}}622 printf(kFormat11); // expected-warning{{'*' specified field width is missing a matching 'int' argument}}623 printf("%*d"); // expected-warning{{'*' specified field width is missing a matching 'int' argument}}624 625 const char kFormat12[] = "%*d"; // expected-note{{format string is defined here}}626 printf(kFormat12, 4.4); // expected-warning{{field width should have type 'int', but argument has type 'double'}}627 printf("%*d", 4.4); // expected-warning{{field width should have type 'int', but argument has type 'double'}}628 629 const char kFormat13[] = "%.3p"; // expected-note{{format string is defined here}}630 void *p;631 printf(kFormat13, p); // expected-warning{{precision used with 'p' conversion specifier, resulting in undefined behavior}}632 printf("%.3p", p); // expected-warning{{precision used with 'p' conversion specifier, resulting in undefined behavior}}633 634 const char kFormat14[] = "%0s"; // expected-note{{format string is defined here}}635 printf(kFormat14, "a"); // expected-warning{{flag '0' results in undefined behavior with 's' conversion specifier}}636 printf("%0s", "a"); // expected-warning{{flag '0' results in undefined behavior with 's' conversion specifier}}637 638 const char kFormat15[] = "%hhs"; // expected-note{{format string is defined here}}639 printf(kFormat15, "a"); // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 's' conversion specifier}}640 printf("%hhs", "a"); // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 's' conversion specifier}}641 642 const char kFormat16[] = "%-0d"; // expected-note{{format string is defined here}}643 printf(kFormat16, 5); // expected-warning{{flag '0' is ignored when flag '-' is present}}644 printf("%-0d", 5); // expected-warning{{flag '0' is ignored when flag '-' is present}}645 646 // Make sure that the "format string is defined here" note is not emitted647 // when the original string is within the argument expression.648 printf(1 ? "yes %d" : "no %d"); // expected-warning{{more '%' conversions than data arguments}}649 650 const char kFormat17[] = "%hu"; // expected-note{{format string is defined here}}}651 printf(kFormat17, (int[]){0}); // expected-warning{{format specifies type 'unsigned short' but the argument}}652 653 printf("%a", (long double)0); // expected-warning{{format specifies type 'double' but the argument has type 'long double'}}654 655 // Test braced char[] initializers.656 const char kFormat18[] = { "%lld" }; // expected-note{{format string is defined here}}657 printf(kFormat18, 0); // expected-warning{{format specifies type}}658 659 // Make sure we point at the offending argument rather than the format string.660 const char kFormat19[] = "%d"; // expected-note{{format string is defined here}}661 printf(kFormat19,662 0.0); // expected-warning{{format specifies}}663}664 665void pr18905(void) {666 const char s1[] = "s\0%s"; // expected-note{{format string is defined here}}667 const char s2[1] = "s"; // expected-note{{format string is defined here}}668 const char s3[2] = "s\0%s"; // expected-warning{{initializer-string for char array is too long}}669 const char s4[10] = "s";670 const char s5[0] = "%s"; // expected-warning{{initializer-string for char array is too long}}671 // expected-note@-1{{format string is defined here}}672 673 printf(s1); // expected-warning{{format string contains '\0' within the string body}}674 printf(s2); // expected-warning{{format string is not null-terminated}}675 printf(s3); // no-warning676 printf(s4); // no-warning677 printf(s5); // expected-warning{{format string is not null-terminated}}678}679 680void __attribute__((format(strfmon,1,2))) monformat(const char *fmt, ...);681void __attribute__((format(gnu_strfmon,1,2))) gnu_monformat(const char *fmt, ...);682void __attribute__((format(strftime,1,0))) dateformat(const char *fmt);683void __attribute__((format(gnu_strftime,1,0))) gnu_dateformat(const char *fmt);684 685// Other formats686void test_other_formats(void) {687 char *str = "";688 monformat("", 1); // expected-warning{{format string is empty}}689 monformat(str); // expected-warning{{format string is not a string literal (potentially insecure)}}690 gnu_monformat("", 1); // expected-warning{{format string is empty}}691 gnu_monformat(str); // expected-warning{{format string is not a string literal (potentially insecure)}}692 dateformat(""); // expected-warning{{format string is empty}}693 dateformat(str); // no-warning (using strftime non-literal is not unsafe)694 gnu_dateformat(""); // expected-warning{{format string is empty}}695 gnu_dateformat(str); // no-warning (using strftime non-literal is not unsafe)696}697 698// Do not warn about unused arguments coming from system headers.699#include <format-unused-system-args.h>700void test_unused_system_args(int x) {701 PRINT1("%d\n", x); // no-warning{{extra argument is system header is OK}}702}703 704void pr12761(char c) {705 // This should not warn even with -fno-signed-char.706 printf("%hhx", c);707}708 709void test_opencl_vector_format(int x) {710 printf("%v4d", x); // expected-warning{{invalid conversion specifier 'v'}}711 printf("%vd", x); // expected-warning{{invalid conversion specifier 'v'}}712 printf("%0vd", x); // expected-warning{{invalid conversion specifier 'v'}}713 printf("%hlf", x); // expected-warning{{invalid conversion specifier 'l'}}714 printf("%hld", x); // expected-warning{{invalid conversion specifier 'l'}}715}716 717// Test that we correctly merge the format in both orders.718extern void test14_foo(const char *, const char *, ...)719 __attribute__((__format__(__printf__, 1, 3)));720extern void test14_foo(const char *, const char *, ...)721 __attribute__((__format__(__scanf__, 2, 3)));722 723extern void test14_bar(const char *, const char *, ...)724 __attribute__((__format__(__scanf__, 2, 3)));725extern void test14_bar(const char *, const char *, ...)726 __attribute__((__format__(__printf__, 1, 3)));727 728void test14_zed(int *p) {729 test14_foo("%", "%d", p); // expected-warning{{incomplete format specifier}}730 test14_bar("%", "%d", p); // expected-warning{{incomplete format specifier}}731}732 733#if !defined(__ANDROID__) && !defined(__Fuchsia__)734 735void test_qualifiers(volatile int *vip, const int *cip,736 const volatile int *cvip) {737 printf("%n", cip); // expected-warning{{format specifies type 'int *' but the argument has type 'const int *'}}738 printf("%n", cvip); // expected-warning{{format specifies type 'int *' but the argument has type 'const volatile int *'}}739 740 printf("%n", vip); // No warning.741 printf("%p", cip); // No warning.742 printf("%p", cvip); // No warning.743 744 745 typedef int* ip_t;746 typedef const int* cip_t;747 printf("%n", (ip_t)0); // No warning.748 printf("%n", (cip_t)0); // expected-warning{{format specifies type 'int *' but the argument has type 'cip_t' (aka 'const int *')}}749}750 751#else752 753void test_qualifiers(volatile int *vip, const int *cip,754 const volatile int *cvip) {755 printf("%n", cip); // expected-warning{{format specifies type 'int *' but the argument has type 'const int *'}}756 // expected-warning@-1 {{'%n' specifier not supported on this platform}}757 printf("%n", cvip); // expected-warning{{format specifies type 'int *' but the argument has type 'const volatile int *'}}758 // expected-warning@-1 {{'%n' specifier not supported on this platform}}759 760 printf("%n", vip); // expected-warning{{'%n' specifier not supported on this platform}}761 printf("%p", cip); // No warning.762 printf("%p", cvip); // No warning.763 764 765 typedef int* ip_t;766 typedef const int* cip_t;767 printf("%n", (ip_t)0); // expected-warning{{'%n' specifier not supported on this platform}}768 printf("%n", (cip_t)0); // expected-warning{{format specifies type 'int *' but the argument has type 'cip_t' (aka 'const int *')}}769 // expected-warning@-1 {{'%n' specifier not supported on this platform}}770}771 772#endif // #if !defined(__ANDROID__) && !defined(__Fuchsia__)773 774#pragma GCC diagnostic ignored "-Wformat-nonliteral"775#pragma GCC diagnostic warning "-Wformat-security"776extern void test_format_security_extra_args(const char*, int, ...)777 __attribute__((__format__(__printf__, 1, 3)));778void test_format_security_pos(char* string) {779 test_format_security_extra_args(string, 5); // expected-warning {{format string is not a string literal (potentially insecure)}}780 // expected-note@-1{{treat the string as an argument to avoid this}}781}782#pragma GCC diagnostic warning "-Wformat-nonliteral"783 784void test_char_pointer_arithmetic(int b) {785 const char s1[] = "string";786 const char s2[] = "%s string";787 788 printf(s1 - 1); // expected-warning {{format string is not a string literal (potentially insecure)}}789 // expected-note@-1{{treat the string as an argument to avoid this}}790 791 printf(s1 + 2); // no-warning792 printf(s2 + 2); // no-warning793 794 const char s3[] = "%s string";795 printf((s3 + 2) - 2); // expected-warning{{more '%' conversions than data arguments}}796 // expected-note@-2{{format string is defined here}}797 printf(2 + s2); // no-warning798 printf(6 + s2 - 2); // no-warning799 printf(2 + (b ? s1 : s2)); // no-warning800 801 const char s5[] = "string %s";802 printf(2 + (b ? s2 : s5)); // expected-warning{{more '%' conversions than data arguments}}803 // expected-note@-2{{format string is defined here}}804 printf(2 + (b ? s2 : s5), ""); // no-warning805 printf(2 + (b ? s1 : s2 - 2), ""); // no-warning806 807 const char s6[] = "%s string";808 printf(2 + (b ? s1 : s6 - 2)); // expected-warning{{more '%' conversions than data arguments}}809 // expected-note@-2{{format string is defined here}}810 printf(1 ? s2 + 2 : s2); // no-warning811 printf(0 ? s2 : s2 + 2); // no-warning812 printf(2 + s2 + 5 * 3 - 16, ""); // expected-warning{{data argument not used}}813 814 const char s7[] = "%s string %s %s";815 printf(s7 + 3, ""); // expected-warning{{more '%' conversions than data arguments}}816 // expected-note@-2{{format string is defined here}}817}818 819void PR30481(void) {820 // This caused crashes due to invalid casts.821 printf(1 > 0); // expected-warning{{format string is not a string literal}} expected-error{{incompatible integer to pointer conversion}} expected-note@format-strings.c:*{{passing argument to parameter here}} expected-note{{to avoid this}}822}823 824void test_printf_opaque_ptr(void *op) {825 printf("%s", op); // expected-warning{{format specifies type 'char *' but the argument has type 'void *'}}826}827 828void test_block(void) {829 void __attribute__((__format__(__printf__, 1, 2))) (^printf_arg1)(830 const char *, ...) =831 ^(const char *fmt, ...) __attribute__((__format__(__printf__, 1, 2))) {832 va_list ap;833 va_start(ap, fmt);834 vprintf(fmt, ap);835 va_end(ap);836 };837 838 printf_arg1("%s string %i\n", "aaa", 123);839 printf_arg1("%s string\n", 123); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}840 841 void __attribute__((__format__(__printf__, 2, 3))) (^printf_arg2)(842 const char *, const char *, ...) =843 ^(const char *not_fmt, const char *fmt, ...)844 __attribute__((__format__(__printf__, 2, 3))) {845 va_list ap;846 va_start(ap, fmt);847 vprintf(fmt, ap);848 vprintf(not_fmt, ap); // expected-warning{{format string is not a string literal}}849 va_end(ap);850 };851 852 printf_arg2("foo", "%s string %i\n", "aaa", 123);853 printf_arg2("%s string\n", "foo", "bar"); // expected-warning{{data argument not used by format string}}854}855 856void test_promotion(void) {857 // Default argument promotions for *printf in N2562858 // https://github.com/llvm/llvm-project/issues/57102859 // N2562: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2562.pdf860 int i;861 signed char sc;862 unsigned char uc;863 char c;864 short ss;865 unsigned short us;866 867 printf("%hhd %hd %d %hhd %hd %d", i, i, i, sc, sc, sc); // no-warning868 printf("%hhd %hd %d %hhd %hd %d", uc, uc, uc, c, c, c); // no-warning869 870 // %ld %lld %llx871 printf("%ld", i); // expected-warning{{format specifies type 'long' but the argument has type 'int'}}872 printf("%lld", i); // expected-warning{{format specifies type 'long long' but the argument has type 'int'}}873 printf("%ld", sc); // expected-warning{{format specifies type 'long' but the argument has type 'signed char'}}874 printf("%lld", sc); // expected-warning{{format specifies type 'long long' but the argument has type 'signed char'}}875 printf("%ld", uc); // expected-warning{{format specifies type 'long' but the argument has type 'unsigned char'}}876 printf("%lld", uc); // expected-warning{{format specifies type 'long long' but the argument has type 'unsigned char'}}877 printf("%llx", i); // expected-warning{{format specifies type 'unsigned long long' but the argument has type 'int'}}878 879 // ill formed spec for floats880 printf("%hf", // expected-warning{{length modifier 'h' results in undefined behavior or no effect with 'f' conversion specifier}}881 sc); // expected-warning{{format specifies type 'double' but the argument has type 'signed char'}}882 883 // for %hhd and `short` they are compatible by promotions but more likely misuse884 printf("%hd", ss); // no-warning885 printf("%hhd", ss); // expected-warning{{format specifies type 'char' but the argument has type 'short'}}886 printf("%hu", us); // no-warning887 printf("%hhu", ss); // expected-warning{{format specifies type 'unsigned char' but the argument has type 'short'}}888 889 // floats & integers are not compatible890 printf("%f", i); // expected-warning{{format specifies type 'double' but the argument has type 'int'}}891 printf("%f", sc); // expected-warning{{format specifies type 'double' but the argument has type 'signed char'}}892 printf("%f", uc); // expected-warning{{format specifies type 'double' but the argument has type 'unsigned char'}}893 printf("%f", c); // expected-warning{{format specifies type 'double' but the argument has type 'char'}}894 printf("%f", ss); // expected-warning{{format specifies type 'double' but the argument has type 'short'}}895 printf("%f", us); // expected-warning{{format specifies type 'double' but the argument has type 'unsigned short'}}896 897 // character literals898 // In C language engineering practice, printing a character literal with %hhd or %d is common, but %hd may be misuse.899 printf("%hhu", 'a'); // no-warning900 printf("%hhd", 'a'); // no-warning901 printf("%hd", 'a'); // expected-warning{{format specifies type 'short' but the argument has type 'char'}}902 printf("%hu", 'a'); // expected-warning{{format specifies type 'unsigned short' but the argument has type 'char'}}903 printf("%d", 'a'); // no-warning904 printf("%u", 'a'); // no-warning905 906 // pointers907 printf("%s", i); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}908}909