diff options
Diffstat (limited to 'include/clang/Analysis')
-rw-r--r-- | include/clang/Analysis/Analyses/PrintfFormatString.h | 214 | ||||
-rw-r--r-- | include/clang/Analysis/Support/BumpVector.h | 1 | ||||
-rw-r--r-- | include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h | 62 |
3 files changed, 208 insertions, 69 deletions
diff --git a/include/clang/Analysis/Analyses/PrintfFormatString.h b/include/clang/Analysis/Analyses/PrintfFormatString.h index e4f7c57061d41..d907637d39c59 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 }; diff --git a/include/clang/Analysis/Support/BumpVector.h b/include/clang/Analysis/Support/BumpVector.h index c6c9eedcbf099..7cd481238f817 100644 --- a/include/clang/Analysis/Support/BumpVector.h +++ b/include/clang/Analysis/Support/BumpVector.h @@ -24,6 +24,7 @@ #include "llvm/ADT/PointerIntPair.h" #include <algorithm> #include <cstring> +#include <memory> namespace clang { diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h index d627b88967f2a..f20a49a6fcd83 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h @@ -22,13 +22,14 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" -#define DISPATCH_CASE(CASE,CLASS) \ -case Decl::CASE: \ -static_cast<ImplClass*>(this)->Visit##CLASS(static_cast<CLASS*>(D));\ +#define DISPATCH_CASE(CLASS) \ +case Decl::CLASS: \ +static_cast<ImplClass*>(this)->Visit##CLASS##Decl( \ + static_cast<CLASS##Decl*>(D)); \ break; -#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS(CLASS* D) {} -#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS(CLASS* D)\ +#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS##Decl(CLASS##Decl* D) {} +#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS##Decl(CLASS##Decl* D)\ { static_cast<ImplClass*>(this)->VisitVarDecl(D); } @@ -55,34 +56,39 @@ public: void VisitDecl(Decl* D) { switch (D->getKind()) { - DISPATCH_CASE(Function,FunctionDecl) - DISPATCH_CASE(CXXMethod,CXXMethodDecl) - DISPATCH_CASE(Var,VarDecl) - DISPATCH_CASE(ParmVar,ParmVarDecl) // FIXME: (same) - DISPATCH_CASE(ImplicitParam,ImplicitParamDecl) - DISPATCH_CASE(EnumConstant,EnumConstantDecl) - DISPATCH_CASE(Typedef,TypedefDecl) - DISPATCH_CASE(Record,RecordDecl) // FIXME: Refine. VisitStructDecl? - DISPATCH_CASE(Enum,EnumDecl) + DISPATCH_CASE(Function) + DISPATCH_CASE(CXXMethod) + DISPATCH_CASE(Var) + DISPATCH_CASE(ParmVar) // FIXME: (same) + DISPATCH_CASE(ImplicitParam) + DISPATCH_CASE(EnumConstant) + DISPATCH_CASE(Typedef) + DISPATCH_CASE(Record) // FIXME: Refine. VisitStructDecl? + DISPATCH_CASE(CXXRecord) + DISPATCH_CASE(Enum) default: assert(false && "Subtype of ScopedDecl not handled."); } } - DEFAULT_DISPATCH(VarDecl) - DEFAULT_DISPATCH(FunctionDecl) - DEFAULT_DISPATCH(CXXMethodDecl) - DEFAULT_DISPATCH_VARDECL(ParmVarDecl) - DEFAULT_DISPATCH(ImplicitParamDecl) - DEFAULT_DISPATCH(EnumConstantDecl) - DEFAULT_DISPATCH(TypedefDecl) - DEFAULT_DISPATCH(RecordDecl) - DEFAULT_DISPATCH(EnumDecl) - DEFAULT_DISPATCH(ObjCInterfaceDecl) - DEFAULT_DISPATCH(ObjCClassDecl) - DEFAULT_DISPATCH(ObjCMethodDecl) - DEFAULT_DISPATCH(ObjCProtocolDecl) - DEFAULT_DISPATCH(ObjCCategoryDecl) + DEFAULT_DISPATCH(Var) + DEFAULT_DISPATCH(Function) + DEFAULT_DISPATCH(CXXMethod) + DEFAULT_DISPATCH_VARDECL(ParmVar) + DEFAULT_DISPATCH(ImplicitParam) + DEFAULT_DISPATCH(EnumConstant) + DEFAULT_DISPATCH(Typedef) + DEFAULT_DISPATCH(Record) + DEFAULT_DISPATCH(Enum) + DEFAULT_DISPATCH(ObjCInterface) + DEFAULT_DISPATCH(ObjCClass) + DEFAULT_DISPATCH(ObjCMethod) + DEFAULT_DISPATCH(ObjCProtocol) + DEFAULT_DISPATCH(ObjCCategory) + + void VisitCXXRecordDecl(CXXRecordDecl *D) { + static_cast<ImplClass*>(this)->VisitRecordDecl(D); + } }; } // end namespace clang |