summaryrefslogtreecommitdiffstats
path: root/test/Sema/format-strings.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/Sema/format-strings.c')
-rw-r--r--test/Sema/format-strings.c117
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 *')}}
+}
OpenPOWER on IntegriCloud