diff options
Diffstat (limited to 'test/Sema/format-strings.c')
-rw-r--r-- | test/Sema/format-strings.c | 117 |
1 files changed, 97 insertions, 20 deletions
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c index 086c5c6..86b9296 100644 --- a/test/Sema/format-strings.c +++ b/test/Sema/format-strings.c @@ -1,7 +1,10 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs -fno-signed-char %s +#define __need_wint_t #include <stdarg.h> -typedef __typeof(sizeof(int)) size_t; +#include <stddef.h> // For wint_t and wchar_t + typedef struct _FILE FILE; int fprintf(FILE *, const char *restrict, ...); int printf(const char *restrict, ...); // expected-note{{passing argument to parameter here}} @@ -85,9 +88,35 @@ void check_writeback_specifier() { int x; char *b; + printf("%n", b); // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}} + printf("%n", &x); // no-warning + + printf("%hhn", (signed char*)0); // no-warning + printf("%hhn", (char*)0); // no-warning + printf("%hhn", (unsigned char*)0); // no-warning + printf("%hhn", (int*)0); // expected-warning{{format specifies type 'signed char *' but the argument has type 'int *'}} + + printf("%hn", (short*)0); // no-warning + printf("%hn", (unsigned short*)0); // no-warning + printf("%hn", (int*)0); // expected-warning{{format specifies type 'short *' but the argument has type 'int *'}} + + printf("%n", (int*)0); // no-warning + printf("%n", (unsigned int*)0); // no-warning + printf("%n", (char*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}} + + printf("%ln", (long*)0); // no-warning + printf("%ln", (unsigned long*)0); // no-warning + printf("%ln", (int*)0); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}} + + printf("%lln", (long long*)0); // no-warning + printf("%lln", (unsigned long long*)0); // no-warning + printf("%lln", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}} + + printf("%qn", (long long*)0); // no-warning + printf("%qn", (unsigned long long*)0); // no-warning + printf("%qn", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}} - printf("%n",&x); // expected-warning {{'%n' in format string discouraged}} - sprintf(b,"%d%%%n",1, &x); // expected-warning {{'%n' in format string dis}} + printf("%Ln", 0); // expected-warning{{length modifier 'L' results in undefined behavior or no effect with 'n' conversion specifier}} } void check_invalid_specifier(FILE* fp, char *buf) @@ -164,7 +193,6 @@ void test9(char *P) { int x; printf(P); // expected-warning {{format string is not a string literal (potentially insecure)}} printf(P, 42); - printf("%n", &x); // expected-warning {{use of '%n' in format string discouraged }} } void torture(va_list v8) { @@ -182,7 +210,6 @@ void test10(int x, float f, int i, long long lli) { printf("%*d\n", f, x); // expected-warning{{field width should have type 'int', but argument has type 'double'}} printf("%*.*d\n", x, f, x); // expected-warning{{field precision should have type 'int', but argument has type 'double'}} printf("%**\n"); // expected-warning{{invalid conversion specifier '*'}} - printf("%n", &i); // expected-warning{{use of '%n' in format string discouraged (potentially insecure)}} printf("%d%d\n", x); // expected-warning{{more '%' conversions than data arguments}} printf("%d\n", x, x); // expected-warning{{data argument not used by format string}} printf("%W%d%Z\n", x, x, x); // expected-warning{{invalid conversion specifier 'W'}} expected-warning{{invalid conversion specifier 'Z'}} @@ -258,7 +285,6 @@ void f0(int_t x) { printf("%d\n", x); } // Unicode test cases. These are possibly specific to Mac OS X. If so, they should // eventually be moved into a separate test. -typedef __WCHAR_TYPE__ wchar_t; void test_unicode_conversions(wchar_t *s) { printf("%S", s); // no-warning @@ -314,14 +340,14 @@ void bug7377_bad_length_mod_usage() { // Bad flag usage printf("%#p", (void *) 0); // expected-warning{{flag '#' results in undefined behavior with 'p' conversion specifier}} printf("%0d", -1); // no-warning - printf("%#n", (void *) 0); // expected-warning{{flag '#' results in undefined behavior with 'n' conversion specifier}} expected-warning{{use of '%n' in format string discouraged (potentially insecure)}} - printf("%-n", (void *) 0); // expected-warning{{flag '-' results in undefined behavior with 'n' conversion specifier}} expected-warning{{use of '%n' in format string discouraged (potentially insecure)}} + printf("%#n", (int *) 0); // expected-warning{{flag '#' results in undefined behavior with 'n' conversion specifier}} + printf("%-n", (int *) 0); // expected-warning{{flag '-' results in undefined behavior with 'n' conversion specifier}} printf("%-p", (void *) 0); // no-warning // Bad optional amount use printf("%.2c", 'a'); // expected-warning{{precision used with 'c' conversion specifier, resulting in undefined behavior}} - printf("%1n", (void *) 0); // expected-warning{{field width used with 'n' conversion specifier, resulting in undefined behavior}} expected-warning{{use of '%n' in format string discouraged (potentially insecure)}} - printf("%.9n", (void *) 0); // expected-warning{{precision used with 'n' conversion specifier, resulting in undefined behavior}} expected-warning{{use of '%n' in format string discouraged (potentially insecure)}} + printf("%1n", (int *) 0); // expected-warning{{field width used with 'n' conversion specifier, resulting in undefined behavior}} + printf("%.9n", (int *) 0); // expected-warning{{precision used with 'n' conversion specifier, resulting in undefined behavior}} // Ignored flags printf("% +f", 1.23); // expected-warning{{flag ' ' is ignored when flag '+' is present}} @@ -332,17 +358,18 @@ void bug7377_bad_length_mod_usage() { } // PR 7981 - handle '%lc' (wint_t) -#ifndef wint_t -typedef int __darwin_wint_t; -typedef __darwin_wint_t wint_t; -#endif void pr7981(wint_t c, wchar_t c2) { printf("%lc", c); // no-warning printf("%lc", 1.0); // expected-warning{{the argument has type 'double'}} printf("%lc", (char) 1); // no-warning - printf("%lc", &c); // expected-warning{{the argument has type 'wint_t *' (aka 'int *')}} + printf("%lc", &c); // expected-warning{{the argument has type 'wint_t *'}} + // If wint_t and wchar_t are the same width and wint_t is signed where + // wchar_t is unsigned, an implicit conversion isn't possible. +#if defined(__WINT_UNSIGNED__) || !defined(__WCHAR_UNSIGNED__) || \ + __WINT_WIDTH__ > __WCHAR_WIDTH__ printf("%lc", c2); // no-warning +#endif } // <rdar://problem/8269537> -Wformat-security says NULL is not a string literal @@ -432,10 +459,6 @@ void pr9751() { printf(kFormat2, 1, "foo"); // expected-warning{{data argument position '18' exceeds the number of data arguments (2)}} printf("%18$s\n", 1, "foo"); // expected-warning{{data argument position '18' exceeds the number of data arguments (2)}} - const char kFormat3[] = "%n"; // expected-note{{format string is defined here}} - printf(kFormat3, "as"); // expected-warning{{use of '%n' in format string discouraged}} - printf("%n", "as"); // expected-warning{{use of '%n' in format string discouraged}} - const char kFormat4[] = "%y"; // expected-note{{format string is defined here}} printf(kFormat4, 5); // expected-warning{{invalid conversion specifier 'y'}} printf("%y", 5); // expected-warning{{invalid conversion specifier 'y'}} @@ -497,6 +520,15 @@ void pr9751() { printf(kFormat17, (int[]){0}); // expected-warning{{format specifies type 'unsigned short' but the argument}} printf("%a", (long double)0); // expected-warning{{format specifies type 'double' but the argument has type 'long double'}} + + // Test braced char[] initializers. + const char kFormat18[] = { "%lld" }; // expected-note{{format string is defined here}} + printf(kFormat18, 0); // expected-warning{{format specifies type}} + + // Make sure we point at the offending argument rather than the format string. + const char kFormat19[] = "%d"; // expected-note{{format string is defined here}} + printf(kFormat19, + 0.0); // expected-warning{{format specifies}} } // PR 9466: clang: doesn't know about %Lu, %Ld, and %Lx @@ -521,3 +553,48 @@ void test_other_formats() { dateformat(""); // expected-warning{{format string is empty}} dateformat(str); // no-warning (using strftime non literal is not unsafe) } + +// Do not warn about unused arguments coming from system headers. +// <rdar://problem/11317765> +#include <format-unused-system-args.h> +void test_unused_system_args(int x) { + PRINT1("%d\n", x); // no-warning{{extra argument is system header is OK}} +} + +void pr12761(char c) { + // This should not warn even with -fno-signed-char. + printf("%hhx", c); +} + + +// Test that we correctly merge the format in both orders. +extern void test14_foo(const char *, const char *, ...) + __attribute__((__format__(__printf__, 1, 3))); +extern void test14_foo(const char *, const char *, ...) + __attribute__((__format__(__scanf__, 2, 3))); + +extern void test14_bar(const char *, const char *, ...) + __attribute__((__format__(__scanf__, 2, 3))); +extern void test14_bar(const char *, const char *, ...) + __attribute__((__format__(__printf__, 1, 3))); + +void test14_zed(int *p) { + test14_foo("%", "%d", p); // expected-warning{{incomplete format specifier}} + test14_bar("%", "%d", p); // expected-warning{{incomplete format specifier}} +} + +void test_qualifiers(volatile int *vip, const int *cip, + const volatile int *cvip) { + printf("%n", cip); // expected-warning{{format specifies type 'int *' but the argument has type 'const int *'}} + printf("%n", cvip); // expected-warning{{format specifies type 'int *' but the argument has type 'const volatile int *'}} + + printf("%n", vip); // No warning. + printf("%p", cip); // No warning. + printf("%p", cvip); // No warning. + + + typedef int* ip_t; + typedef const int* cip_t; + printf("%n", (ip_t)0); // No warning. + printf("%n", (cip_t)0); // expected-warning{{format specifies type 'int *' but the argument has type 'cip_t' (aka 'const int *')}} +} |