From: Jordan Rose Date: Wed, 31 Oct 2012 16:44:55 +0000 (+0000) Subject: [analyzer] Let ConstraintManager subclasses provide a more efficient checkNull. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c45bb4dcb648cd8b5250492afe7df254e4157aaa;p=clang [analyzer] Let ConstraintManager subclasses provide a more efficient checkNull. Previously, every call to a ConstraintManager's isNull would do a full assumeDual to test feasibility. Now, ConstraintManagers can override checkNull if they have a cheaper way to do the same thing. RangeConstraintManager can do this in less than half the work. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167138 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h index adb4d3ac16..9af59e4b38 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -16,6 +16,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "llvm/Support/SaveAndRestore.h" namespace llvm { class APSInt; @@ -97,8 +98,12 @@ public: virtual void EndPath(ProgramStateRef state) {} /// Convenience method to query the state to see if a symbol is null or - /// not null, or neither assumption can be made. - ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym); + /// not null, or if neither assumption can be made. + ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym) { + llvm::SaveAndRestore DisableNotify(NotifyAssumeClients, false); + + return checkNull(State, Sym); + } protected: /// A flag to indicate that clients should be notified of assumptions. @@ -115,6 +120,10 @@ protected: /// ExprEngine to determine if the value should be replaced with a /// conjured symbolic value in order to recover some precision. virtual bool canReasonAbout(SVal X) const = 0; + + /// Returns whether or not a symbol is known to be null ("true"), known to be + /// non-null ("false"), or may be either ("underconstrained"). + virtual ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym); }; ConstraintManager* CreateRangeConstraintManager(ProgramStateManager& statemgr, diff --git a/lib/StaticAnalyzer/Core/ConstraintManager.cpp b/lib/StaticAnalyzer/Core/ConstraintManager.cpp index 5dd1392bde..4dec526005 100644 --- a/lib/StaticAnalyzer/Core/ConstraintManager.cpp +++ b/lib/StaticAnalyzer/Core/ConstraintManager.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" -#include "llvm/Support/SaveAndRestore.h" using namespace clang; using namespace ento; @@ -26,13 +25,8 @@ static DefinedSVal getLocFromSymbol(const ProgramStateRef &State, return loc::MemRegionVal(R); } -/// Convenience method to query the state to see if a symbol is null or -/// not null, or neither assumption can be made. -ConditionTruthVal ConstraintManager::isNull(ProgramStateRef State, - SymbolRef Sym) { - // Disable recursive notification of clients. - llvm::SaveAndRestore DisableNotify(NotifyAssumeClients, false); - +ConditionTruthVal ConstraintManager::checkNull(ProgramStateRef State, + SymbolRef Sym) { QualType Ty = Sym->getType(); DefinedSVal V = Loc::isLocType(Ty) ? getLocFromSymbol(State, Sym) : nonloc::SymbolVal(Sym); diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index a4c841eb6b..467abd0837 100644 --- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -324,6 +324,7 @@ public: const llvm::APSInt& Adjustment); const llvm::APSInt* getSymVal(ProgramStateRef St, SymbolRef sym) const; + ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym); ProgramStateRef removeDeadBindings(ProgramStateRef St, SymbolReaper& SymReaper); @@ -347,6 +348,30 @@ const llvm::APSInt* RangeConstraintManager::getSymVal(ProgramStateRef St, return T ? T->getConcreteValue() : NULL; } +ConditionTruthVal RangeConstraintManager::checkNull(ProgramStateRef State, + SymbolRef Sym) { + const RangeSet *Ranges = State->get(Sym); + + // If we don't have any information about this symbol, it's underconstrained. + if (!Ranges) + return ConditionTruthVal(); + + // If we have a concrete value, see if it's zero. + if (const llvm::APSInt *Value = Ranges->getConcreteValue()) + return *Value == 0; + + BasicValueFactory &BV = getBasicVals(); + APSIntType IntType = BV.getAPSIntType(Sym->getType()); + llvm::APSInt Zero = IntType.getZeroValue(); + + // Check if zero is in the set of possible values. + if (Ranges->Intersect(BV, F, Zero, Zero).isEmpty()) + return false; + + // Zero is a possible value, but it is not the /only/ possible value. + return ConditionTruthVal(); +} + /// Scan all symbols referenced by the constraints. If the symbol is not alive /// as marked in LSymbols, mark it as dead in DSymbols. ProgramStateRef