aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Analysis/PrintfFormatString.cpp10
-rw-r--r--lib/Sema/SemaChecking.cpp71
2 files changed, 74 insertions, 7 deletions
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 986411fc7d..1a95e0b882 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -15,7 +15,7 @@
#include "clang/Analysis/Analyses/PrintfFormatString.h"
using namespace clang;
-using namespace analyze_printf;
+using namespace clang::analyze_printf;
namespace {
class FormatSpecifierResult {
@@ -70,10 +70,12 @@ static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
}
if (foundDigits)
- return OptionalAmount(accumulator);
+ return OptionalAmount(accumulator, Beg);
- if (c == '*')
- return OptionalAmount(OptionalAmount::Arg);
+ if (c == '*') {
+ ++I;
+ return OptionalAmount(OptionalAmount::Arg, Beg);
+ }
break;
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 3589affaf3..f34d2388b4 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -1290,14 +1290,20 @@ class CheckPrintfHandler : public analyze_printf::FormatStringHandler {
const unsigned NumDataArgs;
const bool IsObjCLiteral;
const char *Beg; // Start of format string.
+ const bool HasVAListArg;
+ const CallExpr *TheCall;
+ unsigned FormatIdx;
public:
CheckPrintfHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr,
unsigned numDataArgs, bool isObjCLiteral,
- const char *beg)
+ const char *beg, bool hasVAListArg,
+ const CallExpr *theCall, unsigned formatIdx)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
NumConversions(0), NumDataArgs(numDataArgs),
- IsObjCLiteral(isObjCLiteral), Beg(beg) {}
+ IsObjCLiteral(isObjCLiteral), Beg(beg),
+ HasVAListArg(hasVAListArg),
+ TheCall(theCall), FormatIdx(formatIdx) {}
void HandleNullChar(const char *nullCharacter);
@@ -1307,6 +1313,11 @@ public:
private:
SourceRange getFormatRange();
SourceLocation getLocationOfByte(const char *x);
+
+ bool HandleAmount(const analyze_printf::OptionalAmount &Amt,
+ unsigned MissingArgDiag, unsigned BadTypeDiag);
+
+ const Expr *getDataArg(unsigned i) const;
};
}
@@ -1325,6 +1336,43 @@ void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) {
<< getFormatRange();
}
+const Expr *CheckPrintfHandler::getDataArg(unsigned i) const {
+ return TheCall->getArg(FormatIdx + i);
+}
+
+bool
+CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt,
+ unsigned MissingArgDiag,
+ unsigned BadTypeDiag) {
+
+ if (Amt.hasDataArgument()) {
+ ++NumConversions;
+ if (!HasVAListArg) {
+ if (NumConversions > NumDataArgs) {
+ S.Diag(getLocationOfByte(Amt.getStart()), MissingArgDiag)
+ << getFormatRange();
+ // Don't do any more checking. We will just emit
+ // spurious errors.
+ return false;
+ }
+
+ // Type check the data argument. It should be an 'int'.
+ const Expr *Arg = getDataArg(NumConversions);
+ QualType T = Arg->getType();
+ const BuiltinType *BT = T->getAs<BuiltinType>();
+ if (!BT || BT->getKind() != BuiltinType::Int) {
+ S.Diag(getLocationOfByte(Amt.getStart()), BadTypeDiag)
+ << T << getFormatRange() << Arg->getSourceRange();
+ // Don't do any more checking. We will just emit
+ // spurious errors.
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
bool
CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS,
const char *startSpecifier,
@@ -1333,6 +1381,22 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
using namespace analyze_printf;
const ConversionSpecifier &CS = FS.getConversionSpecifier();
+ // First check if the field width, precision, and conversion specifier
+ // have matching data arguments.
+ if (!HandleAmount(FS.getFieldWidth(),
+ diag::warn_printf_asterisk_width_missing_arg,
+ diag::warn_printf_asterisk_width_wrong_type)) {
+ return false;
+ }
+
+ if (!HandleAmount(FS.getPrecision(),
+ diag::warn_printf_asterisk_precision_missing_arg,
+ diag::warn_printf_asterisk_precision_wrong_type)) {
+ return false;
+ }
+
+ ++NumConversions;
+
// Check for using an Objective-C specific conversion specifier
// in a non-ObjC literal.
if (!IsObjCLiteral && CS.isObjCArg()) {
@@ -1377,7 +1441,8 @@ Sema::AlternateCheckPrintfString(const StringLiteral *FExpr,
CheckPrintfHandler H(*this, FExpr, OrigFormatExpr,
TheCall->getNumArgs() - firstDataArg,
- isa<ObjCStringLiteral>(OrigFormatExpr), Str);
+ isa<ObjCStringLiteral>(OrigFormatExpr), Str,
+ HasVAListArg, TheCall, format_idx);
analyze_printf::ParseFormatString(H, Str, Str + StrLen);
}