Skip to content

Conversation

@Caball009
Copy link

@Caball009 Caball009 commented Jan 10, 2026

Sufficiently high weapon speeds expose an out-of-bounds access bug for DumbProjectile, which is the reason for non-deterministic behavior across clients (i.e. mismatches).

This PR fixes the bug properly in no retail mode, and makes behavior deterministic for patched clients in retail mode.

TODO:

  • [ ] Replicate in Generals
    Generals doesn't have this particular out-of-bounds bug.

@Caball009 Caball009 added Bug Something is not working right, typically is user facing Major Severity: Minor < Major < Critical < Blocker Stability Concerns stability of the runtime NoRetail This fix or change is not applicable with Retail game compatibility labels Jan 10, 2026
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.

Looks logical in principle.

@xezon xezon changed the title bugfix(projectile): Fix out-of-bounds access bug in DumbProjectile which may cause mismatches bugfix(projectile): Fix out-of-bounds access in DumbProjectile which causes mismatch with very high speed weapons at small hit distances Jan 10, 2026
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.

Code looks correct to me.

@xezon xezon added Gen Relates to Generals ZH Relates to Zero Hour labels Jan 10, 2026
@Caball009
Copy link
Author

Caball009 commented Jan 10, 2026

I hadn't at looked the Generals code until now.

Coord3D prevPos = m_flightPath[0];
Coord3D curPos = m_flightPath[1];

It doesn't have this particular OOB bug, but I'm not entirely sure why the code was updated for Zero Hour or how the behavior changed.

@Caball009
Copy link
Author

Maybe we can just leave the Generals code 'as is', and look at it in more detail later as part of a unification effort for this code.

@xezon
Copy link

xezon commented Jan 12, 2026

Is the code very different yes?

@Caball009
Copy link
Author

Check the links two comments back. It's not that different, but it doesn't have this particular OOB bug.

xezon
xezon previously approved these changes Jan 12, 2026
@xezon
Copy link

xezon commented Jan 12, 2026

@greptileai

@greptile-apps
Copy link

greptile-apps bot commented Jan 12, 2026

Greptile Summary

This PR fixes a critical out-of-bounds memory access bug in DumbProjectileBehavior::update() that caused non-deterministic behavior (mismatches) when using high-speed weapons at small hit distances.

Root Cause: When a weapon has sufficiently high speed, the flight path Bezier curve calculation produces fewer than 2 points in m_flightPath. The original code unconditionally accessed m_flightPath[0] and m_flightPath[1] to calculate projectile orientation on the first frame, causing out-of-bounds access.

The Fix:

  • Added size check if (m_flightPath.size() >= 2) before accessing flight path elements
  • When size < 2, uses fallback values: m_flightPathStart and m_flightPathEnd to calculate orientation deterministically
  • Includes DEBUG_CRASH warning in retail compatibility mode since unpatched clients will still exhibit non-deterministic behavior
  • Sets flightStep = m_flightPathStart in the fallback path to ensure position is valid

Impact: Eliminates mismatch issues for patched clients. Retail mode still warns about potential mismatches with unpatched clients, but behavior is now deterministic for patched clients.

Confidence Score: 5/5

  • This PR is safe to merge with no risk - it fixes a critical deterministic bug with proper bounds checking
  • The fix addresses the root cause of the out-of-bounds access properly by checking vector size before access and providing deterministic fallback values. The solution is well-documented, handles both retail and non-retail modes appropriately, and the previous concern about the condition (>= 2 vs <= 2) has been correctly resolved. The fix maintains code consistency and follows project conventions.
  • No files require special attention

Important Files Changed

Filename Overview
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/DumbProjectileBehavior.cpp Fixed critical out-of-bounds access bug when m_flightPath has fewer than 2 elements. The fix properly sets flightStep, prevPos, and curPos using start/end coordinates as fallback, with appropriate retail compatibility warning.

Sequence Diagram

sequenceDiagram
    participant Game as Game Logic
    participant DPB as DumbProjectileBehavior
    participant FlightPath as m_flightPath Vector
    participant Obj as Projectile Object

    Note over Game,Obj: High-speed weapon triggers projectile update

    Game->>DPB: update()
    DPB->>DPB: Check lifespan
    DPB->>FlightPath: Check m_currentFlightPathStep >= size()
    alt Flight path exhausted
        DPB->>DPB: detonate()
        DPB-->>Game: UPDATE_SLEEP_NONE
    else Valid flight step
        DPB->>FlightPath: flightStep = m_flightPath[m_currentFlightPathStep]
        
        alt orientToFlightPath enabled
            alt m_currentFlightPathStep > 0
                DPB->>FlightPath: Get prevPos from [step-1]
                DPB->>DPB: Calculate orientation
            else step == 0 (Bug Fix Path)
                DPB->>FlightPath: Check size() >= 2
                alt size >= 2 (Normal case)
                    DPB->>FlightPath: prevPos = m_flightPath[0]
                    DPB->>FlightPath: curPos = m_flightPath[1]
                else size < 2 (Bug case - FIXED)
                    Note over DPB: BEFORE: Out-of-bounds access!<br/>AFTER: Use fallback values
                    DPB->>DPB: flightStep = m_flightPathStart
                    DPB->>DPB: prevPos = m_flightPathStart
                    DPB->>DPB: curPos = m_flightPathEnd
                    alt RETAIL_COMPATIBLE_CRC
                        DPB->>DPB: DEBUG_CRASH warning about mismatch
                    end
                end
                DPB->>DPB: Calculate curDir and orientation
                DPB->>Obj: setTransformMatrix(orientMtx)
            end
        else no orientation
            DPB->>Obj: setPosition(flightStep)
        end
        
        DPB->>DPB: Increment m_currentFlightPathStep
        DPB-->>Game: UPDATE_SLEEP_NONE
    end
Loading

@xezon xezon dismissed their stale review January 16, 2026 22:27

Dismissing Approval because this needs one more looking regarding m_flightPathSegments ==1

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, 1 comment

Edit Code Review Agent Settings | Greptile

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.

This is one of currently 3 open PRs with fixes for uninitialized variables, which come with a small risk of introducing new mismatches. These should be merged together without other PRs in between:

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.

Ok. Should be good then.

@Caball009
Copy link
Author

Caball009 commented Jan 25, 2026

I'll put my last comment here, so it doesn't get buried.

With fewer than 2 points, there's no visible projectile, but that's to be expected. There's also no bullet impact when force firing on the ground. Where the damage is applied needs more testing, because it seems like it's applied to a much wider field.

@tintinhamans

This comment was marked as resolved.

greptile-apps[bot]

This comment was marked as resolved.

@tintinhamans
Copy link

@greptileai

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 NoRetail This fix or change is not applicable with Retail game compatibility Stability Concerns stability of the runtime ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tank projectiles cause mismatch

3 participants