19#include "llvm/Support/SMTAPI.h"
20#include "llvm/Support/Timer.h"
22#define DEBUG_TYPE "Z3CrosscheckOracle"
29STAT_COUNTER(NumTimesZ3TimedOut,
"Number of times Z3 query timed out");
31 "Number of times Z3 query exhausted the rlimit");
33 NumTimesZ3SpendsTooMuchTimeOnASingleEQClass,
34 "Number of times report equivalenece class was cut because it spent "
35 "too much time in Z3");
38 "Number of Z3 queries accepting a report");
40 "Number of Z3 queries rejecting a report");
42 "Number of times rejecting an report equivalenece class");
45 "Total time spent solving Z3 queries excluding retries");
47 "Max time spent solving a Z3 query excluding retries");
54 : Constraints(
ConstraintMap::Factory().getEmptyMap()), Result(Result),
61 addConstraints(EndPathNode,
true);
64 llvm::SMTSolverRef RefutationSolver = llvm::CreateZ3Solver();
65 if (Opts.Z3CrosscheckRLimitThreshold)
66 RefutationSolver->setUnsignedParam(
"rlimit",
67 Opts.Z3CrosscheckRLimitThreshold);
68 if (Opts.Z3CrosscheckTimeoutThreshold)
69 RefutationSolver->setUnsignedParam(
"timeout",
70 Opts.Z3CrosscheckTimeoutThreshold);
75 for (
const auto &[Sym,
Range] : Constraints) {
76 auto RangeIt =
Range.begin();
79 RefutationSolver, Ctx, Sym, RangeIt->From(), RangeIt->To(),
81 while ((++RangeIt) !=
Range.end()) {
82 SMTConstraints = RefutationSolver->mkOr(
84 RangeIt->From(), RangeIt->To(),
87 RefutationSolver->addConstraint(SMTConstraints);
90 auto GetUsedRLimit = [](
const llvm::SMTSolverRef &Solver) {
91 return Solver->getStatistics()->getUnsigned(
"rlimit count");
94 auto AttemptOnce = [&](
const llvm::SMTSolverRef &Solver) ->
Z3Result {
95 auto getCurrentTime = llvm::TimeRecord::getCurrentTime;
96 unsigned InitialRLimit = GetUsedRLimit(Solver);
97 double Start = getCurrentTime(
true).getWallTime();
98 std::optional<bool> IsSAT = Solver->check();
99 double End = getCurrentTime(
false).getWallTime();
102 static_cast<unsigned>((End - Start) * 1000),
103 GetUsedRLimit(Solver) - InitialRLimit,
108 unsigned MinQueryTimeAcrossAttempts = std::numeric_limits<unsigned>::max();
109 for (
unsigned I = 0; I < Opts.Z3CrosscheckMaxAttemptsPerQuery; ++I) {
110 Result = AttemptOnce(RefutationSolver);
113 if (Result.
IsSAT.has_value())
118void Z3CrosscheckVisitor::addConstraints(
119 const ExplodedNode *N,
bool OverwriteConstraintsOnExistingSyms) {
125 for (
auto const &[Sym,
Range] : NewCs) {
126 if (!Constraints.contains(Sym)) {
128 Constraints =
CF.add(Constraints, Sym,
Range);
129 }
else if (OverwriteConstraintsOnExistingSyms) {
131 Constraints =
CF.remove(Constraints, Sym);
132 Constraints =
CF.add(Constraints, Sym,
Range);
140 addConstraints(N,
false);
157 ++NumTimesZ3QueryAcceptsReport;
162 if (Opts.Z3CrosscheckTimeoutThreshold &&
164 ++NumTimesZ3TimedOut;
165 ++NumTimesZ3QueryRejectEQClass;
169 if (Opts.Z3CrosscheckRLimitThreshold &&
170 Query.
UsedRLimit >= Opts.Z3CrosscheckRLimitThreshold) {
171 ++NumTimesZ3ExhaustedRLimit;
172 ++NumTimesZ3QueryRejectEQClass;
176 if (Opts.Z3CrosscheckEQClassTimeoutThreshold &&
177 AccumulatedZ3QueryTimeInEqClass >
178 Opts.Z3CrosscheckEQClassTimeoutThreshold) {
179 ++NumTimesZ3SpendsTooMuchTimeOnASingleEQClass;
180 ++NumTimesZ3QueryRejectEQClass;
186 ++NumTimesZ3QueryRejectReport;
#define STAT_COUNTER(VARNAME, DESC)
#define STAT_MAX(VARNAME, DESC)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Stores options for the analyzer from the command line.
ASTContext & getASTContext() const
const ProgramStateRef & getState() const
A Range represents the closed range [from, to].
static llvm::SMTExprRef getRangeExpr(llvm::SMTSolverRef &Solver, ASTContext &Ctx, SymbolRef Sym, const llvm::APSInt &From, const llvm::APSInt &To, bool InRange)
Z3Decision interpretQueryResult(const Z3CrosscheckVisitor::Z3Result &Meta)
Updates the internal state with the new Z3Result and makes a decision how to proceed:
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Return a diagnostic piece which should be associated with the given node.
void Profile(llvm::FoldingSetNodeID &ID) const override
Z3CrosscheckVisitor(Z3CrosscheckVisitor::Z3Result &Result, const AnalyzerOptions &Opts)
void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode, PathSensitiveBugReport &BR) override
Last function called on the visitor, no further calls to VisitNode would follow.
llvm::ImmutableMap< SymbolRef, RangeSet > ConstraintMap
@ CF
Indicates that the tracked object is a CF object.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
ConstraintMap getConstraintMap(ProgramStateRef State)
The JSON file list parser is used to communicate input to InstallAPI.
unsigned Z3QueryTimeMilliseconds
std::optional< bool > IsSAT