Repository navigation
verify: Verify records through references, as pointers never null or reseated - #70
Open
SwayamInSync wants to merge 92 commits into
Open
SwayamInSync wants to merge 92 commits into
SwayamInSync wants to merge 92 commits into
Conversation
…e a goal's assumptions come from.
…alizing a module.
…om in the architecture.
…ded integer quantifiers in the prelude.
…the address passed to a callee.
…reseated, and members named whole in modifies as their bytes.
… at most 4096 integers.
… verdict and not an abort.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A reference to a record was an error, so the free-function form of a method on an object could not be verified. On the base:
Now a
Counter &(orconst Counter &), as a parameter or a local, is a pointer to its object that is never null and never reseated:Stacked on #69 (B3a-3 of extras plan item B3a; B3a-1 #50 and B3a-2 #53 are merged).
Design
modifies cis every field of the objectcreferences andmodifies c`none field. Here a reference to a record gets exactly what 3b gives a pointer to a record:c.f,c.buf[i],c.inner.xare cells, each access with its array-index check and its object check, and&c.fandc.bufare subobject pointers with bounds.cppverify::modifies(c)is the object,cppverify::modifies(c.n)one cell.getRecordFromTypelooked through references, a remnant of a design that would have flattenedC&intoparam.fieldvalues. It now stops at them, so source variables (c [ssa=c_0]in counterexamples), type-invariant injection, parameter lists, and call arguments treat a reference as the address it is. A record's type invariant is not injected for a reference, as for a pointer.recordReferenceRootfinds the reference parameter or local a selection chain starts at, andinPointeeObject(it, orpointeeRootPointer) replacespointeeRootPointerwherever a place through a pointer is admitted: loads, stores, subscripts, reference bindings, footprints, pointer-difference operands.objectPlaceof a bare reference is the place at its address, as*p.VFunction::ReferenceParamsdecided that every reference'smodifies(r)is one cell, which is right for a scalar reference (it may bind a field of a larger object) and wrong for a record, whose cell then had no logic sort (obligation lowering failed: frame (invalid sort in obligation IR)at a call). The set is nowScalarReferenceParams; a record reference's footprint is a region, its entry object, as*p.cppverify::modifies(p->left), for a member that is a record or array, was one cell holding the whole member, through a pointer as well: no store lies in it, so a function writingp->left.nfailedframe, and so didreset(&p->left).convertFootprintnow lowers a record or array named whole inside an object (p->inner,c.buf,p[k]of a record extent) to a range of one element of its size, so every frame path (own stores, call havoc, containment, loop frames) treats it as its bytes.*pand a bare reference stay regions.Counter &r = p->left;,= a[i],= other_ref, chained, inside loops) and may bind a promoted local record, whose reads and writes keep their lifetime and initialization checks through the reference's provenance companion. A pointer formed through such a reference (&r.n,r.buf) would not carry the local's lifetime, sosubobjectPointerRootadmits pointer formation only through a pointer or a reference whose object outlives the function (a parameter, or a local not bound to represented storage), and the existing&localand decay errors apply otherwise.What stays out (fail-closed)
Unresolved [construct.unsupported]; the message now says "the address of local or dynamic storage is passed to bump" (it said "a pointer to", wrong for a reference). This is B3a-4, next.modifies(p.left.n, p.left.limit)does not containreset(p.left)'s footprint. Documented and tested.volatilereferences, references in spec and proof functions.Tests
suite/record_references.cpp: Z3, BMC, and a VCR dump.constreferences,&cof a whole reference passed to a pointer callee, references passed on from a reference,*p,p.left; two mutable references disjoint (frame(c, c)failsaliasing),aliaseshonored (may_aliasfails its postcondition with distinct objects), twoconstreferences may alias;modifies(c)verified, a store outsidemodifies(c.n)failsframe, a callee's whole object outside the caller's cell failsframe(reference and member), the fields-one-by-one case;left_only) and a pointer (right_only), and their VCR (range 8/1);r.buf[r.head], an index past the array failsbounds, a decayed member passed to a buffer callee,&r.headand one past it (bounds);*p,p->left, chained,a[i]in a loop, one past an extent (dereference), a local record (verified and an uninitialized field read failinginitialization);construct.unsupported, with the message),&r.headandr.bufthrough a reference to a local, a whole-record read, a proof function's reference, rvalue and volatile references.references_unsupported.cppno longer expectsPair &to be rejected.Mutants, each built and run on
record_references.cppand the 13 reference, subobject, and record-layout tests beside it: 12 of 12 killed, all byrecord_references.cpp. A thirteenth, acceptingvolatile Counter &, survived because the explicitvolatilecheck was dead (the pointer type check already rejects a volatile pointee); that check, and an equally unreachable collection check (Sema keeps collections out of executable code, and spec and proof functions take no references), are removed.record_referencesrecord_referencesrecord_referencesrecord_referencesrecord_referencesrecord_referencesgetRecordFromTypesees through references (the base)record_referencesrecord_referencesrecord_referencesrecord_referencesrecord_referencesrecord_referencesThe member mutant on its own reproduces the base for pointers:
left_only(Pair *p)undermodifies(p->left)failsframeatreset(&p->left), and its caller endsUnresolved: obligation lowering failed: caller (invalid sort in obligation IR).Docs
reset_countfailsframe), what is not yet supported; type invariants not injected for references.cppverify::modifies" (failures that were not real).Checked
docs_examples.testincluded, pass.record_references.cppon the base: every function taking aCounter &is an error.--no-check-ub,--int-encoding=bitvector, and a Lean export give the same verdicts or export.