ROSE  0.11.31.0
BinarySmtSolver.h
1 #ifndef Rose_BinaryAnalysis_SmtSolver_H
2 #define Rose_BinaryAnalysis_SmtSolver_H
3 #include <featureTests.h>
4 #ifdef ROSE_ENABLE_BINARY_ANALYSIS
5 
6 #ifndef __STDC_FORMAT_MACROS
7 #define __STDC_FORMAT_MACROS
8 #endif
9 
10 #include <BinarySymbolicExpr.h>
11 #include <boost/chrono.hpp>
12 #include <boost/lexical_cast.hpp>
13 #include <boost/noncopyable.hpp>
14 #include <boost/serialization/access.hpp>
15 #include <boost/thread/mutex.hpp>
16 #include <boost/unordered_map.hpp>
17 #include <inttypes.h>
18 
19 namespace Rose {
20 namespace BinaryAnalysis {
21 
23 using SmtSolverPtr = std::shared_ptr<class SmtSolver>;
24 
26 public:
27  bool operator()(const SymbolicExpr::LeafPtr&, const SymbolicExpr::LeafPtr&) const;
28 };
29 
34 class SmtSolver: private boost::noncopyable {
35 public:
37  using Ptr = SmtSolverPtr;
38 
40  typedef std::map<std::string, bool> Availability;
41 
43  enum LinkMode {
44  LM_NONE = 0x0000,
45  LM_LIBRARY = 0x0001,
46  LM_EXECUTABLE = 0x0002,
47  LM_ANY = 0x0003,
48  };
49 
55  enum Type { NO_TYPE, BOOLEAN, BIT_VECTOR, MEM_STATE };
56 
58  typedef std::pair<std::string, Type> StringTypePair;
60 
63 
65  struct Exception: std::runtime_error {
66  Exception(const std::string &mesg): std::runtime_error(mesg) {}
67  ~Exception() throw () {}
68  };
69 
72  ParseError(const std::pair<size_t /*line*/, size_t /*col*/> &loc, const std::string &mesg)
73  : Exception("input line " + boost::lexical_cast<std::string>(loc.first+1) +
74  " column " + boost::lexical_cast<std::string>(loc.second+1) + ": " + mesg) {}
75  ~ParseError() throw () {}
76  };
77 
79  enum Satisfiable { SAT_NO=0,
82  };
83 
88  struct Stats {
89  size_t ncalls;
90  size_t input_size;
91  size_t output_size;
92  size_t memoizationHits;
93  size_t nSolversCreated;
95  double prepareTime;
96  double solveTime;
97  double evidenceTime;
98  size_t nSatisfied;
99  size_t nUnsatisfied;
100  size_t nUnknown;
101  // Remember to add all data members to resetStatistics()
102 
103  Stats()
104  : ncalls(0), input_size(0), output_size(0), memoizationHits(0), nSolversCreated(0), nSolversDestroyed(0),
105  prepareTime(0.0), solveTime(0.0), evidenceTime(0.0), nSatisfied(0), nUnsatisfied(0), nUnknown(0) {
106  }
107  };
108 
121  class Transaction {
122  SmtSolver::Ptr solver_;
123  size_t nLevels_;
124  bool committed_;
125  public:
130  : solver_(solver), committed_(false) {
131  if (solver) {
132  nLevels_ = solver->nLevels();
133  solver->push();
134  } else {
135  nLevels_ = 0;
136  }
137  }
138 
141  if (solver_ && !committed_) {
142  ASSERT_require2(solver_->nLevels() > nLevels_, "something popped this transaction already");
143  while (solver_->nLevels() > nLevels_) {
144  if (solver_->nLevels() > 1) {
145  solver_->pop();
146  } else {
147  solver_->reset();
148  }
149  }
150  }
151  }
152 
154  void commit(bool b = true) {
155  committed_ = b;
156  }
157 
159  bool isCommitted() const {
160  return committed_;
161  }
162 
165  return solver_;
166  }
167  };
168 
171 
172  typedef std::set<uint64_t> Definitions;
176  public:
178  private:
179  explicit SExpr(const std::string &content): content_(content) {}
180  std::string content_;
181  std::vector<Ptr> children_;
182  public:
183  static Ptr instance(const std::string &content); // leaf node
184  static Ptr instance(size_t); // integer leaf node
185  static Ptr instance(const Ptr &a = Ptr(), const Ptr &b = Ptr(), const Ptr &c = Ptr(), const Ptr &d = Ptr());
186 
187  const std::string name() const { return content_; }
188  const std::vector<Ptr>& children() const { return children_; }
189  std::vector<Ptr>& children() { return children_; }
190  void append(const std::vector<Ptr>&);
191  void print(std::ostream&) const;
192  };
193 
194  typedef std::pair<SExpr::Ptr, Type> SExprTypePair;
195 
196  typedef boost::unordered_map<SymbolicExpr::Hash, Satisfiable> Memoization;
197 
198 private:
199  std::string name_;
200  std::vector<std::vector<SymbolicExpr::Ptr> > stack_;
201  bool errorIfReset_;
202 
203 protected:
204  LinkMode linkage_;
205  std::string outputText_;
206  std::vector<SExpr::Ptr> parsedOutput_; // the evidence output
207  TermNames termNames_; // maps ROSE exprs to SMT exprs and their basic type
208  Memoization memoization_; // cached of previously computed results
209  bool doMemoization_; // use the memoization_ table?
210  SymbolicExpr::Hash latestMemoizationId_; // key for last found or inserted memoization, or zero
211  SymbolicExpr::ExprExprHashMap latestMemoizationRewrite_; // variables rewritten, need to be undone when parsing evidence
212 
213  // Statistics
214  static boost::mutex classStatsMutex;
215  static Stats classStats; // all access must be protected by classStatsMutex
216  Stats stats;
217 
218 public:
221 
222 private:
223 #ifdef ROSE_HAVE_BOOST_SERIALIZATION_LIB
224  friend class boost::serialization::access;
225 
226  template<class S>
227  void serialize(S &s, const unsigned /*version*/) {
228  s & BOOST_SERIALIZATION_NVP(name_);
229  s & BOOST_SERIALIZATION_NVP(stack_);
230  // linkage_ -- not serialized
231  // termNames_ -- not serialized
232  // outputText_ -- not serialized
233  // parsedOutput_ -- not serialized
234  // termNames_ -- not serialized
235  // memoization_ -- not serialized
236  // doMemoization_ -- not serialized
237  // latestMemoizationId_ -- not serialized
238  // latestMemoizationRewrite_ -- not serialized
239  // classStatsMutex -- not serialized
240  // classStats -- not serialized
241  // stats -- not serialized
242  // mlog -- not serialized
243  }
244 #endif
245 
246 protected:
255  SmtSolver(const std::string &name, unsigned linkages)
256  : name_(name), errorIfReset_(false), linkage_(LM_NONE), doMemoization_(true), latestMemoizationId_(0) {
257  init(linkages);
258  }
259 
260 public:
262  virtual Ptr create() const = 0;
263 
264  // Solvers are reference counted and should not be explicitly deleted.
265  virtual ~SmtSolver();
266 
267 
269  // Methods for creating solvers.
271 public:
272 
277  static Availability availability();
278 
285  static Ptr instance(const std::string &name);
286 
290  static Ptr bestAvailable();
291 
298  const std::string& name() const { return name_; }
299  void name(const std::string &s) { name_ = s; }
305  LinkMode linkage() const {
306  return linkage_;
307  }
308 
312  void requireLinkage(LinkMode) const;
313 
317  static LinkMode bestLinkage(unsigned linkages);
318 
324  bool memoization() const { return doMemoization_; }
325  void memoization(bool b) {
326  doMemoization_ = b;
327  if (!b)
329  }
334  return latestMemoizationId_;
335  }
336 
338  virtual void clearMemoization() {
339  memoization_.clear();
340  }
341 
343  virtual size_t memoizationNEntries() const {
344  return memoization_.size();
345  }
346 
350  virtual void timeout(boost::chrono::duration<double> seconds) = 0;
351 
352 
354  // High-level abstraction for testing satisfiability.
356 public:
357 
365  virtual Satisfiable triviallySatisfiable(const std::vector<SymbolicExpr::Ptr> &exprs);
366 
374  virtual Satisfiable satisfiable(const SymbolicExpr::Ptr&);
375  virtual Satisfiable satisfiable(const std::vector<SymbolicExpr::Ptr>&);
379  // Mid-level abstractions for testing satisfiaiblity.
382 public:
383 
388  virtual void reset();
389 
396  bool errorIfReset() const {
397  return errorIfReset_;
398  }
399  void errorIfReset(bool b) {
400  errorIfReset_ = b;
401  }
413  virtual void push();
414 
421  virtual void pop();
422 
427  virtual size_t nLevels() const { return stack_.size(); }
428 
432  virtual size_t nAssertions(size_t backtrackingLevel);
433 
435  virtual size_t nAssertions() const;
436 
442  virtual void insert(const SymbolicExpr::Ptr&);
443  virtual void insert(const std::vector<SymbolicExpr::Ptr>&);
449  virtual std::vector<SymbolicExpr::Ptr> assertions() const;
450 
455  virtual std::vector<SymbolicExpr::Ptr> assertions(size_t level) const;
456 
461  virtual Satisfiable check();
462 
468  virtual Satisfiable checkTrivial();
469 
470 
472  // High-level abstraction for solver results.
474 public:
475 
483  virtual std::vector<std::string> evidenceNames() {
484  return std::vector<std::string>();
485  }
486 
492  virtual SymbolicExpr::Ptr evidenceForName(const std::string&) {
493  return SymbolicExpr::Ptr();
494  }
495 
496 
498  // Mid-level abstraction for solver results.
500 public:
501 
507  virtual void clearEvidence();
508 
516  SymbolicExpr::LeafPtr ln = var->isLeafNode();
517  ASSERT_require(ln && ln->isVariable2());
518  return evidenceForVariable(ln->nameId());
519  }
520  virtual SymbolicExpr::Ptr evidenceForVariable(uint64_t varno) {
521  char buf[64];
522  snprintf(buf, sizeof buf, "v%" PRIu64, varno);
523  return evidenceForName(buf);
524  }
532  virtual SymbolicExpr::Ptr evidenceForAddress(uint64_t addr);
533 
534 
536  // Statistics
538 public:
539 
543  const Stats& statistics() const { return stats; }
544 
551  static Stats classStatistics();
552 
554  void resetStatistics();
555 
560  static void resetClassStatistics();
561 
562 
564  // Low-level API used in subclasses.
566 protected:
568  virtual Satisfiable checkExe();
569 
571  virtual Satisfiable checkLib();
572 
578  virtual std::string getErrorMessage(int exitStatus);
579 
581  virtual void findVariables(const SymbolicExpr::Ptr&, VariableSet&) {}
582 
587  static void printSExpression(std::ostream&, const SExpr::Ptr&);
588 
592  virtual void generateFile(std::ostream&, const std::vector<SymbolicExpr::Ptr> &exprs, Definitions*) = 0;
593 
596  virtual std::string getCommand(const std::string &config_name) = 0;
597 
599  std::vector<SExpr::Ptr> parseSExpressions(const std::string&);
600 
603  virtual void parseEvidence() {};
604 
611  static std::vector<SymbolicExpr::Ptr> normalizeVariables(const std::vector<SymbolicExpr::Ptr>&,
612  SymbolicExpr::ExprExprHashMap &index /*out*/);
613 
621  static std::vector<SymbolicExpr::Ptr> undoNormalization(const std::vector<SymbolicExpr::Ptr>&,
622  const SymbolicExpr::ExprExprHashMap &index);
623 
624 
626  // Miscellaneous
628 public:
630  virtual void selfTest();
631 
635  static void initDiagnostics();
636 
637 private:
638  void init(unsigned linkages); // Called during construction
639 
640 
641 
643  // Deprecated junk
645 
646  // FIXME[Robb Matzke 2017-10-17]: these are all deprecated
647 public:
648  virtual Satisfiable trivially_satisfiable(const std::vector<SymbolicExpr::Ptr> &exprs)
649  ROSE_DEPRECATED("use triviallySatisfiable");
650  virtual SymbolicExpr::Ptr evidence_for_variable(uint64_t varno) ROSE_DEPRECATED("use evidenceForVariable");
651  virtual SymbolicExpr::Ptr evidence_for_variable(const SymbolicExpr::Ptr &var) ROSE_DEPRECATED("use evidenceForVariable");
652  virtual SymbolicExpr::Ptr evidence_for_name(const std::string&) ROSE_DEPRECATED("use evidenceForName");
653  virtual SymbolicExpr::Ptr evidence_for_address(uint64_t addr) ROSE_DEPRECATED("use evidenceForAddress");
654  virtual std::vector<std::string> evidence_names() ROSE_DEPRECATED("use evidenceNames");
655  virtual void clear_evidence() ROSE_DEPRECATED("use clearEvidence");
656  const Stats& get_stats() const ROSE_DEPRECATED("use statistics");
657  static Stats get_class_stats() ROSE_DEPRECATED("use classStatistics");
658  void reset_stats() ROSE_DEPRECATED("use resetStatistics");
659  void reset_class_stats() ROSE_DEPRECATED("use resetClassStatistics");
660 protected:
661  virtual void generate_file(std::ostream&, const std::vector<SymbolicExpr::Ptr> &exprs, Definitions*)
662  ROSE_DEPRECATED("use generateFile");
663  virtual std::string get_command(const std::string &config_name) ROSE_DEPRECATED("use getCommand");
664  virtual void parse_evidence() ROSE_DEPRECATED("use parseEvidence");
665 };
666 
667 std::ostream& operator<<(std::ostream&, const SmtSolver::SExpr&);
668 
669 // FIXME[Robb Matzke 2017-10-17]: This typedef is deprecated. Use SmtSolver instead.
670 typedef SmtSolver SMTSolver;
671 
672 } // namespace
673 } // namespace
674 
675 #endif
676 #endif
virtual void push()
Create a backtracking point.
SmtSolverPtr Ptr
Reference counting pointer for SMT solvers.
bool isCommitted() const
Whether the guard is canceled.
Ordered set of values.
Definition: Set.h:52
Sawyer::SharedPointer< Node > Ptr
Shared-ownership pointer to an expression Node.
S-Expr parsed from SMT solver text output.
uint64_t Hash
Hash of symbolic expression.
virtual Satisfiable checkLib()
Check satisfiability using a library API.
virtual void clearEvidence()
Clears evidence information.
Satisfiable and evidence of satisfiability may be available.
virtual SymbolicExpr::Ptr evidenceForVariable(const SymbolicExpr::Ptr &var)
Evidence of satisfiability for a bitvector variable.
virtual SymbolicExpr::Ptr evidenceForName(const std::string &)
Evidence of satisfiability for a variable or memory address.
Mapping from expression to expression.
Collection of streams.
Definition: Message.h:1606
virtual void insert(const SymbolicExpr::Ptr &)
Insert assertions.
size_t nUnsatisfied
Number of times the solver returned "unsatisfied".
static void printSExpression(std::ostream &, const SExpr::Ptr &)
Print an S-Expr for debugging.
size_t ncalls
Number of times satisfiable() was called.
void requireLinkage(LinkMode) const
Assert required linkage.
virtual void timeout(boost::chrono::duration< double > seconds)=0
Set the timeout for the solver.
virtual void reset()
Reset solver state.
STL namespace.
std::string outputText_
Additional output obtained by satisfiable().
Small object support.
Definition: SmallObject.h:19
const std::string & name() const
Property: Name of solver for debugging.
LinkMode
Bit flags to indicate the kind of solver interface.
Main namespace for the ROSE library.
size_t nSolversCreated
Number of solvers created.
Sawyer::Container::Map< SymbolicExpr::Ptr, SymbolicExpr::Ptr > ExprExprMap
Maps one symbolic expression to another.
static Availability availability()
Availability of all known solvers.
std::set< uint64_t > Definitions
Free variables that have been defined.
Satisfiable
Satisfiability constants.
Sawyer::Container::Set< SymbolicExpr::LeafPtr, CompareLeavesByName > VariableSet
Set of variables.
Reference-counting intrusive smart pointer.
Definition: SharedPointer.h:68
virtual Satisfiable check()
Check satisfiability of current stack.
void resetStatistics()
Resets statistics for this solver.
static std::vector< SymbolicExpr::Ptr > normalizeVariables(const std::vector< SymbolicExpr::Ptr > &, SymbolicExpr::ExprExprHashMap &index)
Normalize expressions by renaming variables.
size_t nSatisfied
Number of times the solver returned "satisified".
double prepareTime
Time spent creating assertions before solving.
bool errorIfReset() const
Property: Throw an exception if the solver is reset.
virtual size_t nAssertions() const
Total number of assertions across all backtracking levels.
virtual size_t nLevels() const
Number of backtracking levels.
Exceptions for all things SMT related.
static void resetClassStatistics()
Resets statistics for the class.
std::map< std::string, bool > Availability
Solver availability map.
virtual Ptr create() const =0
Virtual constructor.
static Ptr bestAvailable()
Best available solver.
static Ptr instance(const std::string &name)
Allocate a new solver by name.
void name(const std::string &s)
Property: Name of solver for debugging.
virtual void findVariables(const SymbolicExpr::Ptr &, VariableSet &)
Return all variables that need declarations.
void errorIfReset(bool b)
Property: Throw an exception if the solver is reset.
SymbolicExpr::Hash latestMemoizationId() const
Id for latest memoized result, or zero.
virtual void generateFile(std::ostream &, const std::vector< SymbolicExpr::Ptr > &exprs, Definitions *)=0
Generates an input file for for the solver.
static void initDiagnostics()
Initialize diagnostic output facilities.
bool memoization() const
Property: Perform memoization.
virtual Satisfiable checkExe()
Check satisfiability using text files and an executable.
~Transaction()
Destructor pops level unless canceled.
void memoization(bool b)
Property: Perform memoization.
Exception for parse errors when reading SMT solver output.
SmtSolver(const std::string &name, unsigned linkages)
Construct with name and linkage.
virtual SymbolicExpr::Ptr evidenceForAddress(uint64_t addr)
Evidence of satisfiability for a memory address.
void commit(bool b=true)
Cancel the popping during the destructor.
virtual Satisfiable triviallySatisfiable(const std::vector< SymbolicExpr::Ptr > &exprs)
Determines if expressions are trivially satisfiable or unsatisfiable.
Transaction(const SmtSolver::Ptr &solver)
Constructor pushes level if solver is non-null.
virtual void selfTest()
Unit tests.
const Stats & statistics() const
Property: Statistics for this solver.
virtual Satisfiable checkTrivial()
Check whether the stack of assertions is trivially satisfiable.
virtual void clearMemoization()
Clear memoization table.
static std::vector< SymbolicExpr::Ptr > undoNormalization(const std::vector< SymbolicExpr::Ptr > &, const SymbolicExpr::ExprExprHashMap &index)
Undo the normalizations that were performed earlier.
Base class for reference counted objects.
Definition: SharedObject.h:64
A runtime library is available.
virtual void pop()
Pop a backtracking point.
Type
Type (sort) of expression.
size_t nSolversDestroyed
Number of solvers destroyed.
Could not be proved satisfiable or unsatisfiable.
SmtSolver::Ptr solver() const
Solver being protected.
virtual std::vector< SymbolicExpr::Ptr > assertions() const
All assertions.
double evidenceTime
Seconds to retrieve evidence of satisfiability.
virtual Satisfiable satisfiable(const SymbolicExpr::Ptr &)
Determines if the specified expressions are all satisfiable, unsatisfiable, or unknown.
double solveTime
Seconds spent in solver's solve function.
virtual std::vector< std::string > evidenceNames()
Names of items for which satisfiability evidence exists.
virtual std::string getCommand(const std::string &config_name)=0
Given the name of a configuration file, return the command that is needed to run the solver...
std::pair< std::string, Type > StringTypePair
Maps expression nodes to term names.
Interface to Satisfiability Modulo Theory (SMT) solvers.
size_t input_size
Bytes of input generated for satisfiable().
virtual size_t memoizationNEntries() const
Size of memoization table.
virtual void parseEvidence()
Parses evidence of satisfiability.
std::vector< SExpr::Ptr > parseSExpressions(const std::string &)
Parse all SExprs from the specified string.
static Stats classStatistics()
Property: Statistics across all solvers.
static LinkMode bestLinkage(unsigned linkages)
Given a bit vector of linkages, return the best one.
virtual SymbolicExpr::Ptr evidenceForVariable(uint64_t varno)
Evidence of satisfiability for a bitvector variable.
static Sawyer::Message::Facility mlog
Diagnostic facility.
size_t memoizationHits
Number of times memoization supplied a result.
std::shared_ptr< class SmtSolver > SmtSolverPtr
Reference-counting pointer for SMT solvers.
LinkMode linkage() const
Property: How ROSE communicates with the solver.
size_t nUnknown
Number of times the solver returned "unknown".
virtual std::string getErrorMessage(int exitStatus)
Error message from running a solver executable.
size_t output_size
Amount of output produced by the SMT solver.