Conversation
A module is an ordinary GC object, so a generational collection stops traversing it once it is old. What it holds still changes after that: a literal boxes itself on first use, the JIT embeds that box, a script static is assigned. None of those writes has a barrier, so a minor collection freed the young object while the module still pointed at it, and the next use read reused memory. Modules are now marked with the class statics. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The cppia host now builds with HXCPP_GC_GENERATIONAL. After full collections make the module old, ClientModuleValues boxes a string literal and assigns a static array, which only the module references. Weak references then check that a generational collection keeps them. Without the fix, both are freed without the JIT, and the array with it (the JIT boxes the literal at load time). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
|
Added a test to test/cppia in 3b88426 |
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.
With
HXCPP_GC_GENERATIONAL, objects held by a loaded cppia module can be freed while still in use.CppiaObject::__Markis the only thing that marks a module (CppiaModule::mark: strings, types,markable, classes). A generational collection stops traversing an object once it is old, and a module is old soon after it is loaded. But what a module holds keeps changing after that, with no write barrier:StringVal::runObject/DataVal::runObjectbox the literal on first use (value = strVal), andStringVal::genCodeembeds that box in JIT code;mMarkFunc, so their statics are also only marked through the module).The young object is then reachable only from the old module, so the next minor collection frees it, and a later use reads reused memory. In practice, a closure passing a string literal to a dynamic call worked the first time and crashed or printed garbage (
Abstract(cpp.Pointer:…)) a minute later; a script static assigned after load did the same.A standalone reproduction is attached: a scriptable host with
HXCPP_GC_GENERATIONALloads a small ASCII cppia script, lets the module grow old with full collections, then calls two script closures (one boxes a string literal, one assigns a script static) with only generational collections in between. Onmasterthe first round prints the right values and the second crashes, every run; with this change all five rounds pass.hxcpp-cppia-generational-module.zip
The fix marks every loaded module on every collection, next to
MarkClassStatics(and visits them next toVisitClassStaticsunderHXCPP_VISIT_ALLOCS), via the existinggAllCppiaModuleslist. A full collection marks a module twice, which is harmless. The cost is proportional to what the modules hold, as for class statics.Tested on Linux: the reproduction crashes on
masterand passes with the change, and a game embedding cppia mods (generational, big blocks,HXCPP_CHECK_POINTER) no longer crashes on its second use of a closure. hxScript's cppia suite (447 tests) and its conformance corpus (hxcpp-cppia and hxcpp-cppia-jit, 351 ok / 5 expected throws) pass against it.