lifter: destroy an inheritable object through its vtable, even an emp… - #2532
Merged
Merged
Conversation
…ty one A closure's environment is a ref to a compiler-made object deriving from RootObj, and the closure value knows it only as `(ref RootObj)`. Its =destroy decremented the count and freed the block, but never ran the env's OWN destructor: RootObj has no fields, `isTrivialTypeDecl` called it trivial, and `emitRefDestructor` skipped the payload. Every captured string, ref or resource in every closure leaked. An object with RTTI is never trivial for `=destroy` now: the value may be a DERIVED object that owns something, and its `=destroy` is a method. The synthesized `=destroy_RootObj` is an empty method — the vtable slot is the point — and the `ref RootObj` hook dispatches through it to the env's synthesized destroy, which releases the captures. Same mechanism the existing user-hierarchy dispatch (txdestroy) relies on; `=wasMoved` already had this exception for the vtable field. Test: tclosure_env_release — a captured resource with a loud destructor is released when the last reference to the closure goes, and not before. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.
…ty one
A closure's environment is a ref to a compiler-made object deriving from RootObj, and the closure value knows it only as
(ref RootObj). Its =destroy decremented the count and freed the block, but never ran the env's OWN destructor: RootObj has no fields,isTrivialTypeDeclcalled it trivial, andemitRefDestructorskipped the payload. Every captured string, ref or resource in every closure leaked.An object with RTTI is never trivial for
=destroynow: the value may be a DERIVED object that owns something, and its=destroyis a method. The synthesized=destroy_RootObjis an empty method — the vtable slot is the point — and theref RootObjhook dispatches through it to the env's synthesized destroy, which releases the captures. Same mechanism the existing user-hierarchy dispatch (txdestroy) relies on;=wasMovedalready had this exception for the vtable field.Test: tclosure_env_release — a captured resource with a loud destructor is released when the last reference to the closure goes, and not before.