Skip to content

bugfix(treebuffer): Fix crash in W3DTreeBuffer::updateVertexBuffer()#2526

Merged
xezon merged 3 commits intoTheSuperHackers:mainfrom
githubawn:fix/tree-crash
Apr 6, 2026
Merged

bugfix(treebuffer): Fix crash in W3DTreeBuffer::updateVertexBuffer()#2526
xezon merged 3 commits intoTheSuperHackers:mainfrom
githubawn:fix/tree-crash

Conversation

@githubawn
Copy link
Copy Markdown

@githubawn githubawn commented Apr 2, 2026

Fixes a crash in W3DTreeBuffer::updateVertexBuffer caused by stale bufferNdx/firstIndex values from a previous vertex buffer rebuild. When a tree was pushed aside after the buffer layout changed, the old offset was used to write into the wrong location. Additional guards were added for failed vertex buffer locks and missing tree meshes.

Fixes Air force general challenge 2 easy on 1280 x 960 with raised camera height (or anywhere there is massive tree culling)

generalszh.exe!W3DTreeBuffer::updateVertexBuffer() Line 1050 (\Core\GameEngineDevice\Source\W3DDevice\GameClient\W3DTreeBuffer.cpp:1050)
generalszh.exe!W3DTreeBuffer::drawTrees(CameraClass * camera, RefMultiListIterator<RenderObjClass> * pDynamicLightsIterator) Line 1633 (\Core\GameEngineDevice\Source\W3DDevice\GameClient\W3DTreeBuffer.cpp:1633)
generalszh.exe!BaseHeightMapRenderObjClass::renderTrees(CameraClass * camera) Line 2967 (\Core\GameEngineDevice\Source\W3DDevice\GameClient\BaseHeightMap.cpp:2967)
generalszh.exe!DoTrees(RenderInfoClass & rinfo) Line 123 (\Core\GameEngineDevice\Source\W3DDevice\GameClient\BaseHeightMap.cpp:123)
generalszh.exe!RTS3DScene::Flush(RenderInfoClass & rinfo) Line 870 (\GeneralsMD\Code\GameEngineDevice\Source\W3DDevice\GameClient\W3DScene.cpp:870)
generalszh.exe!RTS3DScene::Render(RenderInfoClass & rinfo) Line 988 (\GeneralsMD\Code\GameEngineDevice\Source\W3DDevice\GameClient\W3DScene.cpp:988)
generalszh.exe!WW3D::Render(SceneClass * scene, CameraClass * cam, bool clear, bool clearz, const Vector3 & color) Line 975 (\GeneralsMD\Code\Libraries\Source\WWVegas\WW3D2\ww3d.cpp:975)
generalszh.exe!RTS3DScene::draw() Line 1763 (\GeneralsMD\Code\GameEngineDevice\Source\W3DDevice\GameClient\W3DScene.cpp:1763)
generalszh.exe!SubsystemInterface::DRAW() Line 132 (\Core\GameEngine\Include\Common\SubsystemInterface.h:132)
generalszh.exe!RTS3DScene::doRender(CameraClass * cam) Line 1748 (\GeneralsMD\Code\GameEngineDevice\Source\W3DDevice\GameClient\W3DScene.cpp:1748)
generalszh.exe!W3DView::draw() Line 1677 (\Core\GameEngineDevice\Source\W3DDevice\GameClient\W3DView.cpp:1677)
generalszh.exe!SubsystemInterface::DRAW() Line 132 (\Core\GameEngine\Include\Common\SubsystemInterface.h:132)
generalszh.exe!W3DView::drawView() Line 1641 (\Core\GameEngineDevice\Source\W3DDevice\GameClient\W3DView.cpp:1641)
generalszh.exe!Display::drawViews() Line 115 (\GeneralsMD\Code\GameEngine\Source\GameClient\Display.cpp:115)
generalszh.exe!W3DDisplay::draw() Line 1860 (\GeneralsMD\Code\GameEngineDevice\Source\W3DDevice\GameClient\W3DDisplay.cpp:1860)
generalszh.exe!SubsystemInterface::DRAW() Line 132 (\Core\GameEngine\Include\Common\SubsystemInterface.h:132)
generalszh.exe!GameClient::update() Line 759 (\GeneralsMD\Code\GameEngine\Source\GameClient\GameClient.cpp:759)
generalszh.exe!W3DGameClient::update() Line 94 (\GeneralsMD\Code\GameEngineDevice\Source\W3DDevice\GameClient\W3DGameClient.cpp:94)
generalszh.exe!SubsystemInterface::UPDATE() Line 131 (\Core\GameEngine\Include\Common\SubsystemInterface.h:131)
generalszh.exe!GameEngine::update() Line 906 (\GeneralsMD\Code\GameEngine\Source\Common\GameEngine.cpp:906)

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 2, 2026

Greptile Summary

This PR fixes a crash in W3DTreeBuffer::updateVertexBuffer() caused by stale bufferNdx/firstIndex values from a previous vertex buffer rebuild. When trees were culled and the buffer layout changed, old offsets were used to write geometry into wrong memory locations — causing the out-of-bounds write/crash described in the stack trace.

Key changes:

  • Resets all trees' bufferNdx to -1 before each loadTreesInVertexAndIndexBuffers rebuild, so updateVertexBuffer naturally skips trees absent from the new layout (since bNdx >= 0 never equals -1)
  • Consolidates the type < 0 and m_treeTypes[type].m_mesh == nullptr null guards into one combined check at the top of the load loop
  • Adds a null guard for Get_Vertex_Array() returning null during vertex buffer lock, using continue to attempt remaining buffers rather than crashing
  • Removes the now-redundant type < 0 check in updateVertexBuffer (superseded by the bufferNdx reset)
  • Replaces the silent type = 0 fallback with DEBUG_ASSERTCRASH to surface logic errors in debug builds rather than silently rendering with the wrong mesh

Confidence Score: 5/5

Safe to merge — the fix is logically sound and directly addresses the root cause of the crash.

No P0 or P1 issues found. The bufferNdx=-1 sentinel correctly prevents stale offsets from being used since bNdx is always >=0. All null guards use continue appropriately. No newly introduced regressions detected.

No files require special attention.

Important Files Changed

Filename Overview
Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DTreeBuffer.cpp Correct fix: resets bufferNdx to -1 before rebuild, adds null VB guard with continue, consolidates mesh checks, and replaces silent type=0 fallback with DEBUG_ASSERTCRASH

Sequence Diagram

sequenceDiagram
    participant LT as loadTreesInVertexAndIndexBuffers
    participant Tree as m_trees[t]
    participant UV as updateVertexBuffer

    LT->>Tree: Reset all bufferNdx = -1
    loop For each visible tree with valid mesh
        LT->>Tree: Set bufferNdx = bNdx, firstIndex = startVertex
    end
    Note over LT,Tree: Trees absent from rebuild keep bufferNdx = -1

    UV->>UV: Lock vertex buffer[bNdx]
    alt Lock fails (vb == null)
        UV->>UV: continue to next bNdx
    else Lock succeeds
        loop For each tree
            UV->>Tree: Check bufferNdx != bNdx?
            alt bufferNdx == -1 (absent/deleted)
                UV->>UV: skip (continue)
            else bufferNdx matches
                UV->>Tree: Write push-aside vertices at firstIndex
            end
        end
    end
Loading

Reviews (4): Last reviewed commit: "implemented review feedback" | Re-trigger Greptile

@githubawn githubawn marked this pull request as draft April 2, 2026 22:37
@githubawn githubawn marked this pull request as ready for review April 2, 2026 23:42
@githubawn
Copy link
Copy Markdown
Author

Undrafted, thought I ran into regression, but this happened on weekly as well. Ready for review.

@xezon xezon changed the title fix(W3DTreeBuffer): Fix updateVertexBuffer crash fix(treebuffer): Fix crash in W3DTreeBuffer::loadTreesInVertexAndIndexBuffers Apr 3, 2026
@xezon xezon changed the title fix(treebuffer): Fix crash in W3DTreeBuffer::loadTreesInVertexAndIndexBuffers bugfix(treebuffer): Fix crash in W3DTreeBuffer::loadTreesInVertexAndIndexBuffers Apr 3, 2026
@xezon xezon changed the title bugfix(treebuffer): Fix crash in W3DTreeBuffer::loadTreesInVertexAndIndexBuffers bugfix(treebuffer): Fix crash in W3DTreeBuffer::updateVertexBuffer() Apr 3, 2026
@xezon xezon added Major Severity: Minor < Major < Critical < Blocker ZH Relates to Zero Hour Crash This is a crash, very bad labels Apr 3, 2026
@xezon xezon added this to the Stability fixes milestone Apr 3, 2026
@xezon xezon merged commit 78221a0 into TheSuperHackers:main Apr 6, 2026
23 checks passed
@githubawn githubawn deleted the fix/tree-crash branch April 6, 2026 19:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Crash This is a crash, very bad Major Severity: Minor < Major < Critical < Blocker ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants