clang API Documentation

ConstraintManager.h
Go to the documentation of this file.
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