Skip to content

fix(pathfinder): Fix CRC computation of PathFinder::m_wallPieces#2575

Open
Caball009 wants to merge 2 commits intoTheSuperHackers:mainfrom
Caball009:fix_crc_pathfinder_wallpieces
Open

fix(pathfinder): Fix CRC computation of PathFinder::m_wallPieces#2575
Caball009 wants to merge 2 commits intoTheSuperHackers:mainfrom
Caball009:fix_crc_pathfinder_wallpieces

Conversation

@Caball009
Copy link
Copy Markdown

@Caball009 Caball009 commented Apr 10, 2026

Original EA code links

https://github.com/electronicarts/CnC_Generals_Zero_Hour/blob/main/Generals/Code/GameEngine/Include/GameLogic/AIPathfind.h#L846-L847

https://github.com/electronicarts/CnC_Generals_Zero_Hour/blob/main/Generals/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp#L10395-L10398

https://github.com/electronicarts/CnC_Generals_Zero_Hour/blob/main/GeneralsMD/Code/GameEngine/Include/GameLogic/AIPathfind.h#L858-L859

https://github.com/electronicarts/CnC_Generals_Zero_Hour/blob/main/GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp#L11095-L11098

ObjectID m_wallPieces[MAX_WALL_PIECES];
Int m_numWallPieces;

for (Int i=0; i<MAX_WALL_PIECES; ++i)
{
xfer->xferObjectID(&m_wallPieces[MAX_WALL_PIECES]);
}

This loop uses the address of the first element after the m_numWallPieces array, which is effectively the same as:

 for (Int i=0; i<MAX_WALL_PIECES; ++i) 
 { 
 	xfer->xferObjectID(&m_numWallPieces); 
 }

This should be a change that's not user facing, but I need to check some replays to verify that everything works as expected.

TODO:

  • Check replays.

@Caball009 Caball009 added Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Fix Is fixing something, but is not user facing NoRetail This fix or change is not applicable with Retail game compatibility labels Apr 10, 2026
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 10, 2026

Greptile Summary

This PR fixes a bug in Pathfinder::crc() where &m_wallPieces[MAX_WALL_PIECES] (an out-of-bounds address pointing to m_numWallPieces) was being passed to xferObjectID in a loop, effectively serializing m_numWallPieces 128 times instead of each wall piece. The fix gates the behavior behind RETAIL_COMPATIBLE_CRC: the legacy path replicates the original (buggy) behavior for save/replay compatibility, while the corrected path serializes the actual m_wallPieces array via xferUser.

The verification that xferObjectID and xferInt both delegate to xferImplementation(data, sizeof(T)) confirms the static_assert(sizeof(Int) == sizeof(ObjectID)) is sufficient to guarantee identical CRC output on the compatibility path.

Confidence Score: 5/5

Safe to merge; the fix is logically sound, the compatibility path is correctly guarded, and the static_assert prevents silent breakage if type sizes ever diverge.

No P0/P1 findings. The RETAIL_COMPATIBLE_CRC path faithfully replicates the original behavior (confirmed by reading Xfer.cpp — both xferObjectID and xferInt delegate to xferImplementation with the same size), and the corrected path properly serializes the actual array. The static_assert is a well-placed defensive guard.

No files require special attention.

Important Files Changed

Filename Overview
Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp Fixes out-of-bounds UB in the CRC loop by gating the legacy (buggy) behavior behind RETAIL_COMPATIBLE_CRC and introducing a correct xferUser path; static_assert guards type-size equivalence.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Pathfinder::crc(Xfer *xfer)"] --> B["xferInt(&m_numWallPieces)"]
    B --> C{RETAIL_COMPATIBLE_CRC?}
    C -- Yes --> D["Loop 128x: xferInt(&m_numWallPieces)\n(replicates original buggy behavior)\nstatic_assert sizeof(Int)==sizeof(ObjectID)"]
    C -- No --> E["xferUser(m_wallPieces, sizeof(m_wallPieces))\n(correct: serializes all ObjectIDs)"]
    D --> F["CRCDEBUG_LOG m_wallPieces"]
    E --> F
    F --> G["xferReal(&m_wallHeight)"]
Loading

Reviews (2): Last reviewed commit: "Tweaked code and comment." | Re-trigger Greptile

@Caball009
Copy link
Copy Markdown
Author

Updated PR.

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

Labels

Fix Is fixing something, but is not user facing Gen Relates to Generals Minor Severity: Minor < Major < Critical < Blocker NoRetail This fix or change is not applicable with Retail game compatibility ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants