clang API Documentation
00001 //== ConstraintManager.h - Constraints on symbolic values.-------*- C++ -*--==// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defined the interface to manage constraints on symbolic values. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H 00015 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H 00016 00017 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 00018 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" 00019 #include "llvm/Support/SaveAndRestore.h" 00020 00021 namespace llvm { 00022 class APSInt; 00023 } 00024 00025 namespace clang { 00026 namespace ento { 00027 00028 class SubEngine; 00029 00030 class ConditionTruthVal { 00031 Optional<bool> Val; 00032 public: 00033 /// Construct a ConditionTruthVal indicating the constraint is constrained 00034 /// to either true or false, depending on the boolean value provided. 00035 ConditionTruthVal(bool constraint) : Val(constraint) {} 00036 00037 /// Construct a ConstraintVal indicating the constraint is underconstrained. 00038 ConditionTruthVal() {} 00039 00040 /// Return true if the constraint is perfectly constrained to 'true'. 00041 bool isConstrainedTrue() const { 00042 return Val.hasValue() && Val.getValue(); 00043 } 00044 00045 /// Return true if the constraint is perfectly constrained to 'false'. 00046 bool isConstrainedFalse() const { 00047 return Val.hasValue() && !Val.getValue(); 00048 } 00049 00050 /// Return true if the constrained is perfectly constrained. 00051 bool isConstrained() const { 00052 return Val.hasValue(); 00053 } 00054 00055 /// Return true if the constrained is underconstrained and we do not know 00056 /// if the constraint is true of value. 00057 bool isUnderconstrained() const { 00058 return !Val.hasValue(); 00059 } 00060 }; 00061 00062 class ConstraintManager { 00063 public: 00064 ConstraintManager() : NotifyAssumeClients(true) {} 00065 00066 virtual ~ConstraintManager(); 00067 virtual ProgramStateRef assume(ProgramStateRef state, 00068 DefinedSVal Cond, 00069 bool Assumption) = 0; 00070 00071 typedef std::pair<ProgramStateRef, ProgramStateRef> ProgramStatePair; 00072 00073 /// Returns a pair of states (StTrue, StFalse) where the given condition is 00074 /// assumed to be true or false, respectively. 00075 ProgramStatePair assumeDual(ProgramStateRef State, DefinedSVal Cond) { 00076 ProgramStateRef StTrue = assume(State, Cond, true); 00077 00078 // If StTrue is infeasible, asserting the falseness of Cond is unnecessary 00079 // because the existing constraints already establish this. 00080 if (!StTrue) { 00081 #ifndef __OPTIMIZE__ 00082 // This check is expensive and should be disabled even in Release+Asserts 00083 // builds. 00084 // FIXME: __OPTIMIZE__ is a GNU extension that Clang implements but MSVC 00085 // does not. Is there a good equivalent there? 00086 assert(assume(State, Cond, false) && "System is over constrained."); 00087 #endif 00088 return ProgramStatePair((ProgramStateRef)nullptr, State); 00089 } 00090 00091 ProgramStateRef StFalse = assume(State, Cond, false); 00092 if (!StFalse) { 00093 // We are careful to return the original state, /not/ StTrue, 00094 // because we want to avoid having callers generate a new node 00095 // in the ExplodedGraph. 00096 return ProgramStatePair(State, (ProgramStateRef)nullptr); 00097 } 00098 00099 return ProgramStatePair(StTrue, StFalse); 00100 } 00101 00102 /// \brief If a symbol is perfectly constrained to a constant, attempt 00103 /// to return the concrete value. 00104 /// 00105 /// Note that a ConstraintManager is not obligated to return a concretized 00106 /// value for a symbol, even if it is perfectly constrained. 00107 virtual const llvm::APSInt* getSymVal(ProgramStateRef state, 00108 SymbolRef sym) const { 00109 return nullptr; 00110 } 00111 00112 virtual ProgramStateRef removeDeadBindings(ProgramStateRef state, 00113 SymbolReaper& SymReaper) = 0; 00114 00115 virtual void print(ProgramStateRef state, 00116 raw_ostream &Out, 00117 const char* nl, 00118 const char *sep) = 0; 00119 00120 virtual void EndPath(ProgramStateRef state) {} 00121 00122 /// Convenience method to query the state to see if a symbol is null or 00123 /// not null, or if neither assumption can be made. 00124 ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym) { 00125 SaveAndRestore<bool> DisableNotify(NotifyAssumeClients, false); 00126 00127 return checkNull(State, Sym); 00128 } 00129 00130 protected: 00131 /// A flag to indicate that clients should be notified of assumptions. 00132 /// By default this is the case, but sometimes this needs to be restricted 00133 /// to avoid infinite recursions within the ConstraintManager. 00134 /// 00135 /// Note that this flag allows the ConstraintManager to be re-entrant, 00136 /// but not thread-safe. 00137 bool NotifyAssumeClients; 00138 00139 /// canReasonAbout - Not all ConstraintManagers can accurately reason about 00140 /// all SVal values. This method returns true if the ConstraintManager can 00141 /// reasonably handle a given SVal value. This is typically queried by 00142 /// ExprEngine to determine if the value should be replaced with a 00143 /// conjured symbolic value in order to recover some precision. 00144 virtual bool canReasonAbout(SVal X) const = 0; 00145 00146 /// Returns whether or not a symbol is known to be null ("true"), known to be 00147 /// non-null ("false"), or may be either ("underconstrained"). 00148 virtual ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym); 00149 }; 00150 00151 std::unique_ptr<ConstraintManager> 00152 CreateRangeConstraintManager(ProgramStateManager &statemgr, 00153 SubEngine *subengine); 00154 00155 } // end GR namespace 00156 00157 } // end clang namespace 00158 00159 #endif