Skip to content

Give a script none for an object that no longer exists, instead of crashing - #553

Open
GuvenHuso wants to merge 1 commit into
testingfrom
script-stale-object-index
Open

GuvenHuso wants to merge 1 commit into
testingfrom
script-stale-object-index

Conversation

@GuvenHuso

Copy link
Copy Markdown
Collaborator

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:

EXCEPTION assert in c:\halo\SOURCE\memory\data.c,#412: object index #449 (0xe43001c1) is unused or changed (release build)
segmentation fault (signal 11, code 1) at 0x8

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 ran volume_test_object on 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 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.

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_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 just before the call, because a later argument's static script can sleep after an earlier one was evaluated.
  • Object lists: a list that has been collected counts as gone too, and walking a list passes over deleted objects. list_count still counts every entry, as it always has.
  • unit_kill, unit_kill_silent and scenery_get_animation_time crashed 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

  • New harness test tools/harness/tests/test_script_stale_objects.py, on the real runtime and data arrays, with negative controls: 42 pass.
  • Locally on Windows, the full harness has the same 631 failures as testing (Linux-only tests) and no new ones. The four changed source files compile for Windows; CI builds the other platforms.
  • Not run on the real map. The crash depends on what happens to that Warthog in play, so it hasn't been reproduced in a game, only in the harness.

🤖 Generated with Claude Code

…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

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant