8000 bugfix(pathfinder): Fix uninitialized variable in Pathfinder::tightenPathCallback to prevent mismatches by Caball009 · Pull Request #2309 · TheSuperHackers/GeneralsGameCode · GitHub
[go: up one dir, main page]

Skip to content

bugfix(pathfinder): Fix uninitialized variable in Pathfinder::tightenPathCallback to prevent mismatches#2309

Merged
xezon merged 5 commits intoTheSuperHackers:mainfrom
Caball009:fix_Pathfinder_tightenPathCallback_variable
Mar 3, 2026
Merged

bugfix(pathfinder): Fix uninitialized variable in Pathfinder::tightenPathCallback to prevent mismatches#2309
xezon merged 5 commits intoTheSuperHackers:mainfrom
Caball009:fix_Pathfinder_tightenPathCallback_variable

Conversation

@Caball009
Copy link
@Caball009 Caball009 commented Feb 15, 2026

Another uninitialized variable rears its ugly head; this time in the path finding code. Causes mismatches, which can be reproduced by driving on the terrain around certain bridges.

Reproduction in Sand Serpent:

bridge_mm.mp4

Replay for VC6:

00-04-16_1v1_adapte_Anthony1.zip This replay does not mismatch with retail executable, and first started to mismatch with 4bbf0c0

Map and replay for VS22:

bridge_mm.zip This replay was recorded with a release build, and the mismatch shows when replay is played back with a debug build.

Notes:

I could not see any noticeable issues in-game because of this bug during my testing. I checked more than 3500 replays and this change did not introduce new mismatches. Unfortunately, the mismatch in the above replay did not go away.

The retail compatible code uses effectively this initialization logic:

Coord3D pos = (!d->foundNewDest) ? Coord3D(0.0f, 0.0f, 0.0f) : d->newDestPos;

TODO:

  • Replicate in Generals.

Thanks to @Mauller and @DrGoldFish1 for their help.

@Caball009 Caball009 added Major Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Stability Concerns stability of the runtime Bug Something is not working right, typically is user facing labels Feb 15, 2026
@greptile-apps
Copy link
greptile-apps bot commented Feb 15, 2026

Greptile Summary

This PR fixes an uninitialized-variable bug in Pathfinder::tightenPathCallback (both Generals/ and GeneralsMD/ copies) that caused determinism mismatches, most visibly when units drove near certain bridges. The local Coord3D pos was previously stack-allocated without initialization; its garbage value was passed to checkForAdjust as a starting point, producing different results between debug and retail builds.

Key changes:

  • TightenPathStruct gains an orgDestPos field (original destination) alongside the renamed foundNewDest / newDestPos, giving the callback a well-defined starting value.
  • Under RETAIL_COMPATIBLE_CRC, pos is seeded from the accumulated newDestPos (zero-initialized by the caller), approximating the retail stack layout where the value was near-zero on the first call.
  • In non-RETAIL_COMPATIBLE_CRC builds, pos is seeded from orgDestPos, providing a fully deterministic, correct initial value.
  • The fix is applied symmetrically to both Generals/ and GeneralsMD/ code paths, closing the previously noted inconsistency between the two trees.

Confidence Score: 5/5

  • Safe to merge — the uninitialized variable bug is correctly identified and fixed in both code trees with sound RETAIL_COMPATIBLE_CRC branching logic.
  • The PR correctly fixes the core uninitialized-variable bug that was causing determinism mismatches. The variable pos in tightenPathCallback is now properly initialized in both retail-compatible and non-retail code paths. The fix is symmetric across both Generals/ and GeneralsMD/ variants, maintaining consistency. All changes are straightforward and safe.
  • No files require special attention.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["tightenPath(obj, locomotorSet, from, to)"] --> B["Init TightenPathStruct\nfoundNewDest = false\norgDestPos = *to\n[RETAIL] newDestPos.zero()"]
    B --> C["iterateCellsAlongLine()\ncalls tightenPathCallback per cell"]
    C --> D{"from == nullptr\nor to == nullptr?"}
    D -- yes --> E["return 0 // failure"]
    D -- no --> F{"layer matches?"}
    F -- no --> E
    F -- yes --> G{"RETAIL_COMPATIBLE_CRC?"}
    G -- yes --> H["pos = d->newDestPos\n(accumulated or zero)"]
    G -- no --> I["pos = d->orgDestPos\n(original destination)"]
    H --> J["checkForAdjust(..., &pos, nullptr)"]
    I --> J
    J -- fails --> E
    J -- succeeds --> K["foundNewDest = true\nnewDestPos = pos"]
    K --> L["return 0 // success, continue"]
    C --> M{"foundNewDest?"}
    M -- yes --> N["*from = newDestPos"]
    M -- no --> O["*from unchanged"]
Loading

Last reviewed commit: 036368c

@Caball009 Caball009 added NoRetail This fix or change is not applicable with Retail game compatibility and removed NoRetail This fix or change is not applicable with Retail game compatibility labels Feb 15, 2026
@Caball009 Caball009 marked this pull request as draft February 15, 2026 03:53
@helmutbuhler
Copy link

Interesting, that commit you mentioned already caused problems earlier in #1061. I predicted there that it might cause further mismatches, and this seems like confirmation of that. Maybe we should revert #1009 and #1013, at least for VC6 builds?

@stephanmeesters
Copy link

Did you mean to do the fix in Generals/ not GeneralsMD/?

@Caball009
Copy link
Author

Did you mean to do the fix in Generals/ not GeneralsMD/?

Oops, yeah, that's silly of me. Not sure how that happened.

@Caball009 Caball009 force-pushed the fix_Pathfinder_tightenPathCallback_variable branch from 1c744fc to 52d46c5 Compare February 15, 2026 18:06
@Caball009
Copy link
Author

Interesting, that commit you mentioned already caused problems earlier in #1061. I predicted there that it might cause further mismatches, and this seems like confirmation of that. Maybe we should revert #1009 and #1013, at least for VC6 builds?

I'm not sure if that solves anything. I tried the current main branch with the wwmath.h header from 2856a23 ( the commit before 4bbf0c0 ) and the VC6 replay still mismatches.

Harmless changes anywhere can change stack layouts and introduce mismatches that hadn't been noticeable before because of uninitialized variables.

@Caball009 Caball009 force-pushed the fix_Pathfinder_tightenPathCallback_variable branch from cc871b4 to 3eb91ef Compare February 17, 2026 18:00
@Mauller
Copy link
Mauller commented Feb 21, 2026

Considering how varied the value of Pos was, from what you showed me, maybe we can't set it to anything specific but take the non retail stuff?

@Caball009
Copy link
Author

... but take the non retail stuff?

What do you mean?

@Caball009 Caball009 force-pushed the fix_Pathfinder_tightenPathCallback_variable branch from 2fa625d to da544e9 Compare February 27, 2026 19:44
@Caball009
Copy link
Author

I was able to find a way to initialize this variable without introducing new mismatches. I checked more than 3500 replays to verify that. Unfortunately, the mismatch in the original replay did not go away.

@Caball009 Caball009 marked this pull request as ready for review February 27, 2026 23:05
@Caball009 Caball009 force-pushed the fix_Pathfinder_tightenPathCallback_variable branch from d945477 to 51919b3 Compare February 28, 2026 15:36
xezon
xezon previously approved these changes Mar 2, 2026
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.

i don't think d->destPos is initialised properly by using zero for non retail compatible use.

destPos could be externally initialised with the initial destination position in the calling function.

or as we did before, pos could just be set to the to position by using the adjust cell to world function in non retail code like we did on a first attempt.

Copy link
@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@Caball009 Caball009 dismissed xezon’s stale review March 3, 2026 15:05

Code changes since review.

@Caball009 Caball009 force-pushed the fix_Pathfinder_tightenPathCallback_variable branch from 477c448 to a7cb4fa Compare March 3, 2026 15:42
@Caball009
Copy link
Author

I made a couple of changes to the initialization logic. The intended initialization for retail is still:

Coord3D pos = (!d->foundNewDest) ? Coord3D(0.0f, 0.0f, 0.0f) : d->newDestPos;

The new changes are probably an improvement to the code, but I'm not sure if the code comment still makes sense without context.

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.

Looks good to me, i guess this still passes all the same replays?

info.foundNewDest = false;
info.orgDestPos = *to;
#if RETAIL_COMPATIBLE_CRC
info.newDestPos.zero();
Copy link
@Mauller Mauller Mar 3, 2026

Choose a reason for hiding this comment

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

newDestPost could be zero initialied here anyway regardless of retail compat for cleanliness.

I don't think it matters if it is left uninitialised for non-retail since it's only ever assigned to then read from when foundNewDest is true etc.

Copy link
Author

Choose a reason for hiding this comment

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

I don't have a strong opinion on it, either way.

@Caball009
Copy link
4D1C
Author

Looks good to me, i guess this still passes all the same replays?

The current code should effectively still be the same as what I tested with. I did a quick check just now with the fastest replays and those are still fine.

I happened to be doing some unrelated replay testing with the latest weekly release (2026-02-27), and noticed 30+ / 2000 new mismatches, e.g. for replays like this one 1v1 (25.11.18) [rank] vendetta zh v1 SR_MaD^(gla) vs Penguin(tox).zip

These replays don't mismatch with the previous weekly release (2026-02-20), and I tracked it down to https://github.com/TheSuperHackers/GeneralsGameCode/pull/2327/changes The mismatches are gone with this PR :)

Copy link
@xezon xezon left a comment

Choose a reason for hiding this comment

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

Good job

@xezon xezon merged commit 7cb5a62 into TheSuperHackers:main Mar 3, 2026
26 checks passed
@Caball009 Caball009 deleted the fix_Pathfinder_tightenPathCallback_variable branch March 3, 2026 21:13
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 Gen Relates to Generals Major Severity: Minor < Major < Critical < Blocker Stability Concerns stability of the runtime ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

0