aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/PrintfFormatString.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2010-02-27 01:41:03 +0000
committerTed Kremenek <kremenek@apple.com>2010-02-27 01:41:03 +0000
commitefaff195ba1fa55b6fe0b0b2435b81451387d241 (patch)
tree1923cd17053f841ed7e5035ace8f32637df29049 /lib/Analysis/PrintfFormatString.cpp
parentc8dfe5ece04e683106eb96c58a2999f70b53ac21 (diff)
For printf format string checking, add support for positional format strings.
Along the way, coelesce some of the diagnostics. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97297 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/PrintfFormatString.cpp')
-rw-r--r--lib/Analysis/PrintfFormatString.cpp149
1 files changed, 134 insertions, 15 deletions
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 9c0f813964..6d6b370b3f 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -15,10 +15,12 @@
#include "clang/Analysis/Analyses/PrintfFormatString.h"
#include "clang/AST/ASTContext.h"
-using clang::analyze_printf::FormatSpecifier;
-using clang::analyze_printf::OptionalAmount;
using clang::analyze_printf::ArgTypeResult;
+using clang::analyze_printf::FormatSpecifier;
using clang::analyze_printf::FormatStringHandler;
+using clang::analyze_printf::OptionalAmount;
+using clang::analyze_printf::PositionContext;
+
using namespace clang;
namespace {
@@ -62,36 +64,141 @@ public:
// Methods for parsing format strings.
//===----------------------------------------------------------------------===//
-static OptionalAmount ParseAmount(const char *&Beg, const char *E,
- unsigned &argIndex) {
+static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
const char *I = Beg;
UpdateOnReturn <const char*> UpdateBeg(Beg, I);
- bool foundDigits = false;
unsigned accumulator = 0;
for ( ; I != E; ++I) {
char c = *I;
if (c >= '0' && c <= '9') {
- foundDigits = true;
+ // Ignore '0' on the first character.
+ if (c == '0' && I == Beg)
+ break;
accumulator += (accumulator * 10) + (c - '0');
continue;
}
- if (foundDigits)
+ if (accumulator)
return OptionalAmount(OptionalAmount::Constant, accumulator, Beg);
- if (c == '*') {
- ++I;
- return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg);
- }
-
break;
}
return OptionalAmount();
}
+static OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
+ unsigned &argIndex) {
+ if (*Beg == '*') {
+ ++Beg;
+ return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg);
+ }
+
+ return ParseAmount(Beg, E);
+}
+
+static OptionalAmount ParsePositionAmount(FormatStringHandler &H,
+ const char *Start,
+ const char *&Beg, const char *E,
+ PositionContext p) {
+ if (*Beg == '*') {
+ const char *I = Beg + 1;
+ const OptionalAmount &Amt = ParseAmount(I, E);
+
+ if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
+ H.HandleInvalidPosition(Beg, I - Beg, p);
+ return OptionalAmount(false);
+ }
+
+ if (I== E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return OptionalAmount(false);
+ }
+
+ if (*I == '$') {
+ const char *Tmp = Beg;
+ Beg = ++I;
+ return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
+ Tmp);
+ }
+
+ H.HandleInvalidPosition(Beg, I - Beg, p);
+ return OptionalAmount(false);
+ }
+
+ return ParseAmount(Beg, E);
+}
+
+static bool ParsePrecision(FormatStringHandler &H, FormatSpecifier &FS,
+ const char *Start, const char *&Beg, const char *E,
+ unsigned *argIndex) {
+ if (argIndex) {
+ FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
+ }
+ else {
+ const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
+ analyze_printf::PrecisionPos);
+ if (Amt.isInvalid())
+ return true;
+ FS.setPrecision(Amt);
+ }
+ return false;
+}
+
+static bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &FS,
+ const char *Start, const char *&Beg, const char *E,
+ unsigned *argIndex) {
+ // FIXME: Support negative field widths.
+ if (argIndex) {
+ FS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
+ }
+ else {
+ const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
+ analyze_printf::FieldWidthPos);
+ if (Amt.isInvalid())
+ return true;
+ FS.setFieldWidth(Amt);
+ }
+ return false;
+}
+
+
+static bool ParseArgPosition(FormatStringHandler &H,
+ FormatSpecifier &FS, const char *Start,
+ const char *&Beg, const char *E) {
+
+ using namespace clang::analyze_printf;
+ const char *I = Beg;
+
+ const OptionalAmount &Amt = ParseAmount(I, E);
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return true;
+ }
+
+ if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
+ FS.setArgIndex(Amt.getConstantAmount() - 1);
+ FS.setUsesPositionalArg();
+ // Update the caller's pointer if we decided to consume
+ // these characters.
+ Beg = I;
+ return false;
+ }
+
+ // Special case: '%0$', since this is an easy mistake.
+ if (*I == '0' && (I+1) != E && *(I+1) == '$') {
+ H.HandleZeroPosition(Start, I - Start + 2);
+ return true;
+ }
+
+ return false;
+}
+
static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
const char *&Beg,
const char *E,
@@ -128,6 +235,14 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
}
FormatSpecifier FS;
+ if (ParseArgPosition(H, FS, Start, I, E))
+ return true;
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E - Start);
+ return true;
+ }
// Look for flags (if any).
bool hasMore = true;
@@ -151,7 +266,9 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
}
// Look for the field width (if any).
- FS.setFieldWidth(ParseAmount(I, E, argIndex));
+ if (ParseFieldWidth(H, FS, Start, I, E,
+ FS.usesPositionalArg() ? 0 : &argIndex))
+ return true;
if (I == E) {
// No more characters left?
@@ -167,7 +284,9 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
return true;
}
- FS.setPrecision(ParseAmount(I, E, argIndex));
+ if (ParsePrecision(H, FS, Start, I, E,
+ FS.usesPositionalArg() ? 0 : &argIndex))
+ return true;
if (I == E) {
// No more characters left?
@@ -245,7 +364,7 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
}
ConversionSpecifier CS(conversionPosition, k);
FS.setConversionSpecifier(CS);
- if (CS.consumesDataArgument())
+ if (CS.consumesDataArgument() && !FS.usesPositionalArg())
FS.setArgIndex(argIndex++);
if (k == ConversionSpecifier::InvalidSpecifier) {