--- /dev/null
+//==- PrintfFormatStrings.h - Analysis of printf format strings --*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Handling of format string in printf and friends. The structure of format
+// strings for fprintf() are described in C99 7.19.6.1.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FPRINTF_FORMAT_H
+#define LLVM_CLANG_FPRINTF_FORMAT_H
+
+#include <cassert>
+
+namespace clang {
+namespace printf {
+
+class ConversionSpecifier {
+public:
+ enum Kind {
+ InvalidSpecifier = 0,
+ dArg, // 'd'
+ iArg, // 'i',
+ oArg, // 'o',
+ uArg, // 'u',
+ xArg, // 'x',
+ XArg, // 'X',
+ fArg, // 'f',
+ FArg, // 'F',
+ eArg, // 'e',
+ EArg, // 'E',
+ gArg, // 'g',
+ GArg, // 'G',
+ aArg, // 'a',
+ AArg, // 'A',
+ IntAsCharArg, // 'c'
+ CStrArg, // 's'
+ VoidPtrArg, // 'p'
+ OutIntPtrArg, // 'n'
+ PercentArg, // '%'
+ IntArgBeg = dArg,
+ IntArgEnd = iArg,
+ UIntArgBeg = oArg,
+ UIntArgEnd = XArg,
+ DoubleArgBeg = fArg,
+ DoubleArgEnd = AArg
+ };
+
+ ConversionSpecifier(Kind k) : kind(k) {}
+
+ bool isIntArg() const { return kind >= dArg && kind <= iArg; }
+ bool isUIntArg() const { return kind >= oArg && kind <= XArg; }
+ bool isDoubleArg() const { return kind >= fArg && kind <= AArg; }
+ Kind getKind() const { return kind; }
+
+private:
+ const Kind kind;
+};
+
+enum LengthModifier {
+ None,
+ AsChar, // 'hh'
+ AsShort, // 'h'
+ AsLong, // 'l'
+ AsLongLong, // 'll'
+ AsIntMax, // 'j'
+ AsSizeT, // 'z'
+ AsPtrDiff, // 't'
+ AsLongDouble // 'L'
+};
+
+enum Flags {
+ LeftJustified = 0x1,
+ PlusPrefix = 0x2,
+ SpacePrefix = 0x4,
+ AlternativeForm = 0x8,
+ LeadingZeroes = 0x16
+};
+
+class OptionalAmount {
+public:
+ enum HowSpecified { NotSpecified, Constant, Arg };
+
+ OptionalAmount(HowSpecified h = NotSpecified) : hs(h), amt(0) {}
+ OptionalAmount(unsigned i) : hs(Constant), amt(i) {}
+
+ HowSpecified getHowSpecified() const { return hs; }
+
+ unsigned getConstantAmount() const {
+ assert(hs == Constant);
+ return amt;
+ }
+
+ unsigned getArgumentsConsumed() {
+ return hs == Arg ? 1 : 0;
+ }
+
+private:
+ HowSpecified hs;
+ unsigned amt;
+};
+
+class FormatSpecifier {
+ unsigned conversionSpecifier : 6;
+ unsigned lengthModifier : 5;
+ unsigned flags : 5;
+ OptionalAmount FieldWidth;
+ OptionalAmount Precision;
+public:
+ FormatSpecifier() : conversionSpecifier(0), lengthModifier(0), flags(0) {}
+
+ static FormatSpecifier Parse(const char *beg, const char *end);
+
+ // Methods for incrementally constructing the FormatSpecifier.
+ void setConversionSpecifier(ConversionSpecifier cs) {
+ conversionSpecifier = (unsigned) cs.getKind();
+ }
+ void setLengthModifier(LengthModifier lm) {
+ lengthModifier = (unsigned) lm;
+ }
+ void setIsLeftJustified() { flags |= LeftJustified; }
+ void setHasPlusPrefix() { flags |= PlusPrefix; }
+ void setHasSpacePrefix() { flags |= SpacePrefix; }
+ void setHasAlternativeForm() { flags |= AlternativeForm; }
+ void setHasLeadingZeros() { flags |= LeadingZeroes; }
+
+ // Methods for querying the format specifier.
+
+ ConversionSpecifier getConversionSpecifier() const {
+ return (ConversionSpecifier::Kind) conversionSpecifier;
+ }
+
+ LengthModifier getLengthModifier() const {
+ return (LengthModifier) lengthModifier;
+ }
+
+ void setFieldWidth(const OptionalAmount &Amt) {
+ FieldWidth = Amt;
+ }
+
+ void setPrecision(const OptionalAmount &Amt) {
+ Precision = Amt;
+ }
+
+ bool isLeftJustified() const { return flags & LeftJustified; }
+ bool hasPlusPrefix() const { return flags & PlusPrefix; }
+ bool hasAlternativeForm() const { return flags & AlternativeForm; }
+ bool hasLeadingZeros() const { return flags & LeadingZeroes; }
+};
+
+
+class FormatStringHandler {
+public:
+ FormatStringHandler() {}
+ virtual ~FormatStringHandler();
+
+ virtual void HandleIncompleteFormatSpecifier(const char *startSpecifier,
+ const char *endSpecifier) {}
+
+ virtual void HandleNullChar(const char *nullCharacter) {}
+
+ virtual void HandleIncompletePrecision(const char *periodChar) {}
+
+ virtual void HandleInvalidConversionSpecifier(const char *conversionChar) {}
+
+ virtual void HandleFormatSpecifier(const FormatSpecifier &FS,
+ const char *startSpecifier,
+ const char *endSpecifier) {}
+};
+
+bool ParseFormatString(FormatStringHandler &H,
+ const char *beg, const char *end);
+
+
+} // end printf namespace
+} // end clang namespace
+#endif
--- /dev/null
+//= PrintfFormatStrings.cpp - Analysis of printf format strings --*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Handling of format string in printf and friends. The structure of format
+// strings for fprintf() are described in C99 7.19.6.1.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/PrintfFormatString.h"
+
+using namespace clang;
+using namespace printf;
+
+namespace {
+class FormatSpecifierResult {
+ FormatSpecifier FS;
+ const char *Start;
+ bool HasError;
+public:
+ FormatSpecifierResult(bool err = false)
+ : Start(0), HasError(err) {}
+ FormatSpecifierResult(const char *start,
+ const printf::FormatSpecifier &fs)
+ : FS(fs), Start(start), HasError(false) {}
+
+
+ const char *getStart() const { return Start; }
+ bool hasError() const { return HasError; }
+ bool hasValue() const { return Start != 0; }
+ const FormatSpecifier &getValue() const {
+ assert(hasValue());
+ return FS;
+ }
+ const printf::FormatSpecifier &getValue() { return FS; }
+};
+} // end anonymous namespace
+
+template <typename T>
+class UpdateOnReturn {
+ T &ValueToUpdate;
+ const T &ValueToCopy;
+public:
+ UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
+ : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
+
+ ~UpdateOnReturn() {
+ ValueToUpdate = ValueToCopy;
+ }
+};
+
+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;
+ accumulator += (accumulator * 10) + (c - '0');
+ continue;
+ }
+
+ if (foundDigits)
+ return OptionalAmount(accumulator);
+
+ if (c == '*')
+ return OptionalAmount(OptionalAmount::Arg);
+
+ break;
+ }
+
+ return OptionalAmount();
+}
+
+static FormatSpecifierResult ParseFormatSpecifier(printf::FormatStringHandler &H,
+ const char *&Beg, const char *E) {
+
+ const char *I = Beg;
+ const char *Start = NULL;
+ UpdateOnReturn <const char*> UpdateBeg(Beg, I);
+
+ // Look for a '%' character that indicates the start of a format specifier.
+ while (I != E) {
+ char c = *I;
+ ++I;
+ if (c == '\0') {
+ // Detect spurious null characters, which are likely errors.
+ H.HandleNullChar(I);
+ return true;
+ }
+ if (c == '%') {
+ Start = I; // Record the start of the format specifier.
+ break;
+ }
+ }
+
+ // No format specifier found?
+ if (!Start)
+ return false;
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E);
+ return true;
+ }
+
+ FormatSpecifier FS;
+
+ // Look for flags (if any).
+ bool hasMore = true;
+ for ( ; I != E; ++I) {
+ switch (*I) {
+ default: hasMore = false; break;
+ case '-': FS.setIsLeftJustified(); break;
+ case '+': FS.setHasPlusPrefix(); break;
+ case ' ': FS.setHasSpacePrefix(); break;
+ case '#': FS.setHasAlternativeForm(); break;
+ case '0': FS.setHasLeadingZeros(); break;
+ }
+ if (!hasMore)
+ break;
+ }
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E);
+ return true;
+ }
+
+ // Look for the field width (if any).
+ FS.setFieldWidth(ParseAmount(I, E));
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E);
+ return true;
+ }
+
+ // Look for the precision (if any).
+ if (*I == '.') {
+ const char *startPrecision = I++;
+ if (I == E) {
+ H.HandleIncompletePrecision(I - 1);
+ return true;
+ }
+
+ FS.setPrecision(ParseAmount(I, E));
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompletePrecision(startPrecision);
+ return true;
+ }
+ }
+
+ // Look for the length modifier.
+ LengthModifier lm = None;
+ switch (*I) {
+ default:
+ break;
+ case 'h':
+ ++I;
+ lm = (I != E && *I == 'h') ? ++I, AsChar : AsShort;
+ break;
+ case 'l':
+ ++I;
+ lm = (I != E && *I == 'l') ? ++I, AsLongLong : AsLong;
+ break;
+ case 'j': lm = AsIntMax; ++I; break;
+ case 'z': lm = AsSizeT; ++I; break;
+ case 't': lm = AsPtrDiff; ++I; break;
+ case 'L': lm = AsLongDouble; ++I; break;
+ }
+ FS.setLengthModifier(lm);
+
+ if (I == E) {
+ // No more characters left?
+ H.HandleIncompleteFormatSpecifier(Start, E);
+ return true;
+ }
+
+ // Finally, look for the conversion specifier.
+ ConversionSpecifier::Kind cs;
+ switch (*I) {
+ default:
+ H.HandleInvalidConversionSpecifier(I);
+ return true;
+ case 'd' : cs = ConversionSpecifier::dArg; break;
+ case 'i' : cs = ConversionSpecifier::iArg; break;
+ case 'o' : cs = ConversionSpecifier::oArg; break;
+ case 'u' : cs = ConversionSpecifier::uArg; break;
+ case 'x' : cs = ConversionSpecifier::xArg; break;
+ case 'X' : cs = ConversionSpecifier::XArg; break;
+ case 'f' : cs = ConversionSpecifier::fArg; break;
+ case 'F' : cs = ConversionSpecifier::FArg; break;
+ case 'e' : cs = ConversionSpecifier::eArg; break;
+ case 'E' : cs = ConversionSpecifier::EArg; break;
+ case 'g' : cs = ConversionSpecifier::gArg; break;
+ case 'G' : cs = ConversionSpecifier::GArg; break;
+ case 'a' : cs = ConversionSpecifier::aArg; break;
+ case 'A' : cs = ConversionSpecifier::AArg; break;
+ case 'c' : cs = ConversionSpecifier::IntAsCharArg; break;
+ case 's' : cs = ConversionSpecifier::CStrArg; break;
+ case 'p' : cs = ConversionSpecifier::VoidPtrArg; break;
+ case 'n' : cs = ConversionSpecifier::OutIntPtrArg; break;
+ case '%' : cs = ConversionSpecifier::PercentArg; break;
+ }
+ FS.setConversionSpecifier(cs);
+ return FormatSpecifierResult(Start, FS);
+}
+
+bool ParseFormatSring(FormatStringHandler &H, const char *I, const char *E) {
+ // Keep looking for a format specifier until we have exhausted the string.
+ while (I != E) {
+ const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E);
+ // Did an error of any kind occur when parsing the specifier? If so,
+ // don't do any more processing.
+ if (FSR.hasError())
+ return true;;
+ // Done processing the string?
+ if (!FSR.hasValue())
+ break;
+ // We have a format specifier. Pass it to the callback.
+ H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(), I);
+ }
+ assert(I == E && "Format string not exhausted");
+ return false;
+}
+
+FormatStringHandler::~FormatStringHandler() {}