bugfix(contain): Abort AIExitState if the containing object dies#2513
bugfix(contain): Abort AIExitState if the containing object dies#2513Stubbjax wants to merge 3 commits intoTheSuperHackers:mainfrom
Conversation
|
| Filename | Overview |
|---|---|
| Generals/Code/GameEngine/Source/GameLogic/AI/AIStates.cpp | Adds isEffectivelyDead() guard in AIExitState::update() under !RETAIL_COMPATIBLE_CRC to short-circuit exit logic when the container is already dead |
| GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIStates.cpp | Mirror of the Generals change — identical isEffectivelyDead() guard added to the Zero Hour copy of AIExitState::update() |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[AIExitState::update] --> B{goal != nullptr?}
B -- No --> Z[STATE_FAILURE]
B -- Yes --> C{goalAI->getAiFreeToExit == WAIT_TO_EXIT?}
C -- Yes --> Y[STATE_CONTINUE]
C -- No --> D{goalExitInterface == nullptr?}
D -- Yes --> Z
D -- No --> E{goal->isEffectivelyDead?\n#if !RETAIL_COMPATIBLE_CRC}
E -- Yes --> Z
E -- No --> F{goalExitInterface->isExitBusy?}
F -- Yes --> Y
F -- No --> G[reserveDoorForExit]
G --> H{exitDoor == DOOR_NONE_AVAILABLE?}
H -- Yes --> Z
H -- No --> I[exitObjectViaDoor]
I --> J{state changed?}
J -- Yes --> Y
J -- No --> K[STATE_SUCCESS]
Reviews (3): Last reviewed commit: "refactor: Convert fix into a standalone ..." | Re-trigger Greptile
Caball009
left a comment
There was a problem hiding this comment.
If this can lead to a crash, the PR should include a crash reproduction.
Why? |
That strikes me as an odd question. The PR is labeled as a crash fix. The PR description and the surrounding code suggest that this shouldn't be a |
|
Yes it is concerning that this function is called on an object that is not a rider. The assert in this function makes clear that this should not happen. Can you check why it happens and if it can be fixed higher up? Even after this fix it would still be a bug, because the assert can be hit. |
I ask because I've only ever seen this to be a suggestion rather than a requirement. A developer might not be in a position to spend hours replicating whatever potentially obscure or convoluted scenario leads to a crash. It could take days or even weeks to figure out. Do we let users keep crashing until that happens? When it comes to live software, plugging the hole is typically the priority; understanding how and why can come later. |
Thankfully it was an easy 3-minute reproduction in this case: Just have a vehicle in the middle of evacuation when it dies. A full Assault Outpost is the best unit for the job. Simply evacuate it and then have it die before all troops have exited. |
The PR description didn't say that this was a crash hotfix, and even if it did, TSH typically doesn't move so quickly that those sort of PRs are merged fast enough. The GeneralsOnline devs put out their own hotfix an hour after the creation of this PR, so there's no longer a sense of urgency:
Thank you, that was helpful. I have dismissed my review, but I do think we should check why this happens at all. FWIW I was able to reproduce this issue with an Attack Outpost but not a Troop Crawler. I created a replay for VC6, but it also works with VS22: crash_containedby.zip Probably not surprising, if Here's the callstack if needed. |
|
Can we stop the evacuation sequence when the container dies? |
| // are not free to exit. | ||
| DEBUG_ASSERTCRASH(specificObject->getContainedBy(), ("rider must be contained")); | ||
| if (specificObject->getContainedBy()->isDisabledByType(DISABLED_HELD)) | ||
| if (specificObject->getContainedBy() && specificObject->getContainedBy()->isDisabledByType(DISABLED_HELD)) |
There was a problem hiding this comment.
Is it worth storing the result from getContainedBy() so we don't call it two or three times here?
|
Needs more investigation to prevent non-existing riders exiting. |
The occupants now abort the |
The pull desc needs updating. |
|
Are the pull title and description up-to-date? |
They are now. |
|
Title says "Abort AIExitState if the containing object dies". Shouldn't it say "Abort AIExitState if the container object dies" ? |
Occupants of a container now abort their
AIExitStateif their container dies. As a result, occupants will no longer attempt to reserve or exit doors on destroyed containers, which could potentially result in accessing invalid states of the original container object.