diff options
Diffstat (limited to 'include/clang/Analysis/Analyses/PrintfFormatString.h')
-rw-r--r-- | include/clang/Analysis/Analyses/PrintfFormatString.h | 214 |
1 files changed, 173 insertions, 41 deletions
diff --git a/include/clang/Analysis/Analyses/PrintfFormatString.h b/include/clang/Analysis/Analyses/PrintfFormatString.h index e4f7c57..d907637 100644 --- a/include/clang/Analysis/Analyses/PrintfFormatString.h +++ b/include/clang/Analysis/Analyses/PrintfFormatString.h @@ -25,8 +25,8 @@ namespace analyze_printf { class ArgTypeResult { public: - enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CStrTy, - WCStrTy }; + enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy, + CStrTy, WCStrTy }; private: const Kind K; QualType T; @@ -57,6 +57,7 @@ public: InvalidSpecifier = 0, // C99 conversion specifiers. dArg, // 'd' + IntAsCharArg, // 'c' iArg, // 'i', oArg, // 'o', uArg, // 'u', @@ -70,7 +71,6 @@ public: GArg, // 'G', aArg, // 'a', AArg, // 'A', - IntAsCharArg, // 'c' CStrArg, // 's' VoidPtrArg, // 'p' OutIntPtrArg, // 'n' @@ -124,45 +124,87 @@ public: bool isUIntArg() const { return kind >= oArg && kind <= XArg; } bool isDoubleArg() const { return kind >= fArg && kind <= AArg; } Kind getKind() const { return kind; } + void setKind(Kind k) { kind = k; } unsigned getLength() const { // Conversion specifiers currently only are represented by // single characters, but we be flexible. return 1; } + const char *toString() const; private: const char *Position; Kind kind; }; -enum LengthModifier { - None, - AsChar, // 'hh' - AsShort, // 'h' - AsLong, // 'l' - AsLongLong, // 'll', 'q' (BSD, deprecated) - AsIntMax, // 'j' - AsSizeT, // 'z' - AsPtrDiff, // 't' - AsLongDouble, // 'L' - AsWideChar = AsLong // for '%ls' +class LengthModifier { +public: + enum Kind { + None, + AsChar, // 'hh' + AsShort, // 'h' + AsLong, // 'l' + AsLongLong, // 'll', 'q' (BSD, deprecated) + AsIntMax, // 'j' + AsSizeT, // 'z' + AsPtrDiff, // 't' + AsLongDouble, // 'L' + AsWideChar = AsLong // for '%ls' + }; + + LengthModifier() + : Position(0), kind(None) {} + LengthModifier(const char *pos, Kind k) + : Position(pos), kind(k) {} + + const char *getStart() const { + return Position; + } + + unsigned getLength() const { + switch (kind) { + default: + return 1; + case AsLongLong: + case AsChar: + return 2; + case None: + return 0; + } + } + + Kind getKind() const { return kind; } + void setKind(Kind k) { kind = k; } + + const char *toString() const; + +private: + const char *Position; + Kind kind; }; class OptionalAmount { public: enum HowSpecified { NotSpecified, Constant, Arg, Invalid }; - OptionalAmount(HowSpecified h, unsigned i, const char *st) - : start(st), hs(h), amt(i) {} + OptionalAmount(HowSpecified howSpecified, + unsigned amount, + const char *amountStart, + unsigned amountLength, + bool usesPositionalArg) + : start(amountStart), length(amountLength), hs(howSpecified), amt(amount), + UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {} - OptionalAmount(bool b = true) - : start(0), hs(b ? NotSpecified : Invalid), amt(0) {} + OptionalAmount(bool valid = true) + : start(0),length(0), hs(valid ? NotSpecified : Invalid), amt(0), + UsesPositionalArg(0), UsesDotPrefix(0) {} bool isInvalid() const { return hs == Invalid; } HowSpecified getHowSpecified() const { return hs; } + void setHowSpecified(HowSpecified h) { hs = h; } bool hasDataArgument() const { return hs == Arg; } @@ -177,36 +219,87 @@ public: } const char *getStart() const { - return start; + // We include the . character if it is given. + return start - UsesDotPrefix; + } + + unsigned getConstantLength() const { + assert(hs == Constant); + return length + UsesDotPrefix; } ArgTypeResult getArgType(ASTContext &Ctx) const; + void toString(llvm::raw_ostream &os) const; + + bool usesPositionalArg() const { return (bool) UsesPositionalArg; } + unsigned getPositionalArgIndex() const { + assert(hasDataArgument()); + return amt + 1; + } + + bool usesDotPrefix() const { return UsesDotPrefix; } + void setUsesDotPrefix() { UsesDotPrefix = true; } + private: const char *start; + unsigned length; HowSpecified hs; unsigned amt; + bool UsesPositionalArg : 1; + bool UsesDotPrefix; +}; + +// Class representing optional flags with location and representation +// information. +class OptionalFlag { +public: + OptionalFlag(const char *Representation) + : representation(Representation), flag(false) {} + bool isSet() { return flag; } + void set() { flag = true; } + void clear() { flag = false; } + void setPosition(const char *position) { + assert(position); + this->position = position; + } + const char *getPosition() const { + assert(position); + return position; + } + const char *toString() const { return representation; } + + // Overloaded operators for bool like qualities + operator bool() const { return flag; } + OptionalFlag& operator=(const bool &rhs) { + flag = rhs; + return *this; // Return a reference to myself. + } +private: + const char *representation; + const char *position; + bool flag; }; class FormatSpecifier { LengthModifier LM; - unsigned IsLeftJustified : 1; - unsigned HasPlusPrefix : 1; - unsigned HasSpacePrefix : 1; - unsigned HasAlternativeForm : 1; - unsigned HasLeadingZeroes : 1; + OptionalFlag IsLeftJustified; // '-' + OptionalFlag HasPlusPrefix; // '+' + OptionalFlag HasSpacePrefix; // ' ' + OptionalFlag HasAlternativeForm; // '#' + OptionalFlag HasLeadingZeroes; // '0' /// Positional arguments, an IEEE extension: /// IEEE Std 1003.1, 2004 Edition /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html - unsigned UsesPositionalArg : 1; + bool UsesPositionalArg; unsigned argIndex; ConversionSpecifier CS; OptionalAmount FieldWidth; OptionalAmount Precision; public: - FormatSpecifier() : LM(None), - IsLeftJustified(0), HasPlusPrefix(0), HasSpacePrefix(0), - HasAlternativeForm(0), HasLeadingZeroes(0), UsesPositionalArg(0), + FormatSpecifier() : + IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "), + HasAlternativeForm("#"), HasLeadingZeroes("0"), UsesPositionalArg(false), argIndex(0) {} static FormatSpecifier Parse(const char *beg, const char *end); @@ -218,12 +311,27 @@ public: void setLengthModifier(LengthModifier lm) { LM = lm; } - void setIsLeftJustified() { IsLeftJustified = 1; } - void setHasPlusPrefix() { HasPlusPrefix = 1; } - void setHasSpacePrefix() { HasSpacePrefix = 1; } - void setHasAlternativeForm() { HasAlternativeForm = 1; } - void setHasLeadingZeros() { HasLeadingZeroes = 1; } - void setUsesPositionalArg() { UsesPositionalArg = 1; } + void setIsLeftJustified(const char *position) { + IsLeftJustified = true; + IsLeftJustified.setPosition(position); + } + void setHasPlusPrefix(const char *position) { + HasPlusPrefix = true; + HasPlusPrefix.setPosition(position); + } + void setHasSpacePrefix(const char *position) { + HasSpacePrefix = true; + HasSpacePrefix.setPosition(position); + } + void setHasAlternativeForm(const char *position) { + HasAlternativeForm = true; + HasAlternativeForm.setPosition(position); + } + void setHasLeadingZeros(const char *position) { + HasLeadingZeroes = true; + HasLeadingZeroes.setPosition(position); + } + void setUsesPositionalArg() { UsesPositionalArg = true; } void setArgIndex(unsigned i) { assert(CS.consumesDataArgument()); @@ -235,13 +343,18 @@ public: return argIndex; } + unsigned getPositionalArgIndex() const { + assert(CS.consumesDataArgument()); + return argIndex + 1; + } + // Methods for querying the format specifier. const ConversionSpecifier &getConversionSpecifier() const { return CS; } - LengthModifier getLengthModifier() const { + const LengthModifier &getLengthModifier() const { return LM; } @@ -255,6 +368,7 @@ public: void setPrecision(const OptionalAmount &Amt) { Precision = Amt; + Precision.setUsesDotPrefix(); } const OptionalAmount &getPrecision() const { @@ -268,12 +382,30 @@ public: /// more than one type. ArgTypeResult getArgType(ASTContext &Ctx) const; - bool isLeftJustified() const { return (bool) IsLeftJustified; } - bool hasPlusPrefix() const { return (bool) HasPlusPrefix; } - bool hasAlternativeForm() const { return (bool) HasAlternativeForm; } - bool hasLeadingZeros() const { return (bool) HasLeadingZeroes; } - bool hasSpacePrefix() const { return (bool) HasSpacePrefix; } - bool usesPositionalArg() const { return (bool) UsesPositionalArg; } + const OptionalFlag &isLeftJustified() const { return IsLeftJustified; } + const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; } + const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; } + const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; } + const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; } + bool usesPositionalArg() const { return UsesPositionalArg; } + + /// Changes the specifier and length according to a QualType, retaining any + /// flags or options. Returns true on success, or false when a conversion + /// was not successful. + bool fixType(QualType QT); + + void toString(llvm::raw_ostream &os) const; + + // Validation methods - to check if any element results in undefined behavior + bool hasValidPlusPrefix() const; + bool hasValidAlternativeForm() const; + bool hasValidLeadingZeros() const; + bool hasValidSpacePrefix() const; + bool hasValidLeftJustified() const; + + bool hasValidLengthModifier() const; + bool hasValidPrecision() const; + bool hasValidFieldWidth() const; }; enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 }; |