[cfe-commits] r95869 - in /cfe/trunk: include/clang/Analysis/Analyses/PrintfFormatString.h include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaChecking.cpp test/Sema/format-strings.c
Ted Kremenek
kremenek at apple.com
Thu Feb 11 01:27:42 PST 2010
Author: kremenek
Date: Thu Feb 11 03:27:41 2010
New Revision: 95869
URL: http://llvm.org/viewvc/llvm-project?rev=95869&view=rev
Log:
Patch by Cristian Draghici:
Enhance the printf format string checking when using the format
specifier flags ' ', '0', '+' with the 'p' or 's' conversions (since
they are nonsensical and undefined). This is similar to GCC's
checking.
Also warning when a precision is used with the 'p' conversin
specifier, since it has no meaning.
Modified:
cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaChecking.cpp
cfe/trunk/test/Sema/format-strings.c
Modified: cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h?rev=95869&r1=95868&r2=95869&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h Thu Feb 11 03:27:41 2010
@@ -73,6 +73,10 @@
const char *getStart() const {
return Position;
}
+
+ llvm::StringRef getCharacters() const {
+ return llvm::StringRef(getStart(), getLength());
+ }
bool consumesDataArgument() const {
switch (kind) {
@@ -232,6 +236,7 @@
bool hasPlusPrefix() const { return (bool) HasPlusPrefix; }
bool hasAlternativeForm() const { return (bool) HasAlternativeForm; }
bool hasLeadingZeros() const { return (bool) HasLeadingZeroes; }
+ bool hasSpacePrefix() const { return (bool) HasSpacePrefix; }
};
class FormatStringHandler {
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=95869&r1=95868&r2=95869&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Feb 11 03:27:41 2010
@@ -2514,7 +2514,13 @@
def warn_printf_asterisk_precision_wrong_type : Warning<
"field precision should have type %0, but argument has type %1">,
InGroup<Format>;
-
+def warn_printf_nonsensical_precision: Warning<
+ "precision used in '%0' conversion specifier (where it has no meaning)">,
+ InGroup<Format>;
+def warn_printf_nonsensical_flag: Warning<
+ "flag '%0' results in undefined behavior in '%1' conversion specifier">,
+ InGroup<Format>;
+
// CHECK: returning address/reference of stack memory
def warn_ret_stack_addr : Warning<
"address of stack memory associated with local variable %0 returned">;
Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=95869&r1=95868&r2=95869&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Feb 11 03:27:41 2010
@@ -1080,6 +1080,9 @@
bool HandleAmount(const analyze_printf::OptionalAmount &Amt,
unsigned MissingArgDiag, unsigned BadTypeDiag,
const char *startSpecifier, unsigned specifierLen);
+ void HandleFlags(const analyze_printf::FormatSpecifier &FS,
+ llvm::StringRef flag, llvm::StringRef cspec,
+ const char *startSpecifier, unsigned specifierLen);
bool MatchType(QualType A, QualType B, bool ignoreSign);
@@ -1175,6 +1178,16 @@
return false;
}
+void CheckPrintfHandler::HandleFlags(const analyze_printf::FormatSpecifier &FS,
+ llvm::StringRef flag,
+ llvm::StringRef cspec,
+ const char *startSpecifier,
+ unsigned specifierLen) {
+ const analyze_printf::ConversionSpecifier &CS = FS.getConversionSpecifier();
+ S.Diag(getLocationOfByte(CS.getStart()), diag::warn_printf_nonsensical_flag)
+ << flag << cspec << getFormatSpecifierRange(startSpecifier, specifierLen);
+}
+
bool
CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt,
unsigned MissingArgDiag,
@@ -1214,7 +1227,8 @@
}
bool
-CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS,
+CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
+ &FS,
const char *startSpecifier,
unsigned specifierLen) {
@@ -1262,7 +1276,25 @@
// Continue checking the other format specifiers.
return true;
}
-
+
+ if (CS.getKind() == ConversionSpecifier::VoidPtrArg) {
+ if (FS.getPrecision().getHowSpecified() != OptionalAmount::NotSpecified)
+ S.Diag(getLocationOfByte(CS.getStart()),
+ diag::warn_printf_nonsensical_precision)
+ << CS.getCharacters()
+ << getFormatSpecifierRange(startSpecifier, specifierLen);
+ }
+ if (CS.getKind() == ConversionSpecifier::VoidPtrArg ||
+ CS.getKind() == ConversionSpecifier::CStrArg) {
+ // FIXME: Instead of using "0", "+", etc., eventually get them from
+ // the FormatSpecifier.
+ if (FS.hasLeadingZeros())
+ HandleFlags(FS, "0", CS.getCharacters(), startSpecifier, specifierLen);
+ if (FS.hasPlusPrefix())
+ HandleFlags(FS, "+", CS.getCharacters(), startSpecifier, specifierLen);
+ if (FS.hasSpacePrefix())
+ HandleFlags(FS, " ", CS.getCharacters(), startSpecifier, specifierLen);
+ }
// The remaining checks depend on the data arguments.
if (HasVAListArg)
Modified: cfe/trunk/test/Sema/format-strings.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings.c?rev=95869&r1=95868&r2=95869&view=diff
==============================================================================
--- cfe/trunk/test/Sema/format-strings.c (original)
+++ cfe/trunk/test/Sema/format-strings.c Thu Feb 11 03:27:41 2010
@@ -171,6 +171,18 @@
printf("%f\n", (long double) 1.0); // expected-warning{{conversion specifies type 'double' but the argument has type 'long double'}}
}
+void test11(void *p, char *s) {
+ printf("%p", p); // no-warning
+ printf("%.4p", p); // expected-warning{{precision used in 'p' conversion specifier (where it has no meaning)}}
+ printf("%+p", p); // expected-warning{{flag '+' results in undefined behavior in 'p' conversion specifier}}
+ printf("% p", p); // expected-warning{{flag ' ' results in undefined behavior in 'p' conversion specifier}}
+ printf("%0p", p); // expected-warning{{flag '0' results in undefined behavior in 'p' conversion specifier}}
+ printf("%s", s); // no-warning
+ printf("%+s", p); // expected-warning{{flag '+' results in undefined behavior in 's' conversion specifier}}
+ printf("% s", p); // expected-warning{{flag ' ' results in undefined behavior in 's' conversion specifier}}
+ printf("%0s", p); // expected-warning{{flag '0' results in undefined behavior in 's' conversion specifier}}
+}
+
typedef struct __aslclient *aslclient;
typedef struct __aslmsg *aslmsg;
int asl_log(aslclient asl, aslmsg msg, int level, const char *format, ...) __attribute__((__format__ (__printf__, 4, 5)));
More information about the cfe-commits
mailing list