Skip to content

[GEN][ZH] Prevent game crash when a player is selected in Replay playback #1212

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 1, 2025

Conversation

xezon
Copy link

@xezon xezon commented Jun 28, 2025

This change fixes a critical problem with AIGroup, that happens all the time in any match, but only crashes the Replay playback when a player is selected. The memory management of AIGroup is totally broken, and it will leak many AIGroups in AI matches (or matches that use AI scripts) and that will slow down iterating over std::list<AIGroup *> m_groupList.

The Problem

AIGroup has a fundamental memory management flaw with its AIGroup::remove function. It deletes itself when all members are removed, which means that any non-AIGroup members holding a reference to that AIGroup will dangle when it is deleted.

This happens all the time in GameLogic::logicMessageDispatcher with its currentlySelectedGroup variable. It holds objects in a AIGroup, but that AIGroup can be deleted by external events, for example

void GameLogic::logicMessageDispatcher( GameMessage *msg, void *userData )
{
...
  AIGroup* currentlySelectedGroup = NULL;

  if (isInGame())
  {
    if (msg->getType() >= GameMessage::MSG_BEGIN_NETWORK_MESSAGES && msg->getType() <= GameMessage::MSG_END_NETWORK_MESSAGES)
    {
      if (msg->getType() != GameMessage::MSG_LOGIC_CRC && msg->getType() != GameMessage::MSG_SET_REPLAY_CAMERA)
      {
        currentlySelectedGroup = TheAI->createGroup(); // can't do this outside a game - it'll cause sync errors galore.
        CRCGEN_LOG(( "Creating AIGroup %d in GameLogic::logicMessageDispatcher()\n", (currentlySelectedGroup)?currentlySelectedGroup->getID():0 ));
        thisPlayer->getCurrentSelectionAsAIGroup(currentlySelectedGroup);

...
  // process the message
  GameMessage::Type msgType = msg->getType();
  switch( msgType )
  {
...
    case GameMessage::MSG_REMOVE_BEACON:
    {
      AIGroup* allSelectedObjects = TheAI->createGroup();
      thisPlayer->getCurrentSelectionAsAIGroup(allSelectedObjects); // <----- xezon: this will delete the AIGroup pointed to by currentlySelectedGroup

There are multiple code paths like this that can delete currentlySelectedGroup.

The Solution

With RETAIL_COMPATIBLE_CRC, GameLogic::logicMessageDispatcher now uses a massive hack to avoid crashing. It uses this hack because fixing AIGroup properly will mismatch with Retail. GenTool applies this exact hack since more than a decade.

TODO

  • Test against VC6 Golden Replay
  • Replicate in Generals
  • Test against more replays

@xezon xezon added this to the Stability fixes milestone Jun 28, 2025
@xezon xezon added Bug Something is not working right, typically is user facing Critical Severity: Minor < Major < Critical < Blocker Performance Is a performance concern Gen Relates to Generals ZH Relates to Zero Hour Crash This is a crash, very bad labels Jun 28, 2025
@xezon
Copy link
Author

xezon commented Jun 28, 2025

I think I will split this in 2.

@xezon xezon force-pushed the xezon/fix-aigroup-5 branch from c6a3480 to 87a69ee Compare June 28, 2025 16:58
@xezon xezon removed the Performance Is a performance concern label Jun 28, 2025
@xezon xezon changed the title [GEN][ZH] Fix AIGroup memory management and game crash when a player is selected in Replay playback due heap-use-after-free in GameLogic::logicMessageDispatcher() [GEN][ZH] Prevent game crash when a player is selected in Replay playback due heap-use-after-free in GameLogic::logicMessageDispatcher() Jun 28, 2025
@xezon
Copy link
Author

xezon commented Jun 28, 2025

Done.

Copy link

@Mauller Mauller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is pretty nasty that, i guess other places are okay for this?

@xezon
Copy link
Author

xezon commented Jun 29, 2025

What do you mean by other places are okay for this?

@Mauller
Copy link

Mauller commented Jun 29, 2025

Oh I meant are the other places In the code that use this okay and dont need similar null testing?

@xezon
Copy link
Author

xezon commented Jun 29, 2025

We will know if we find more crashes.

@xezon xezon changed the title [GEN][ZH] Prevent game crash when a player is selected in Replay playback due heap-use-after-free in GameLogic::logicMessageDispatcher() [GEN][ZH] Prevent game crash when a player is selected in Replay playback Jul 1, 2025
@xezon xezon merged commit 1ebce07 into TheSuperHackers:main Jul 1, 2025
20 checks passed
@xezon xezon deleted the xezon/fix-aigroup-5 branch July 1, 2025 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something is not working right, typically is user facing Crash This is a crash, very bad Critical Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Game can crash when clicking on player icon in Replay Mode
2 participants