From 4035a3c5572b01c5a7b8ecea547ed6732fd2c333 Mon Sep 17 00:00:00 2001 From: "seer-by-sentry[bot]" <157164994+seer-by-sentry[bot]@users.noreply.github.com> Date: Sat, 21 Mar 2026 18:55:12 +0000 Subject: [PATCH] Fix: Prevent out-of-bounds LOD access in HLOD rendering --- .../Libraries/Source/WWVegas/WW3D2/hlod.cpp | 25 ++++++++++++++----- .../Libraries/Source/WWVegas/WW3D2/hlod.cpp | 25 ++++++++++++++----- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/hlod.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/hlod.cpp index 4e8dc5d665e..f9c30340b77 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/hlod.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/hlod.cpp @@ -2144,9 +2144,16 @@ void HLodClass::Render(RenderInfoClass & rinfo) Animatable3DObjClass::Render(rinfo); - for (i = 0; i < Lod[CurLod].Count(); i++) { - if (Lod[CurLod][i].Model->Class_ID() != CLASSID_OBBOX) ///We have no use for these - MW - Lod[CurLod][i].Model->Render(rinfo); + int lod_count = LodCount; + int lod_index = CurLod; + if (lod_index >= lod_count || lod_index < 0) { + lod_index = lod_count - 1; + } + if (lod_index >= 0 && lod_index < lod_count) { + for (i = 0; i < Lod[lod_index].Count(); i++) { + if (Lod[lod_index][i].Model->Class_ID() != CLASSID_OBBOX) ///We have no use for these - MW + Lod[lod_index][i].Model->Render(rinfo); + } } if (Is_Sub_Objects_Match_LOD_Enabled()) { @@ -2183,13 +2190,19 @@ void HLodClass::Special_Render(SpecialRenderInfoClass & rinfo) Animatable3DObjClass::Special_Render(rinfo); + int lod_count = LodCount; int lod_index = CurLod; if (rinfo.RenderType == SpecialRenderInfoClass::RENDER_SHADOW) { // (gth) HACK HACK! yikes - lod_index = LodCount-1; + lod_index = lod_count - 1; + } + if (lod_index >= lod_count || lod_index < 0) { + lod_index = lod_count - 1; } - for (i = 0; i < Lod[lod_index].Count(); i++) { - Lod[lod_index][i].Model->Special_Render(rinfo); + if (lod_index >= 0 && lod_index < lod_count) { + for (i = 0; i < Lod[lod_index].Count(); i++) { + Lod[lod_index][i].Model->Special_Render(rinfo); + } } for (i = 0; i < AdditionalModels.Count(); i++) { diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hlod.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hlod.cpp index e65f7211d6e..1672a07edae 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hlod.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hlod.cpp @@ -2144,9 +2144,16 @@ void HLodClass::Render(RenderInfoClass & rinfo) Animatable3DObjClass::Render(rinfo); - for (i = 0; i < Lod[CurLod].Count(); i++) { - if (Lod[CurLod][i].Model->Class_ID() != CLASSID_OBBOX) ///We have no use for these - MW - Lod[CurLod][i].Model->Render(rinfo); + int lod_count = LodCount; + int lod_index = CurLod; + if (lod_index >= lod_count || lod_index < 0) { + lod_index = lod_count - 1; + } + if (lod_index >= 0 && lod_index < lod_count) { + for (i = 0; i < Lod[lod_index].Count(); i++) { + if (Lod[lod_index][i].Model->Class_ID() != CLASSID_OBBOX) ///We have no use for these - MW + Lod[lod_index][i].Model->Render(rinfo); + } } if (Is_Sub_Objects_Match_LOD_Enabled()) { @@ -2183,13 +2190,19 @@ void HLodClass::Special_Render(SpecialRenderInfoClass & rinfo) Animatable3DObjClass::Special_Render(rinfo); + int lod_count = LodCount; int lod_index = CurLod; if (rinfo.RenderType == SpecialRenderInfoClass::RENDER_SHADOW) { // (gth) HACK HACK! yikes - lod_index = LodCount-1; + lod_index = lod_count - 1; + } + if (lod_index >= lod_count || lod_index < 0) { + lod_index = lod_count - 1; } - for (i = 0; i < Lod[lod_index].Count(); i++) { - Lod[lod_index][i].Model->Special_Render(rinfo); + if (lod_index >= 0 && lod_index < lod_count) { + for (i = 0; i < Lod[lod_index].Count(); i++) { + Lod[lod_index][i].Model->Special_Render(rinfo); + } } for (i = 0; i < AdditionalModels.Count(); i++) {