diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 19 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp | 38 |
2 files changed, 48 insertions, 9 deletions
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 36dc45b..6e47b37 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1260,6 +1260,25 @@ static void initOption(AnalyzerOptions::ConfigTable &Config, << Name << "an unsigned"; } +static void initOption(AnalyzerOptions::ConfigTable &Config, + DiagnosticsEngine *Diags, + PositiveAnalyzerOption &OptionField, StringRef Name, + unsigned DefaultVal) { + auto Parsed = PositiveAnalyzerOption::create( + getStringOption(Config, Name, std::to_string(DefaultVal))); + if (Parsed.has_value()) { + OptionField = Parsed.value(); + return; + } + if (Diags && !Parsed.has_value()) + Diags->Report(diag::err_analyzer_config_invalid_input) + << Name << "a positive"; + + auto Default = PositiveAnalyzerOption::create(DefaultVal); + assert(Default.has_value()); + OptionField = Default.value(); +} + static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts, DiagnosticsEngine *Diags) { // TODO: There's no need to store the entire configtable, it'd be plenty diff --git a/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp b/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp index 739db95..c4dd016 100644 --- a/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp +++ b/clang/lib/StaticAnalyzer/Core/Z3CrosscheckVisitor.cpp @@ -21,6 +21,10 @@ #define DEBUG_TYPE "Z3CrosscheckOracle" +// Queries attempted at most `Z3CrosscheckMaxAttemptsPerQuery` number of times. +// Multiple `check()` calls might be called on the same query if previous +// attempts of the same query resulted in UNSAT for any reason. Each query is +// only counted once for these statistics, the retries are not accounted for. STATISTIC(NumZ3QueriesDone, "Number of Z3 queries done"); STATISTIC(NumTimesZ3TimedOut, "Number of times Z3 query timed out"); STATISTIC(NumTimesZ3ExhaustedRLimit, @@ -77,16 +81,32 @@ void Z3CrosscheckVisitor::finalizeVisitor(BugReporterContext &BRC, RefutationSolver->addConstraint(SMTConstraints); } - // And check for satisfiability - llvm::TimeRecord Start = llvm::TimeRecord::getCurrentTime(/*Start=*/true); - std::optional<bool> IsSAT = RefutationSolver->check(); - llvm::TimeRecord Diff = llvm::TimeRecord::getCurrentTime(/*Start=*/false); - Diff -= Start; - Result = Z3Result{ - IsSAT, - static_cast<unsigned>(Diff.getWallTime() * 1000), - RefutationSolver->getStatistics()->getUnsigned("rlimit count"), + auto GetUsedRLimit = [](const llvm::SMTSolverRef &Solver) { + return Solver->getStatistics()->getUnsigned("rlimit count"); + }; + + auto AttemptOnce = [&](const llvm::SMTSolverRef &Solver) -> Z3Result { + constexpr auto getCurrentTime = llvm::TimeRecord::getCurrentTime; + unsigned InitialRLimit = GetUsedRLimit(Solver); + double Start = getCurrentTime(/*Start=*/true).getWallTime(); + std::optional<bool> IsSAT = Solver->check(); + double End = getCurrentTime(/*Start=*/false).getWallTime(); + return { + IsSAT, + static_cast<unsigned>((End - Start) * 1000), + GetUsedRLimit(Solver) - InitialRLimit, + }; }; + + // And check for satisfiability + unsigned MinQueryTimeAcrossAttempts = std::numeric_limits<unsigned>::max(); + for (unsigned I = 0; I < Opts.Z3CrosscheckMaxAttemptsPerQuery; ++I) { + Result = AttemptOnce(RefutationSolver); + Result.Z3QueryTimeMilliseconds = + std::min(MinQueryTimeAcrossAttempts, Result.Z3QueryTimeMilliseconds); + if (Result.IsSAT.has_value()) + return; + } } void Z3CrosscheckVisitor::addConstraints( |