18#include "llvm/ADT/Statistic.h"
19#include "llvm/Support/SMTAPI.h"
20#include "llvm/Support/Timer.h"
22#define DEBUG_TYPE "Z3CrosscheckOracle"
28STATISTIC(NumZ3QueriesDone,
"Number of Z3 queries done");
29STATISTIC(NumTimesZ3TimedOut,
"Number of times Z3 query timed out");
31 "Number of times Z3 query exhausted the rlimit");
32STATISTIC(NumTimesZ3SpendsTooMuchTimeOnASingleEQClass,
33 "Number of times report equivalenece class was cut because it spent "
34 "too much time in Z3");
37 "Number of Z3 queries accepting a report");
39 "Number of Z3 queries rejecting a report");
41 "Number of times rejecting an report equivalenece class");
48 : Constraints(
ConstraintMap::Factory().getEmptyMap()), Result(Result),
55 addConstraints(EndPathNode,
true);
58 llvm::SMTSolverRef RefutationSolver = llvm::CreateZ3Solver();
59 if (Opts.Z3CrosscheckRLimitThreshold)
60 RefutationSolver->setUnsignedParam(
"rlimit",
61 Opts.Z3CrosscheckRLimitThreshold);
62 if (Opts.Z3CrosscheckTimeoutThreshold)
63 RefutationSolver->setUnsignedParam(
"timeout",
64 Opts.Z3CrosscheckTimeoutThreshold);
69 for (
const auto &[Sym,
Range] : Constraints) {
70 auto RangeIt =
Range.begin();
73 RefutationSolver, Ctx, Sym, RangeIt->From(), RangeIt->To(),
75 while ((++RangeIt) !=
Range.end()) {
76 SMTConstraints = RefutationSolver->mkOr(
78 RangeIt->From(), RangeIt->To(),
81 RefutationSolver->addConstraint(SMTConstraints);
84 auto GetUsedRLimit = [](
const llvm::SMTSolverRef &Solver) {
85 return Solver->getStatistics()->getUnsigned(
"rlimit count");
88 auto AttemptOnce = [&](
const llvm::SMTSolverRef &Solver) ->
Z3Result {
89 constexpr auto getCurrentTime = llvm::TimeRecord::getCurrentTime;
90 unsigned InitialRLimit = GetUsedRLimit(Solver);
91 double Start = getCurrentTime(
true).getWallTime();
92 std::optional<bool> IsSAT = Solver->check();
93 double End = getCurrentTime(
false).getWallTime();
96 static_cast<unsigned>((End - Start) * 1000),
97 GetUsedRLimit(Solver) - InitialRLimit,
102 unsigned MinQueryTimeAcrossAttempts = std::numeric_limits<unsigned>::max();
103 for (
unsigned I = 0; I < Opts.Z3CrosscheckMaxAttemptsPerQuery; ++I) {
104 Result = AttemptOnce(RefutationSolver);
107 if (Result.
IsSAT.has_value())
112void Z3CrosscheckVisitor::addConstraints(
113 const ExplodedNode *N,
bool OverwriteConstraintsOnExistingSyms) {
119 for (
auto const &[Sym,
Range] : NewCs) {
120 if (!Constraints.contains(Sym)) {
122 Constraints =
CF.add(Constraints, Sym,
Range);
123 }
else if (OverwriteConstraintsOnExistingSyms) {
125 Constraints =
CF.remove(Constraints, Sym);
126 Constraints =
CF.add(Constraints, Sym,
Range);
134 addConstraints(N,
false);
149 ++NumTimesZ3QueryAcceptsReport;
154 if (Opts.Z3CrosscheckTimeoutThreshold &&
156 ++NumTimesZ3TimedOut;
157 ++NumTimesZ3QueryRejectEQClass;
161 if (Opts.Z3CrosscheckRLimitThreshold &&
162 Query.
UsedRLimit >= Opts.Z3CrosscheckRLimitThreshold) {
163 ++NumTimesZ3ExhaustedRLimit;
164 ++NumTimesZ3QueryRejectEQClass;
168 if (Opts.Z3CrosscheckEQClassTimeoutThreshold &&
169 AccumulatedZ3QueryTimeInEqClass >
170 Opts.Z3CrosscheckEQClassTimeoutThreshold) {
171 ++NumTimesZ3SpendsTooMuchTimeOnASingleEQClass;
172 ++NumTimesZ3QueryRejectEQClass;
178 ++NumTimesZ3QueryRejectReport;
STATISTIC(NumZ3QueriesDone, "Number of Z3 queries done")
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