Skip to content

Conversation

@bobtista
Copy link

@bobtista bobtista commented Nov 1, 2025

Addresses Issue #1664

The behavior differs between versions:
Generals: Causes visual bugs (missile launches from scaffold) but does not crash
Zero Hour (GeneralsMD): Crashes with a NULL pointer dereference

Root Cause Theory:
For Nuclear Missiles with MissileLauncherBuildingUpdate, this causes issues because:

  1. Buildings under construction never initialize their m_specialPowerModule pointer
  2. The pointer is only initialized in update(), which exits early for OBJECT_STATUS_UNDER_CONSTRUCTION
  3. When the AI tries to fire from the under-construction building, it accesses the NULL pointer → crash (Zero Hour) or visual bugs (Generals)

Mauller's fix (#1218): Prevents exploit where special power timers initialize to 0
This fix (#1664): Prevents AI from firing special powers from buildings under construction

Proposed Fix:
Prevention (AIGroup): Skip buildings under construction when firing special powers. Guarded by !RETAIL_COMPATIBLE_AIGROUP flag

Protection (MissileLauncherBuildingUpdate): Add NULL check to return early if the module isn't initialized. Always active in all builds.

Note: Not yet tested. Also, added Mauller's fix to Generals

@Skyaero42
Copy link

How does this relate to #1461?

@bobtista
Copy link
Author

bobtista commented Nov 1, 2025

How does this relate to #1461?

So, reviewing some related PRs:
1461 would conflict with this, as it changes the initialization code this PR relies on. Specifically, it moves m_specialPowerModule initialization to the constructor, so it's never null - 1769 assumes m_specialPowerModule is NULL during construction, so the checks will be wrong.

1444: Does not conflict

For a scenario where both could come into play, during building construction:

  1. SpecialPowerModule created → 1444 sets m_availableOnFrame appropriately
  2. AI tries to fire → 1769's AIGroup check skips it (if RETAIL_COMPATIBLE_AIGROUP=0)
  3. If AIGroup check is off → 1769 check in MissileLauncherBuildingUpdate blocks it

Thoughts/Questions:
Do we need to use m_availableOnFrame = 0xFFFFFFFF as an escape signal? Could we return early somewhere else eg

Bool initiated = initiateIntentToDoSpecialPower(...);
    
    if (!initiated) {
        return;

If I understand correctly, in retail normal play, initiated is always true, so this would never get hit. In the bugged out scenario, retail would crash anyway (in ZH at least), so do we count that as retail compatible?

1461 I think is cleaner architecture moving forwards. Then we can check if (testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION)) instead of hackily using if (!m_specialPowerModule). This PR would just be the AIGroup checks (assuming those work, I haven't tested them yet) - if they do work, we could just close this and add those lines to 1461. We can still add the escape signal check - can we make it regardless of retail compatible flag though?

I had Claude come up with a summary table to help me visualize what PR does what. I think we should merge all 3 of them, or maybe just combine them into one and close the other two.
Screenshot 2025-11-01 at 4 40 36 PM

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.

2 participants