diff options
Diffstat (limited to 'include/clang/Analysis/Analyses')
-rw-r--r-- | include/clang/Analysis/Analyses/Consumed.h | 264 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/FormatString.h | 8 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/ThreadSafety.h | 4 | ||||
-rw-r--r-- | include/clang/Analysis/Analyses/UninitializedValues.h | 22 |
4 files changed, 293 insertions, 5 deletions
diff --git a/include/clang/Analysis/Analyses/Consumed.h b/include/clang/Analysis/Analyses/Consumed.h new file mode 100644 index 0000000..23a094a --- /dev/null +++ b/include/clang/Analysis/Analyses/Consumed.h @@ -0,0 +1,264 @@ +//===- Consumed.h ----------------------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A intra-procedural analysis for checking consumed properties. This is based, +// in part, on research on linear types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CONSUMED_H +#define LLVM_CLANG_CONSUMED_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtCXX.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/Analyses/PostOrderCFGView.h" +#include "clang/Basic/SourceLocation.h" + +namespace clang { +namespace consumed { + + enum ConsumedState { + // No state information for the given variable. + CS_None, + + CS_Unknown, + CS_Unconsumed, + CS_Consumed + }; + + class ConsumedStmtVisitor; + + typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes; + typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag; + typedef std::list<DelayedDiag> DiagList; + + class ConsumedWarningsHandlerBase { + + public: + + virtual ~ConsumedWarningsHandlerBase(); + + /// \brief Emit the warnings and notes left by the analysis. + virtual void emitDiagnostics() {} + + /// \brief Warn that a variable's state doesn't match at the entry and exit + /// of a loop. + /// + /// \param Loc -- The location of the end of the loop. + /// + /// \param VariableName -- The name of the variable that has a mismatched + /// state. + virtual void warnLoopStateMismatch(SourceLocation Loc, + StringRef VariableName) {} + + /// \brief Warn about parameter typestate mismatches upon return. + /// + /// \param Loc -- The SourceLocation of the return statement. + /// + /// \param ExpectedState -- The state the return value was expected to be + /// in. + /// + /// \param ObservedState -- The state the return value was observed to be + /// in. + virtual void warnParamReturnTypestateMismatch(SourceLocation Loc, + StringRef VariableName, + StringRef ExpectedState, + StringRef ObservedState) {}; + + // FIXME: Add documentation. + virtual void warnParamTypestateMismatch(SourceLocation LOC, + StringRef ExpectedState, + StringRef ObservedState) {} + + // FIXME: This can be removed when the attr propagation fix for templated + // classes lands. + /// \brief Warn about return typestates set for unconsumable types. + /// + /// \param Loc -- The location of the attributes. + /// + /// \param TypeName -- The name of the unconsumable type. + virtual void warnReturnTypestateForUnconsumableType(SourceLocation Loc, + StringRef TypeName) {} + + /// \brief Warn about return typestate mismatches. + /// + /// \param Loc -- The SourceLocation of the return statement. + /// + /// \param ExpectedState -- The state the return value was expected to be + /// in. + /// + /// \param ObservedState -- The state the return value was observed to be + /// in. + virtual void warnReturnTypestateMismatch(SourceLocation Loc, + StringRef ExpectedState, + StringRef ObservedState) {} + + /// \brief Warn about use-while-consumed errors. + /// \param MethodName -- The name of the method that was incorrectly + /// invoked. + /// + /// \param State -- The state the object was used in. + /// + /// \param Loc -- The SourceLocation of the method invocation. + virtual void warnUseOfTempInInvalidState(StringRef MethodName, + StringRef State, + SourceLocation Loc) {} + + /// \brief Warn about use-while-consumed errors. + /// \param MethodName -- The name of the method that was incorrectly + /// invoked. + /// + /// \param State -- The state the object was used in. + /// + /// \param VariableName -- The name of the variable that holds the unique + /// value. + /// + /// \param Loc -- The SourceLocation of the method invocation. + virtual void warnUseInInvalidState(StringRef MethodName, + StringRef VariableName, + StringRef State, + SourceLocation Loc) {} + }; + + class ConsumedStateMap { + + typedef llvm::DenseMap<const VarDecl *, ConsumedState> VarMapType; + typedef llvm::DenseMap<const CXXBindTemporaryExpr *, ConsumedState> + TmpMapType; + + protected: + + bool Reachable; + const Stmt *From; + VarMapType VarMap; + TmpMapType TmpMap; + + public: + ConsumedStateMap() : Reachable(true), From(NULL) {} + ConsumedStateMap(const ConsumedStateMap &Other) + : Reachable(Other.Reachable), From(Other.From), VarMap(Other.VarMap), + TmpMap() {} + + /// \brief Warn if any of the parameters being tracked are not in the state + /// they were declared to be in upon return from a function. + void checkParamsForReturnTypestate(SourceLocation BlameLoc, + ConsumedWarningsHandlerBase &WarningsHandler) const; + + /// \brief Clear the TmpMap. + void clearTemporaries(); + + /// \brief Get the consumed state of a given variable. + ConsumedState getState(const VarDecl *Var) const; + + /// \brief Get the consumed state of a given temporary value. + ConsumedState getState(const CXXBindTemporaryExpr *Tmp) const; + + /// \brief Merge this state map with another map. + void intersect(const ConsumedStateMap *Other); + + void intersectAtLoopHead(const CFGBlock *LoopHead, const CFGBlock *LoopBack, + const ConsumedStateMap *LoopBackStates, + ConsumedWarningsHandlerBase &WarningsHandler); + + /// \brief Return true if this block is reachable. + bool isReachable() const { return Reachable; } + + /// \brief Mark the block as unreachable. + void markUnreachable(); + + /// \brief Set the source for a decision about the branching of states. + /// \param Source -- The statement that was the origin of a branching + /// decision. + void setSource(const Stmt *Source) { this->From = Source; } + + /// \brief Set the consumed state of a given variable. + void setState(const VarDecl *Var, ConsumedState State); + + /// \brief Set the consumed state of a given temporary value. + void setState(const CXXBindTemporaryExpr *Tmp, ConsumedState State); + + /// \brief Remove the variable from our state map. + void remove(const VarDecl *Var); + + /// \brief Tests to see if there is a mismatch in the states stored in two + /// maps. + /// + /// \param Other -- The second map to compare against. + bool operator!=(const ConsumedStateMap *Other) const; + }; + + class ConsumedBlockInfo { + std::vector<ConsumedStateMap*> StateMapsArray; + std::vector<unsigned int> VisitOrder; + + public: + ConsumedBlockInfo() { } + + ConsumedBlockInfo(unsigned int NumBlocks, PostOrderCFGView *SortedGraph) + : StateMapsArray(NumBlocks, 0), VisitOrder(NumBlocks, 0) { + unsigned int VisitOrderCounter = 0; + for (PostOrderCFGView::iterator BI = SortedGraph->begin(), + BE = SortedGraph->end(); BI != BE; ++BI) { + VisitOrder[(*BI)->getBlockID()] = VisitOrderCounter++; + } + } + + bool allBackEdgesVisited(const CFGBlock *CurrBlock, + const CFGBlock *TargetBlock); + + void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap, + bool &AlreadyOwned); + void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap); + + ConsumedStateMap* borrowInfo(const CFGBlock *Block); + + void discardInfo(const CFGBlock *Block); + + ConsumedStateMap* getInfo(const CFGBlock *Block); + + bool isBackEdge(const CFGBlock *From, const CFGBlock *To); + bool isBackEdgeTarget(const CFGBlock *Block); + }; + + /// A class that handles the analysis of uniqueness violations. + class ConsumedAnalyzer { + + ConsumedBlockInfo BlockInfo; + ConsumedStateMap *CurrStates; + + ConsumedState ExpectedReturnState; + + void determineExpectedReturnState(AnalysisDeclContext &AC, + const FunctionDecl *D); + bool hasConsumableAttributes(const CXXRecordDecl *RD); + bool splitState(const CFGBlock *CurrBlock, + const ConsumedStmtVisitor &Visitor); + + public: + + ConsumedWarningsHandlerBase &WarningsHandler; + + ConsumedAnalyzer(ConsumedWarningsHandlerBase &WarningsHandler) + : WarningsHandler(WarningsHandler) {} + + ConsumedState getExpectedReturnState() const { return ExpectedReturnState; } + + /// \brief Check a function's CFG for consumed violations. + /// + /// We traverse the blocks in the CFG, keeping track of the state of each + /// value who's type has uniquness annotations. If methods are invoked in + /// the wrong state a warning is issued. Each block in the CFG is traversed + /// exactly once. + void run(AnalysisDeclContext &AC); + }; +}} // end namespace clang::consumed + +#endif diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h index 4bd989c..c9516b5 100644 --- a/include/clang/Analysis/Analyses/FormatString.h +++ b/include/clang/Analysis/Analyses/FormatString.h @@ -49,7 +49,7 @@ public: const char *toString() const { return representation; } // Overloaded operators for bool like qualities - operator bool() const { return flag; } + LLVM_EXPLICIT operator bool() const { return flag; } OptionalFlag& operator=(const bool &rhs) { flag = rhs; return *this; // Return a reference to myself. @@ -73,6 +73,9 @@ public: AsIntMax, // 'j' AsSizeT, // 'z' AsPtrDiff, // 't' + AsInt32, // 'I32' (MSVCRT, like __int32) + AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL) + AsInt64, // 'I64' (MSVCRT, like __int64) AsLongDouble, // 'L' AsAllocate, // for '%as', GNU extension to C90 scanf AsMAllocate, // for '%ms', GNU extension to scanf @@ -95,6 +98,9 @@ public: case AsLongLong: case AsChar: return 2; + case AsInt32: + case AsInt64: + return 3; case None: return 0; } diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h index 8a888e6..5def3dd 100644 --- a/include/clang/Analysis/Analyses/ThreadSafety.h +++ b/include/clang/Analysis/Analyses/ThreadSafety.h @@ -11,8 +11,8 @@ // A intra-procedural analysis for thread safety (e.g. deadlocks and race // conditions), based off of an annotation system. // -// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety for more -// information. +// See http://clang.llvm.org/docs/LanguageExtensions.html#thread-safety-annotation-checking +// for more information. // //===----------------------------------------------------------------------===// diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h index e8810c3..188722d 100644 --- a/include/clang/Analysis/Analyses/UninitializedValues.h +++ b/include/clang/Analysis/Analyses/UninitializedValues.h @@ -38,6 +38,12 @@ private: /// The expression which uses this variable. const Expr *User; + /// Is this use uninitialized whenever the function is called? + bool UninitAfterCall; + + /// Is this use uninitialized whenever the variable declaration is reached? + bool UninitAfterDecl; + /// Does this use always see an uninitialized value? bool AlwaysUninit; @@ -46,13 +52,17 @@ private: SmallVector<Branch, 2> UninitBranches; public: - UninitUse(const Expr *User, bool AlwaysUninit) : - User(User), AlwaysUninit(AlwaysUninit) {} + UninitUse(const Expr *User, bool AlwaysUninit) + : User(User), UninitAfterCall(false), UninitAfterDecl(false), + AlwaysUninit(AlwaysUninit) {} void addUninitBranch(Branch B) { UninitBranches.push_back(B); } + void setUninitAfterCall() { UninitAfterCall = true; } + void setUninitAfterDecl() { UninitAfterDecl = true; } + /// Get the expression containing the uninitialized use. const Expr *getUser() const { return User; } @@ -62,6 +72,12 @@ public: Maybe, /// The use is uninitialized whenever a certain branch is taken. Sometimes, + /// The use is uninitialized the first time it is reached after we reach + /// the variable's declaration. + AfterDecl, + /// The use is uninitialized the first time it is reached after the function + /// is called. + AfterCall, /// The use is always uninitialized. Always }; @@ -69,6 +85,8 @@ public: /// Get the kind of uninitialized use. Kind getKind() const { return AlwaysUninit ? Always : + UninitAfterCall ? AfterCall : + UninitAfterDecl ? AfterDecl : !branch_empty() ? Sometimes : Maybe; } |