Repository navigation
Conversation
…ashing A dedicated server playing CTF on the Custom Edition map coldsnap_20th_xl_rc5 crashed in hs_thread_main: the map's script ran volume_test_object on a Warthog that had been deleted. A script keeps an object's index after the object is gone, in a global or an object list, and nothing between the script and object_get checked it. In a release build datum_get reports the stale index and returns NULL, and the read through that NULL faults. Halo PC plays this map. The script runtime now turns such a value into none. hs_cast checks every global read and every function's or script's result, before casting, so no list is made of a deleted object. hs_arguments_evaluate checks the arguments again before the call, because a later argument's static script can sleep after an earlier one was evaluated. Lists collected in the same way count as gone too. Walking an object list passes over deleted objects; list_count still counts every entry, as it always has. A script already gets none for a named object that doesn't exist, and nearly every script function takes it. The functions with object parameters were searched for a check of none, and those without one were read: unit_kill, unit_kill_silent and scenery_get_animation_time crashed on none, so they now do nothing for it. HALO_PORT_NETWORK_VERSION stays the same: nothing sent changes, and scripts need not agree between machines. Only the host runs them in co-op, and in other games the host decides what they do to the game. Checked with tools/harness/tests/test_script_stale_objects.py (the real runtime and data arrays, with negative controls): 42 pass. On Windows the full harness has the same 631 failures as testing and no new ones. The four changed files compile for Windows; CI builds the other platforms. Not run on the real map. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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 dedicated server on build-337 crashed during a CTF game on the Custom Edition map
coldsnap_20th_xl_rc5, with about 12 players in:Symbolising the release binary gives
object_get_and_verify_type←scenario_trigger_volume_test_object←scenario_trigger_volume_test_object_evaluate←hs_thread_main. The map's script ranvolume_test_objecton a Warthog that had already been deleted. A script keeps an object's index after the object is gone, in a global or an object list, and nothing between the script andobject_getchecked it. In a release builddatum_getreports the stale index and returns NULL, and the read through that NULL faults.The fix
The script runtime now turns such a value into none, which is already what a script gets for a named object that doesn't exist.
hs_castchecks every global read and every function's or script's result, before casting, so no list is made of a deleted object.hs_arguments_evaluatechecks the arguments again just before the call, because a later argument's static script can sleep after an earlier one was evaluated.list_countstill counts every entry, as it always has.unit_kill,unit_kill_silentandscenery_get_animation_timecrashed on none, so they now do nothing for it. The other script functions with object parameters were searched for a check of none, and those without one were read.Nothing the machines send each other changes, so the network version stays. Scripts need not agree between machines: only the host runs them in co-op, and in other games the host decides what they do to the game.
Testing
tools/harness/tests/test_script_stale_objects.py, on the real runtime and data arrays, with negative controls: 42 pass.testing(Linux-only tests) and no new ones. The four changed source files compile for Windows; CI builds the other platforms.🤖 Generated with Claude Code