aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2011-01-08 05:28:46 +0000
committerTed Kremenek <kremenek@apple.com>2011-01-08 05:28:46 +0000
commit65197b4b0c55bb74af0450230d61ee9461223721 (patch)
tree201f419c8802d9946cd8f61566814961dc7544a5
parentbd18d4584aae0ed6f7111ef5713784cf29fe663f (diff)
Add semantic checking that the "thousands grouping"
prefix in a printf format string is matched with the appropriate conversion specifier. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123055 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Analysis/Analyses/FormatString.h4
-rw-r--r--lib/Analysis/PrintfFormatString.cpp18
-rw-r--r--lib/Sema/SemaChecking.cpp2
-rw-r--r--test/Sema/format-strings.c3
4 files changed, 27 insertions, 0 deletions
diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h
index cc1d3427e7..7cc76a8d47 100644
--- a/include/clang/Analysis/Analyses/FormatString.h
+++ b/include/clang/Analysis/Analyses/FormatString.h
@@ -450,6 +450,9 @@ public:
/// more than one type.
ArgTypeResult getArgType(ASTContext &Ctx) const;
+ const OptionalFlag &hasThousandsGrouping() const {
+ return HasThousandsGrouping;
+ }
const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }
const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }
const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }
@@ -470,6 +473,7 @@ public:
bool hasValidLeadingZeros() const;
bool hasValidSpacePrefix() const;
bool hasValidLeftJustified() const;
+ bool hasValidThousandsGroupingPrefix() const;
bool hasValidPrecision() const;
bool hasValidFieldWidth() const;
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index d99de2215d..82ab14dbed 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -590,6 +590,24 @@ bool PrintfSpecifier::hasValidLeftJustified() const {
}
}
+bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
+ if (!HasThousandsGrouping)
+ return true;
+
+ switch (CS.getKind()) {
+ case ConversionSpecifier::dArg:
+ case ConversionSpecifier::iArg:
+ case ConversionSpecifier::uArg:
+ case ConversionSpecifier::fArg:
+ case ConversionSpecifier::FArg:
+ case ConversionSpecifier::gArg:
+ case ConversionSpecifier::GArg:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool PrintfSpecifier::hasValidPrecision() const {
if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
return true;
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 75b30fcb76..0ca1ce52ab 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -1491,6 +1491,8 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
}
// Check each flag does not conflict with any other component.
+ if (!FS.hasValidThousandsGroupingPrefix())
+ HandleFlag(FS, FS.hasThousandsGrouping(), startSpecifier, specifierLen);
if (!FS.hasValidLeadingZeros())
HandleFlag(FS, FS.hasLeadingZeros(), startSpecifier, specifierLen);
if (!FS.hasValidPlusPrefix())
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index 93b6eb52b2..be506d7c6b 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -336,4 +336,7 @@ void posix_extensions() {
// Test %'d, "thousands grouping".
// <rdar://problem/8816343>
printf("%'d\n", 123456789); // no-warning
+ printf("%'i\n", 123456789); // no-warning
+ printf("%'f\n", (float) 1.0); // no-warning
+ printf("%'p\n", (void*) 0); // expected-warning{{results in undefined behavior with 'p' conversion specifier}}
}