Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
87c43ac
verify: Record the memory checks of contract expressions beside them …
SwayamInSync Oct 21, 2026
5d4a9f4
verify: Copy the recorded memory checks of contract expressions with …
SwayamInSync Oct 21, 2026
73882d9
verify: Keep the memory checks of pre- and postconditions through loo…
SwayamInSync Oct 21, 2026
4c64256
verify: Document the memory checks UB instrumentation records for con…
SwayamInSync Oct 21, 2026
b1d5370
verify: Record the memory checks of contracts, invariants, and assert…
SwayamInSync Oct 21, 2026
9b76d56
verify: Declare the check that a function's contract is defined.
SwayamInSync Oct 21, 2026
9596311
verify: Check each contract clause where it is evaluated, and postcon…
SwayamInSync Oct 21, 2026
47526f2
verify: Report an undefined contract and withhold it from callers.
SwayamInSync Oct 21, 2026
7dceac5
test: Check that contracts are defined where they are evaluated.
SwayamInSync Oct 21, 2026
ab9fa6d
test: Expect the bounds failure of a postcondition read past its object.
SwayamInSync Oct 21, 2026
d8a09e0
test: Declare the extents the quantifier range tests read.
SwayamInSync Oct 21, 2026
29d6739
docs: Describe the check that contracts are defined.
SwayamInSync Oct 21, 2026
d5c6473
docs: Note that contract reads are checked against extents.
SwayamInSync Oct 21, 2026
b17f29d
docs: Note that contracts get the definedness checks.
SwayamInSync Oct 21, 2026
6a75a2f
docs: Note that contracts get the mandatory definedness checks.
SwayamInSync Oct 21, 2026
22107e6
docs: Describe the contract check's label and obligation names.
SwayamInSync Oct 21, 2026
f744d0a
docs: Explain in chapter 18 that contracts must be defined.
SwayamInSync Oct 21, 2026
e30f7ee
docs: Note the contract definedness check in the release notes.
SwayamInSync Oct 21, 2026
059db39
docs: Describe contract well-formedness in the design.
SwayamInSync Oct 21, 2026
c851548
docs: Describe the contract well-formedness program in the architecture.
SwayamInSync Oct 21, 2026
e1f4207
docs: Describe how contracts get definedness checks.
SwayamInSync Oct 21, 2026
5f66e26
verify: Check a model a whole query finds on a slice of the budget wi…
SwayamInSync Oct 22, 2026
894b040
verify: Let the encoder tell a search slice from the query's whole time.
SwayamInSync Oct 22, 2026
6e5c8df
docs: Explain how a whole query on a slice checks the model it finds.
SwayamInSync Oct 22, 2026
217634e
test: Check the hypothesis names of a contract's check that it is def…
SwayamInSync Oct 22, 2026
17e505f
docs: Name the hypotheses of a contract's check that it is defined.
SwayamInSync Oct 22, 2026
ed5bce2
docs: Note how a contract's check labels what it assumes.
SwayamInSync Oct 22, 2026
d783134
test: Add a trusted contract with a check and its caller for the Lean…
SwayamInSync Oct 22, 2026
980876d
test: Add the proof of cppverify_reading_8d7035_division_by_zero_df06…
SwayamInSync Oct 22, 2026
b6c6b8d
test: Add the proof of cppverify_reading_8d7035_missing_return_54ae7c…
SwayamInSync Oct 22, 2026
1e041c9
test: Add the proof of cppverify_reading_8d7035_postcondition_54ae7c8…
SwayamInSync Oct 22, 2026
6494e28
test: Add the proof of cppverify_reading_8d7035_precondition_155ffe95…
SwayamInSync Oct 22, 2026
a88b942
test: Add the proof of cppverify_reading_8d7035_precondition_814bc5b2…
SwayamInSync Oct 22, 2026
9ed1977
test: Add the proof of cppverify_sensor_contract_eb6f5c_division_by_z…
SwayamInSync Oct 22, 2026
7651180
test: Check that a certified contract check establishes the contract …
SwayamInSync Oct 22, 2026
0e22bcc
docs: Say how a contract's check is exported and certified under Lean.
SwayamInSync Oct 22, 2026
2ea7fce
verify: Retry a whole query its slice leaves unresolved as a task of …
SwayamInSync Oct 22, 2026
1b8b599
docs: Explain how a racing whole query is retried beside the obligati…
SwayamInSync Oct 22, 2026
d2af395
verify: Declare the work a whole query may do and the cap on the obli…
SwayamInSync Oct 23, 2026
66cf8cb
verify: Bound the whole-query probe of a module without specs by solv…
SwayamInSync Oct 23, 2026
fc79b8d
docs: Explain why the whole query's probe is bounded by work, and wha…
SwayamInSync Oct 23, 2026
2f3e506
docs: Say that the probe of a complete query is a fixed amount of sol…
SwayamInSync Oct 23, 2026
6dbd097
docs: Note that a function's result no longer depends on the machine'…
SwayamInSync Oct 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 80 additions & 24 deletions clang/lib/Verify/Backend/Z3Encode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2733,6 +2733,9 @@ constexpr unsigned RefinementSliceMs = 500;
/// counterexample on a loaded machine.
constexpr unsigned HiddenSearchSliceMs = 2000;
constexpr unsigned HiddenRoundsBeforeNative = 8;
/// Resource units of the complete query of a module without specs before
/// its ordered obligations.
constexpr unsigned WholeProbeUnits = 6000000;
} // namespace

std::optional<VerifyResult> Z3Encoder::verifyNatively(
Expand Down Expand Up @@ -3011,7 +3014,8 @@ z3::check_result Z3Encoder::certifyModels(const ObligationModule &Module,
z3::model Current = Solver.get_model();
Z3CandidateModel Candidate(*this, Current);
CertifyLimits Limits;
Limits.Deadline = QueryDeadline;
if (!SearchSlice)
Limits.Deadline = QueryDeadline;
CertifyResult Certified = certifyModel(Candidate, Limits);
bool BoundedDomain = false;
if (Certified.Outcome == CertifyOutcome::Disputed && !Probed &&
Expand Down Expand Up @@ -3652,16 +3656,25 @@ bool Z3VerifyBackend::racesEncodings(const ObligationModule &Module) const {

VerifyResult Z3VerifyBackend::solveQuery(
const ObligationModule &Module, const LogicExpr *Query,
std::optional<uint64_t> TraceEventCount, unsigned Timeout, Race *Racing) {
std::optional<uint64_t> TraceEventCount, unsigned Timeout, Race *Racing,
bool Slice, unsigned Units) {
// Every query gets an encoder of its own. A Z3 context keeps the state of
// the queries solved in it, as far as an interrupted one got, and that
// state steers the search of the next: a query refuted in 5 ms timed out
// in 5 of 30 solves repeated in one context.
auto solve = [&](bool Facts, Race *Pair) {
Z3Encoder Encoder;
Encoder.setTimeoutMs(Timeout);
Encoder.setResourceLimit(ResourceLimit);
Encoder.setCertifyTimeoutMs(CertifyTimeoutMs);
unsigned Limit = ResourceLimit;
for (unsigned Cap : {UnitsCap, Units})
if (Cap && (!Limit || Cap < Limit))
Limit = Cap;
Encoder.setResourceLimit(Limit);
// A check gets the time a check of the module's queries gets.
Encoder.setCertifyTimeoutMs(Slice && !CertifyTimeoutMs
? std::optional<unsigned>(TimeoutMs / 2)
: CertifyTimeoutMs);
Encoder.setSearchSlice(Slice);
Encoder.setIntegerEncoding(IntegerEncoding);
Encoder.setProfileQuantifiers(ProfileQuantifiers && Facts);
Encoder.setSequenceFacts(Facts);
Expand Down Expand Up @@ -3893,19 +3906,26 @@ Z3VerifyBackend::verifyModuleDirect(const ObligationModule &Module) {
// can make it far harder than every ordered one (a ghost-sequence sum loop
// timed out whole after 30 s; its obligations take 0.2 s), so there it gets
// a sixth (at least 5 s) before them and the rest after. For spec-free
// programs, a short probe preserves the budget for the ordered obligations.
// programs, a probe of a fixed amount of work preserves the budget for the
// ordered obligations. Work, not time: a probe of 500 ms gave up under load
// and in an assertions build where an idle release build refuted the
// module, and the ordered obligations then ran to the timeout of one whose
// search does not end. WholeProbeUnits covers every probe of the test suite
// that a release build decided within 500 ms (the most took 5.2M units).
const unsigned ProbeUnits =
Module.LogicFunctions.empty() ? WholeProbeUnits : 0;
const bool OverCollections =
Module.RequiredFeatures & (logicFeature(LogicFeature::Sequences) |
logicFeature(LogicFeature::Collections));
const unsigned WholeBudget =
Module.LogicFunctions.empty()
? 500U
: (TimeoutMs == 0 || !OverCollections
? TimeoutMs
: std::max(TimeoutMs / 6, 5000U));
const unsigned WholeBudget = ProbeUnits || TimeoutMs == 0 || !OverCollections
? TimeoutMs
: std::max(TimeoutMs / 6, 5000U);
const bool WholeUsedFullBudget =
TimeoutMs == 0 ? !Module.LogicFunctions.empty()
: WholeBudget >= TimeoutMs;
!ProbeUnits && (TimeoutMs == 0 || WholeBudget >= TimeoutMs);
// A whole query on a slice of the budget still checks a model it finds:
// under load the search can take most of the slice, and the model, which
// settles the module, was then lost for want of time to check it.
const bool WholeSlice = !WholeUsedFullBudget && !ProbeUnits;
// With workers to spare, the obligations are solved one by one beside the
// whole query. Both are exact, so whichever settles the module first
// decides it and interrupts the other.
Expand All @@ -3927,25 +3947,57 @@ Z3VerifyBackend::verifyModuleDirect(const ObligationModule &Module) {
Ordered = Group->async([this, &Module, &Rivals, &WholeRace] {
std::vector<VerifyResult> Results =
verifyObligations(Module, /*StopAtFailure=*/true, &Rivals);
if (Results.size() == Module.Obligations.size() &&
llvm::all_of(Results, [](const VerifyResult &R) {
return R.Status == VerifyStatus::Verified;
}))
// The obligations settle the module when they prove all of it or one
// fails, and the whole query, or its retry, is then stopped.
if (llvm::any_of(Results,
[](const VerifyResult &R) {
return R.Status == VerifyStatus::Failed;
}) ||
(Results.size() == Module.Obligations.size() &&
llvm::all_of(Results, [](const VerifyResult &R) {
return R.Status == VerifyStatus::Verified;
})))
WholeRace.cancel();
return Results;
});
}
VerifyResult Whole;
VerifyResult Whole =
solveQuery(Module, nullptr, std::nullopt, WholeTimeout,
Racing ? &WholeRace : nullptr, WholeSlice, ProbeUnits);
// A probe that ran out of time, not work, had the full budget already.
const bool WholeHadFullBudget =
WholeUsedFullBudget ||
(ProbeUnits && Whole.Reason == VerifyReason::SolverTimeout);
auto retryable = [&](const VerifyResult &Result) {
return Result.Status == VerifyStatus::Unresolved && !WholeHadFullBudget &&
!SkipWholeModuleRetry && !spent();
};
bool RetriedWhole = false;
if (Racing) {
Whole = solveQuery(Module, nullptr, std::nullopt, WholeTimeout, &WholeRace);
// A whole query its probe or slice leaves unresolved is retried with the
// full budget as one more task of the race, after the obligations: a free
// worker runs it beside them, so that an obligation whose search does
// not end cannot hold it back; without one, it runs after them, as alone.
std::shared_future<VerifyResult> Retry;
if (retryable(Whole) && !WholeRace.Cancelled) {
RetriedWhole = true;
Retry = Group->async([this, &Module, &WholeRace, &Rivals] {
VerifyResult Result = solveQuery(Module, nullptr, std::nullopt,
budget(TimeoutMs), &WholeRace);
if (Result.Status == VerifyStatus::Verified ||
Result.Status == VerifyStatus::Failed)
Rivals.cancel();
return Result;
});
}
if (Whole.Status == VerifyStatus::Verified ||
Whole.Status == VerifyStatus::Failed)
Rivals.cancel();
Group->wait();
if (RetriedWhole)
Whole = Retry.get();
if (OwnPool)
Pool = nullptr;
} else {
Whole = solveQuery(Module, nullptr, std::nullopt, WholeTimeout, nullptr);
}
if (Whole.Status == VerifyStatus::Verified)
return finishZ3Result(std::move(Whole));
Expand All @@ -3957,9 +4009,13 @@ Z3VerifyBackend::verifyModuleDirect(const ObligationModule &Module) {
if (Whole.Status == VerifyStatus::Failed) {
// The complete query's counterexample is certified, so the obligations
// only choose the failure to report, within the complete query's budget,
// the same way with any number of jobs.
// its time and a probe's work, the same way with any number of jobs.
const unsigned FullTimeout = TimeoutMs;
llvm::scope_exit Restore([&] { TimeoutMs = FullTimeout; });
UnitsCap = ProbeUnits;
llvm::scope_exit Restore([&] {
TimeoutMs = FullTimeout;
UnitsCap = 0;
});
std::vector<VerifyResult> Results = verifyObligations(
Module, /*StopAtFailure=*/true, nullptr, WholeTimeout);
bool SawUnresolved = false;
Expand All @@ -3985,7 +4041,7 @@ Z3VerifyBackend::verifyModuleDirect(const ObligationModule &Module) {
}

auto retryWhole = [&](VerifyResult SplitResult) {
if (WholeUsedFullBudget || SkipWholeModuleRetry || spent())
if (RetriedWhole || !retryable(SplitResult))
return finishZ3Result(std::move(SplitResult));
VerifyResult Retry =
solveQuery(Module, nullptr, std::nullopt, budget(TimeoutMs), nullptr);
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/Verify/Backend/Z3Encode.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class Z3Encoder {
std::optional<uint64_t> TraceEventCount);
std::chrono::steady_clock::time_point QueryStart;
std::optional<unsigned> CertifyTimeoutMs;
bool SearchSlice = false;
bool QuantifiedQuery = false;
z3::solver freshSolver();
/// \p S.check() within \p Ms milliseconds (0: no limit), unknown at once
Expand Down Expand Up @@ -289,6 +290,9 @@ class Z3Encoder {
void setCertifyTimeoutMs(std::optional<unsigned> Ms) {
CertifyTimeoutMs = Ms;
}
/// The timeout is a slice of the query's time, for the search only: a model
/// found is checked with the check's own time, not what is left of it.
void setSearchSlice(bool Slice) { SearchSlice = Slice; }
/// Stops the check running in this encoder, from any thread.
void interrupt();
/// Lets checks run again after interrupt().
Expand Down Expand Up @@ -320,6 +324,9 @@ class Z3VerifyBackend : public VerifyBackend {
unsigned SolverTimeoutMs;
std::optional<unsigned> CollectionTimeoutMs;
unsigned ResourceLimit;
/// While the obligations only choose the failure to report, the work each
/// of their queries may do: the work the complete query's probe had, or 0.
unsigned UnitsCap = 0;
unsigned Jobs;
llvm::StdThreadPool *Pool;
uint64_t MaxQueryNodes;
Expand Down Expand Up @@ -362,7 +369,8 @@ class Z3VerifyBackend : public VerifyBackend {
VerifyResult solveQuery(const ObligationModule &Module,
const LogicExpr *Query,
std::optional<uint64_t> TraceEventCount,
unsigned Timeout, Race *Racing);
unsigned Timeout, Race *Racing, bool Slice = false,
unsigned Units = 0);
VerifyResult verifyObligation(const ObligationModule &Module,
const Obligation &Item,
llvm::StringRef SemanticHash = {},
Expand Down
Loading
Loading