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();
78 llvm::SMTExprRef SMTConstraints =
83 while ((++RangeIt) !=
Range.end()) {
84 SMTConstraints = RefutationSolver->mkOr(
86 RangeIt->From(), RangeIt->To(),
90 RefutationSolver->addConstraint(SMTConstraints);
93 auto GetUsedRLimit = [](
const llvm::SMTSolverRef &Solver) {
94 return Solver->getStatistics()->getUnsigned(
"rlimit count");
97 auto AttemptOnce = [&](
const llvm::SMTSolverRef &Solver) ->
Z3Result {
98 auto getCurrentTime = llvm::TimeRecord::getCurrentTime;
99 unsigned InitialRLimit = GetUsedRLimit(Solver);
100 double Start = getCurrentTime(
true).getWallTime();
101 std::optional<bool> IsSAT = Solver->check();
102 double End = getCurrentTime(
false).getWallTime();
105 static_cast<unsigned>((End - Start) * 1000),
106 GetUsedRLimit(Solver) - InitialRLimit,
111 unsigned MinQueryTimeAcrossAttempts = std::numeric_limits<unsigned>::max();
112 for (
unsigned I = 0; I < Opts.Z3CrosscheckMaxAttemptsPerQuery; ++I) {
113 Result = AttemptOnce(RefutationSolver);
114 Result.Z3QueryTimeMilliseconds =
115 std::min(MinQueryTimeAcrossAttempts, Result.Z3QueryTimeMilliseconds);
116 if (Result.IsSAT.has_value())
121void Z3CrosscheckVisitor::addConstraints(
122 const ExplodedNode *N,
bool OverwriteConstraintsOnExistingSyms) {
128 for (
auto const &[Sym,
Range] : NewCs) {
129 if (!Constraints.contains(Sym)) {
131 Constraints =
CF.add(Constraints, Sym,
Range);
132 }
else if (OverwriteConstraintsOnExistingSyms) {
134 Constraints =
CF.remove(Constraints, Sym);
135 Constraints =
CF.add(Constraints, Sym,
Range);
143 addConstraints(N,
false);
160 ++NumTimesZ3QueryAcceptsReport;
165 if (Opts.Z3CrosscheckTimeoutThreshold &&
167 ++NumTimesZ3TimedOut;
168 ++NumTimesZ3QueryRejectEQClass;
172 if (Opts.Z3CrosscheckRLimitThreshold &&
173 Query.
UsedRLimit >= Opts.Z3CrosscheckRLimitThreshold) {
174 ++NumTimesZ3ExhaustedRLimit;
175 ++NumTimesZ3QueryRejectEQClass;
179 if (Opts.Z3CrosscheckEQClassTimeoutThreshold &&
180 AccumulatedZ3QueryTimeInEqClass >
181 Opts.Z3CrosscheckEQClassTimeoutThreshold) {
182 ++NumTimesZ3SpendsTooMuchTimeOnASingleEQClass;
183 ++NumTimesZ3QueryRejectEQClass;
189 ++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 std::optional< 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:
void finalizeVisitor(const ExplodedNode *EndPathNode, BugReporterContext &BRC, PathSensitiveBugReport &BR) override
Last function called on the visitor, no further calls to VisitNode would follow.
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)
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