The camera HUD only reads the slots it filled
A Live Cam host launched into a real race took the process down with an access violation. WER put the fault at image offset 0x76239, which with this build's fixed base resolves against the shipped PDB to CameraShipHUDRenderable::Execute - the dereference in the ranking loop. Two defects, both older than Live Cam. playerRank is SPARSE: it is sized for the racing players plus the camera players and filled by playerBitmapIndex - 1, exactly as the constructor's own comment says. But it was allocated with new[], which does not zero, and Execute walked it densely to playerCount and dereferenced every slot. Any bitmap index that nobody claimed was therefore uninitialised heap read as an int*. Live Cam is simply the first thing that can leave a gap at the front. The host takes bitmap index 1 and, being the camera, is not in the "Players" group, so slot 0 was never claimed while playerCount was still 1 and the loop still ran. The arcade never hit it because its camera cabinets sat after the pods in the egg, so slot 0 belonged to a real racer and the dense walk was accidentally safe. So: clear the array on allocation, remember its real length as rankCount, and iterate that while skipping the unclaimed slots. The playerCount bound was wrong on its own terms too - a race whose bitmap indices run past it would have missed the tail. Everything before the crash worked on the first try, which is the other half of the news: with a live racing peer the camera director builds, the camera ship comes up and starts directing. The map-load hang that stopped a camera host before was an artefact of it having no peers. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+20
-1
@@ -2805,6 +2805,7 @@ CameraShipHUDRenderable::CameraShipHUDRenderable(Entity *entity, ExecutionType e
|
||||
//
|
||||
playerRank = NULL;
|
||||
oldPlayerRank = NULL;
|
||||
rankCount = 0;
|
||||
nameDCS = NULL;
|
||||
rankDCS = NULL;
|
||||
nameInstance = NULL;
|
||||
@@ -2848,6 +2849,18 @@ CameraShipHUDRenderable::CameraShipHUDRenderable(Entity *entity, ExecutionType e
|
||||
Verify(camera_player_count <= MAX_PLAYER_NAMES);
|
||||
playerRank = new (int (*[camera_player_count]));
|
||||
Register_Pointer(playerRank);
|
||||
//
|
||||
// Cleared, because the fill below is by bitmap index and leaves
|
||||
// gaps: with a Live Cam host the racing players start at index 2
|
||||
// and nothing ever claims slot 0. new[] does not zero, so those
|
||||
// gaps were uninitialised heap read as int* - the access
|
||||
// violation in Execute.
|
||||
//
|
||||
rankCount = camera_player_count;
|
||||
for (int slot = 0; slot < rankCount; ++slot)
|
||||
{
|
||||
playerRank[slot] = NULL;
|
||||
}
|
||||
Player *active_player;
|
||||
if(player_group)
|
||||
{
|
||||
@@ -3095,8 +3108,14 @@ void CameraShipHUDRenderable::Execute()
|
||||
// whenever they change!
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
for(int ii=0; ii<playerCount; ++ii)
|
||||
// Over the whole array, not playerCount, and skipping the slots no
|
||||
// bitmap index claimed - see rankCount in the header.
|
||||
for(int ii=0; ii<rankCount; ++ii)
|
||||
{
|
||||
if (playerRank[ii] == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (oldPlayerRank[ii] != (*playerRank[ii]))
|
||||
{
|
||||
oldPlayerRank[ii] = *playerRank[ii];
|
||||
|
||||
@@ -846,6 +846,19 @@ class CameraShipHUDRenderable :
|
||||
int
|
||||
playerCount;
|
||||
|
||||
//
|
||||
// How long playerRank/oldPlayerRank actually are. NOT playerCount:
|
||||
// the arrays are keyed by playerBitmapIndex, which a CameraShip
|
||||
// player takes a slot in too, so they are sized for the racing
|
||||
// players plus the camera players and are SPARSE - a slot whose
|
||||
// bitmap index nobody claimed stays NULL. Walking them to
|
||||
// playerCount instead read past the last claimed slot, which is
|
||||
// how a Live Cam host (bitmap index 1, and not in "Players") took
|
||||
// the whole game down.
|
||||
//
|
||||
int
|
||||
rankCount;
|
||||
|
||||
int
|
||||
oldFollowedPlayerIndex,
|
||||
*followedPlayerIndex;
|
||||
|
||||
Reference in New Issue
Block a user