Home | History | Annotate | Download | only in PathSensitive
      1 //== ConstraintManager.h - Constraints on symbolic values.-------*- C++ -*--==//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 //  This file defined the interface to manage constraints on symbolic values.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
     15 #define LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
     16 
     17 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
     18 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
     19 #include "llvm/Support/SaveAndRestore.h"
     20 
     21 namespace llvm {
     22 class APSInt;
     23 }
     24 
     25 namespace clang {
     26 namespace ento {
     27 
     28 class SubEngine;
     29 
     30 class ConditionTruthVal {
     31   Optional<bool> Val;
     32 public:
     33   /// Construct a ConditionTruthVal indicating the constraint is constrained
     34   /// to either true or false, depending on the boolean value provided.
     35   ConditionTruthVal(bool constraint) : Val(constraint) {}
     36 
     37   /// Construct a ConstraintVal indicating the constraint is underconstrained.
     38   ConditionTruthVal() {}
     39 
     40   /// Return true if the constraint is perfectly constrained to 'true'.
     41   bool isConstrainedTrue() const {
     42     return Val.hasValue() && Val.getValue();
     43   }
     44 
     45   /// Return true if the constraint is perfectly constrained to 'false'.
     46   bool isConstrainedFalse() const {
     47     return Val.hasValue() && !Val.getValue();
     48   }
     49 
     50   /// Return true if the constrained is perfectly constrained.
     51   bool isConstrained() const {
     52     return Val.hasValue();
     53   }
     54 
     55   /// Return true if the constrained is underconstrained and we do not know
     56   /// if the constraint is true of value.
     57   bool isUnderconstrained() const {
     58     return !Val.hasValue();
     59   }
     60 };
     61 
     62 class ConstraintManager {
     63 public:
     64   ConstraintManager() : NotifyAssumeClients(true) {}
     65 
     66   virtual ~ConstraintManager();
     67   virtual ProgramStateRef assume(ProgramStateRef state,
     68                                  DefinedSVal Cond,
     69                                  bool Assumption) = 0;
     70 
     71   typedef std::pair<ProgramStateRef, ProgramStateRef> ProgramStatePair;
     72 
     73   /// Returns a pair of states (StTrue, StFalse) where the given condition is
     74   /// assumed to be true or false, respectively.
     75   ProgramStatePair assumeDual(ProgramStateRef State, DefinedSVal Cond) {
     76     ProgramStateRef StTrue = assume(State, Cond, true);
     77 
     78     // If StTrue is infeasible, asserting the falseness of Cond is unnecessary
     79     // because the existing constraints already establish this.
     80     if (!StTrue) {
     81 #ifndef __OPTIMIZE__
     82       // This check is expensive and should be disabled even in Release+Asserts
     83       // builds.
     84       // FIXME: __OPTIMIZE__ is a GNU extension that Clang implements but MSVC
     85       // does not. Is there a good equivalent there?
     86       assert(assume(State, Cond, false) && "System is over constrained.");
     87 #endif
     88       return ProgramStatePair((ProgramStateRef)nullptr, State);
     89     }
     90 
     91     ProgramStateRef StFalse = assume(State, Cond, false);
     92     if (!StFalse) {
     93       // We are careful to return the original state, /not/ StTrue,
     94       // because we want to avoid having callers generate a new node
     95       // in the ExplodedGraph.
     96       return ProgramStatePair(State, (ProgramStateRef)nullptr);
     97     }
     98 
     99     return ProgramStatePair(StTrue, StFalse);
    100   }
    101 
    102   /// \brief If a symbol is perfectly constrained to a constant, attempt
    103   /// to return the concrete value.
    104   ///
    105   /// Note that a ConstraintManager is not obligated to return a concretized
    106   /// value for a symbol, even if it is perfectly constrained.
    107   virtual const llvm::APSInt* getSymVal(ProgramStateRef state,
    108                                         SymbolRef sym) const {
    109     return nullptr;
    110   }
    111 
    112   virtual ProgramStateRef removeDeadBindings(ProgramStateRef state,
    113                                                  SymbolReaper& SymReaper) = 0;
    114 
    115   virtual void print(ProgramStateRef state,
    116                      raw_ostream &Out,
    117                      const char* nl,
    118                      const char *sep) = 0;
    119 
    120   virtual void EndPath(ProgramStateRef state) {}
    121 
    122   /// Convenience method to query the state to see if a symbol is null or
    123   /// not null, or if neither assumption can be made.
    124   ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym) {
    125     SaveAndRestore<bool> DisableNotify(NotifyAssumeClients, false);
    126 
    127     return checkNull(State, Sym);
    128   }
    129 
    130 protected:
    131   /// A flag to indicate that clients should be notified of assumptions.
    132   /// By default this is the case, but sometimes this needs to be restricted
    133   /// to avoid infinite recursions within the ConstraintManager.
    134   ///
    135   /// Note that this flag allows the ConstraintManager to be re-entrant,
    136   /// but not thread-safe.
    137   bool NotifyAssumeClients;
    138 
    139   /// canReasonAbout - Not all ConstraintManagers can accurately reason about
    140   ///  all SVal values.  This method returns true if the ConstraintManager can
    141   ///  reasonably handle a given SVal value.  This is typically queried by
    142   ///  ExprEngine to determine if the value should be replaced with a
    143   ///  conjured symbolic value in order to recover some precision.
    144   virtual bool canReasonAbout(SVal X) const = 0;
    145 
    146   /// Returns whether or not a symbol is known to be null ("true"), known to be
    147   /// non-null ("false"), or may be either ("underconstrained").
    148   virtual ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym);
    149 };
    150 
    151 ConstraintManager* CreateRangeConstraintManager(ProgramStateManager& statemgr,
    152                                                 SubEngine *subengine);
    153 
    154 } // end GR namespace
    155 
    156 } // end clang namespace
    157 
    158 #endif
    159