This revision was automatically updated to reflect the committed changes.
Closed by commit rGcd4e600f5f5c: [Sema] Warn about printf %n on Android and
Fuchsia (authored by abrachet).
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D117611/new/
https://reviews.llvm.org/D117611
Files:
clang/include/clang/AST/FormatString.h
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/AST/OSLog.cpp
clang/lib/AST/PrintfFormatString.cpp
clang/lib/Sema/SemaChecking.cpp
clang/test/FixIt/format.m
clang/test/Sema/format-strings.c
Index: clang/test/Sema/format-strings.c
===================================================================
--- clang/test/Sema/format-strings.c
+++ clang/test/Sema/format-strings.c
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs %s
// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs -fno-signed-char %s
+// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs -triple=x86_64-unknown-fuchsia %s
+// RUN: %clang_cc1 -fblocks -fsyntax-only -verify -Wformat-nonliteral -isystem %S/Inputs -triple=x86_64-linux-android %s
#include <stdarg.h>
#include <stddef.h>
@@ -118,6 +120,8 @@
printf(i ? "%i\n" : "%i %s %s\n", i, s); // expected-warning{{more '%' conversions than data arguments}}
}
+#if !defined(__ANDROID__) && !defined(__Fuchsia__)
+
void check_writeback_specifier()
{
int x;
@@ -154,6 +158,45 @@
// expected-note@-1{{did you mean to use 'll'?}}
}
+#else
+
+void check_writeback_specifier()
+{
+ int x;
+ printf("%n", &x); // expected-warning{{'%n' specifier not supported on this platform}}
+
+ printf("%hhn", (signed char*)0); // expected-warning{{'%n' specifier not supported on this platform}}
+ printf("%hhn", (char*)0); // expected-warning{{'%n' specifier not supported on this platform}}
+ printf("%hhn", (unsigned char*)0); // expected-warning{{'%n' specifier not supported on this platform}}
+ printf("%hhn", (int*)0); // expected-warning{{format specifies type 'signed char *' but the argument has type 'int *'}}
+ // expected-warning@-1 {{'%n' specifier not supported on this platform}}
+
+ printf("%hn", (short*)0); // expected-warning{{'%n' specifier not supported on this platform}}
+ printf("%hn", (unsigned short*)0); // expected-warning{{'%n' specifier not supported on this platform}}
+ printf("%hn", (int*)0); // expected-warning{{format specifies type 'short *' but the argument has type 'int *'}}
+ // expected-warning@-1 {{'%n' specifier not supported on this platform}}
+
+ printf("%n", (int*)0); // expected-warning{{'%n' specifier not supported on this platform}}
+ printf("%n", (unsigned int*)0); // expected-warning{{'%n' specifier not supported on this platform}}
+ printf("%n", (char*)0); // expected-warning{{format specifies type 'int *' but the argument has type 'char *'}}
+ // expected-warning@-1 {{'%n' specifier not supported on this platform}}
+
+ printf("%ln", (long*)0); // expected-warning{{'%n' specifier not supported on this platform}}
+ printf("%ln", (unsigned long*)0); // expected-warning{{'%n' specifier not supported on this platform}}
+ printf("%ln", (int*)0); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
+ // expected-warning@-1 {{'%n' specifier not supported on this platform}}
+
+ printf("%lln", (long long*)0); // expected-warning{{'%n' specifier not supported on this platform}}
+ printf("%lln", (unsigned long long*)0); // expected-warning{{'%n' specifier not supported on this platform}}
+ printf("%lln", (int*)0); // expected-warning{{format specifies type 'long long *' but the argument has type 'int *'}}
+ // expected-warning@-1 {{'%n' specifier not supported on this platform}}
+
+ printf("%qn", (long long*)0); // expected-warning{{'%n' specifier not supported on this platform}}
+ printf("%qn", (unsigned long long*)0); // expected-warning{{'%n' specifier not supported on this platform}}
+}
+
+#endif // !defined(__ANDROID__) && !defined(__Fuchsia__)
+
void check_invalid_specifier(FILE* fp, char *buf)
{
printf("%s%lb%d","unix",10,20); // expected-warning {{invalid conversion specifier 'b'}} expected-warning {{data argument not used by format string}}
@@ -386,14 +429,28 @@
// Bad flag usage
printf("%#p", (void *) 0); // expected-warning{{flag '#' results in undefined behavior with 'p' conversion specifier}}
printf("%0d", -1); // no-warning
+ printf("%-p", (void *) 0); // no-warning
+#if !defined(__ANDROID__) && !defined(__Fuchsia__)
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
+#else
+ printf("%#n", (int *) 0); // expected-warning{{flag '#' results in undefined behavior with 'n' conversion specifier}}
+ // expected-warning@-1 {{'%n' specifier not supported on this platform}}
+ printf("%-n", (int *) 0); // expected-warning{{flag '-' results in undefined behavior with 'n' conversion specifier}}
+ // expected-warning@-1 {{'%n' specifier not supported on this platform}}
+#endif // !defined(__ANDROID__) && !defined(__Fuchsia__)
// Bad optional amount use
printf("%.2c", 'a'); // expected-warning{{precision used with 'c' conversion specifier, resulting in undefined behavior}}
+#if !defined(__ANDROID__) && !defined(__Fuchsia__)
+ 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}}
+#else
printf("%1n", (int *) 0); // expected-warning{{field width used with 'n' conversion specifier, resulting in undefined behavior}}
+ // expected-warning@-1 {{'%n' specifier not supported on this platform}}
printf("%.9n", (int *) 0); // expected-warning{{precision used with 'n' conversion specifier, resulting in undefined behavior}}
+ // expected-warning@-1 {{'%n' specifier not supported on this platform}}
+#endif // #if !defined(__ANDROID__) && !defined(__Fuchsia__)
// Ignored flags
printf("% +f", 1.23); // expected-warning{{flag ' ' is ignored when flag '+' is present}}
@@ -644,6 +701,8 @@
test14_bar("%", "%d", p); // expected-warning{{incomplete format specifier}}
}
+#if !defined(__ANDROID__) && !defined(__Fuchsia__)
+
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 *'}}
@@ -660,6 +719,29 @@
printf("%n", (cip_t)0); // expected-warning{{format specifies type 'int *' but the argument has type 'cip_t' (aka 'const int *')}}
}
+#else
+
+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 *'}}
+ // expected-warning@-1 {{'%n' specifier not supported on this platform}}
+ printf("%n", cvip); // expected-warning{{format specifies type 'int *' but the argument has type 'const volatile int *'}}
+ // expected-warning@-1 {{'%n' specifier not supported on this platform}}
+
+ printf("%n", vip); // expected-warning{{'%n' specifier not supported on this platform}}
+ printf("%p", cip); // No warning.
+ printf("%p", cvip); // No warning.
+
+
+ typedef int* ip_t;
+ typedef const int* cip_t;
+ printf("%n", (ip_t)0); // expected-warning{{'%n' specifier not supported on this platform}}
+ printf("%n", (cip_t)0); // expected-warning{{format specifies type 'int *' but the argument has type 'cip_t' (aka 'const int *')}}
+ // expected-warning@-1 {{'%n' specifier not supported on this platform}}
+}
+
+#endif // #if !defined(__ANDROID__) && !defined(__Fuchsia__)
+
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#pragma GCC diagnostic warning "-Wformat-security"
// <rdar://problem/14178260>
Index: clang/test/FixIt/format.m
===================================================================
--- clang/test/FixIt/format.m
+++ clang/test/FixIt/format.m
@@ -241,8 +241,13 @@
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%f"
short x;
+#if !defined(__ANDROID__) && !defined(__Fuchsia__)
printf("%zn", &x); // expected-warning-re{{format specifies type 'ssize_t *' (aka '{{.+}}') but the argument has type 'short *'}}
- // PrintfSpecifier::fixType doesn't handle %n, so a fix-it is not emitted,
+#else
+ printf("%zn", &x); // expected-warning-re{{format specifies type 'ssize_t *' (aka '{{.+}}') but the argument has type 'short *'}}
+ // expected-warning@-1 {{'%n' specifier not supported on this platform}}
+#endif // !defined(__ANDROID__) && !defined(__Fuchsia__)
+ // PrintfSpecifier::fixType doesn't handle %n, so a fix-it is not emitted,
// see the comment in PrintfSpecifier::fixType in PrintfFormatString.cpp.
}
@@ -269,12 +274,21 @@
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%f"
ptrdiff_t p3 = 0;
+#if !defined(__ANDROID__) && !defined(__Fuchsia__)
printf("%tn", &p3); // No warning.
+#else
+ printf("%tn", &p3); // expected-warning{{'%n' specifier not supported on this platform}}
+#endif // !defined(__ANDROID__) && !defined(__Fuchsia__)
short x;
+#if !defined(__ANDROID__) && !defined(__Fuchsia__)
printf("%tn", &x); // expected-warning-re{{format specifies type 'ptrdiff_t *' (aka '{{.+}}') but the argument has type 'short *'}}
// PrintfSpecifier::fixType doesn't handle %n, so a fix-it is not emitted,
// see the comment in PrintfSpecifier::fixType in PrintfFormatString.cpp.
+#else
+ printf("%tn", &x); // expected-warning-re{{format specifies type 'ptrdiff_t *' (aka '{{.+}}') but the argument has type 'short *'}}
+ // expected-warning@-1 {{'%n' specifier not supported on this platform}}
+#endif // !defined(__ANDROID__) && !defined(__Fuchsia__)
}
void testEnum() {
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -499,7 +499,8 @@
1 /* null byte always written by sprintf */) {}
bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
- const char *, unsigned SpecifierLen) override {
+ const char *, unsigned SpecifierLen,
+ const TargetInfo &) override {
const size_t FieldWidth = computeFieldWidth(FS);
const size_t Precision = computePrecision(FS);
@@ -8909,8 +8910,8 @@
void handleInvalidMaskType(StringRef MaskType) override;
bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
- const char *startSpecifier,
- unsigned specifierLen) override;
+ const char *startSpecifier, unsigned specifierLen,
+ const TargetInfo &Target) override;
bool checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
const char *StartSpecifier,
unsigned SpecifierLen,
@@ -9169,11 +9170,9 @@
return false;
}
-bool
-CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
- &FS,
- const char *startSpecifier,
- unsigned specifierLen) {
+bool CheckPrintfHandler::HandlePrintfSpecifier(
+ const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier,
+ unsigned specifierLen, const TargetInfo &Target) {
using namespace analyze_format_string;
using namespace analyze_printf;
@@ -9305,6 +9304,15 @@
}
}
+ const llvm::Triple &Triple = Target.getTriple();
+ if (CS.getKind() == ConversionSpecifier::nArg &&
+ (Triple.isAndroid() || Triple.isOSFuchsia())) {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_printf_narg_not_supported),
+ getLocationOfByte(CS.getStart()),
+ /*IsStringLocation*/ false,
+ getSpecifierRange(startSpecifier, specifierLen));
+ }
+
// Check for invalid use of field width
if (!FS.hasValidFieldWidth()) {
HandleInvalidAmount(FS, FS.getFieldWidth(), /* field width */ 0,
Index: clang/lib/AST/PrintfFormatString.cpp
===================================================================
--- clang/lib/AST/PrintfFormatString.cpp
+++ clang/lib/AST/PrintfFormatString.cpp
@@ -428,7 +428,7 @@
continue;
// We have a format specifier. Pass it to the callback.
if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
- I - FSR.getStart()))
+ I - FSR.getStart(), Target))
return true;
}
assert(I == E && "Format string not exhausted");
Index: clang/lib/AST/OSLog.cpp
===================================================================
--- clang/lib/AST/OSLog.cpp
+++ clang/lib/AST/OSLog.cpp
@@ -56,8 +56,8 @@
}
bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
- const char *StartSpecifier,
- unsigned SpecifierLen) override {
+ const char *StartSpecifier, unsigned SpecifierLen,
+ const TargetInfo &) override {
if (!FS.consumesDataArgument() &&
FS.getConversionSpecifier().getKind() !=
clang::analyze_format_string::ConversionSpecifier::PrintErrno)
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9369,6 +9369,9 @@
def warn_printf_invalid_objc_flag: Warning<
"'%0' is not a valid object format flag">,
InGroup<Format>;
+def warn_printf_narg_not_supported : Warning<
+ "'%%n' specifier not supported on this platform">,
+ InGroup<Format>;
def warn_scanf_scanlist_incomplete : Warning<
"no closing ']' for '%%[' in scanf format string">,
InGroup<Format>;
Index: clang/include/clang/AST/FormatString.h
===================================================================
--- clang/include/clang/AST/FormatString.h
+++ clang/include/clang/AST/FormatString.h
@@ -726,7 +726,8 @@
virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
const char *startSpecifier,
- unsigned specifierLen) {
+ unsigned specifierLen,
+ const TargetInfo &Target) {
return true;
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits