From bf4832cda8c3f8c8b7eff06be4594cac02ddf6b4 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Sat, 8 Jan 2011 05:28:46 +0000 Subject: [PATCH] Add semantic checking that the "thousands grouping" prefix in a printf format string is matched with the appropriate conversion specifier. llvm-svn: 123055 --- .../clang/Analysis/Analyses/FormatString.h | 4 ++++ clang/lib/Analysis/PrintfFormatString.cpp | 18 ++++++++++++++++++ clang/lib/Sema/SemaChecking.cpp | 2 ++ clang/test/Sema/format-strings.c | 3 +++ 4 files changed, 27 insertions(+) diff --git a/clang/include/clang/Analysis/Analyses/FormatString.h b/clang/include/clang/Analysis/Analyses/FormatString.h index cc1d3427e77c..7cc76a8d471b 100644 --- a/clang/include/clang/Analysis/Analyses/FormatString.h +++ b/clang/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/clang/lib/Analysis/PrintfFormatString.cpp b/clang/lib/Analysis/PrintfFormatString.cpp index d99de2215dcf..82ab14dbed6e 100644 --- a/clang/lib/Analysis/PrintfFormatString.cpp +++ b/clang/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/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 75b30fcb7699..0ca1ce52ab17 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/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/clang/test/Sema/format-strings.c b/clang/test/Sema/format-strings.c index 93b6eb52b2f3..be506d7c6b19 100644 --- a/clang/test/Sema/format-strings.c +++ b/clang/test/Sema/format-strings.c @@ -336,4 +336,7 @@ void posix_extensions() { // Test %'d, "thousands grouping". // 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}} } -- GitLab