Repository navigation
B3-2: constructors, verified on their caller's storage and run where objects are defined - #76
Merged
Merged
Conversation
…r does not represent.
…the release notes.
…the address passed to a callee.
…reseated, and members named whole in modifies as their bytes.
… loop that stores to local storage keeps what was initialized.
…reads bound the head.
…dition reads what the loop changes.
…ion across loops, with a checked example.
…s of the objects it writes.
…ere objects are initialized.
…ark it initialized at calls.
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.
Constructors were not verified: a contracted one was an error (
constructors are not verified yet), and a class with one was not a supported type, so a local of it could not be declared. Now a constructor of a trivially copyable class without bases is verified, and runs where its objects are defined:The second constructor leaves
buf[1]tobuf[7]uninitialized; the failure is located at the member.Stacked on #75 (B3-2 of plan item B3; the loops of constructors such as
Ring()need #74 and #75). Class invariants and member operators follow.Design
From Dafny's two-phase constructors (the fields of an object that exists are assigned before
new;, every field definitely), C++'s [class.base.init] (members initialized in declaration order) and [basic.life] (the object's lifetime begins in storage that exists before it), on top of B3-1'sthis:thiscarries a lifetime companion (__cppverify_constructed_lifetime), so the constructor's accesses are those of local storage, initialization checked, and its generated precondition is that every leaf of*thisis valid with that identity: one live allocation, which the caller shows for its object. Nothing is assumed about the object's initialization, so a member reads as initialized only once the constructor has written it.inits(), which Sema keeps in execution order whatever the written one: the member's initializer, else its in-class initializer (CXXDefaultInitExpr), else its type's default construction.emitConstructedChecks, kindinitialization, located at the member).T x(args),T x{args}, andT x = T(args)pass its address asthis(appendConstruction). The call checks the object's validity but not its initialization, and after the call every leaf is initialized, with the postcondition describing it. An implicit or defaulted default constructor is its member initializers, run in place, recursively for members of class type. A constructor the class provides needs a contract, as any function a verified one calls.cppverify::aliasescannot namethis, a new object; its frame is*thisand the footprints it lists.construct.unsupported, as an out-parameter's is.Two first designs were wrong, and the mutants showed it:
thismade every constructor verify vacuously: an object's validity is a live owner, and the allocation assumed none there.thisas a local object for loop frames (K14 survived): its origin, the entry object, already frames the loop, and a false claim aboutCopy4below still fails in 0.5 s. Both were removed.Tests
suite/constructors.cpp(Z3, with a check that no proof is vacuous, and BMC):Counter()with member initializers andCounter(int)with a body; callersCounter c;,Counter d(5);,Counter e{1};, a member call after construction, and the values the postconditions give;T x = T(3)and a copy of a constructed object;others_kept);Partial:initializationat the member) and a member read before it is initialized (Early, whose initializers are written out of declaration order);point_sum,holder_sum);construct.unsupported);Ring) and one that keeps its source (Copy4, withcppverify::old);Logged);member_functions.cpp: the constructor of a class with a destructor is now rejected for that.Mutants, each built on an assertions build and run on
constructors.cpp,member_functions.cpp,local_record_arguments.cpp,loop_local_frames.cpp, andlocated_errors.cpp: 12 of 12 killed (the two that survived, above, are gone with the code they mutated).constructors,member_functionsconstructors(Partial)constructorsconstructorsthisinitialized at entry, as a member function'sconstructorsconstructorsconstructors(point_sum)constructorsconstructorsconstructorsconstructorsthiswithout its lifetime companionconstructorsDocs
Ring,fresh), and what is not supported yet.Open
return c;of one isaggregate value use of an automatic object is unsupported. Next.newof a record.Checked
thiswas removed; after it,constructors.cpp,member_functions.cpp, andloop_local_frames.cpppass.docs_examples.testanddocs_coverage.testpass.