Skip to content

Conversation

@Stubbjax
Copy link

Closes #2214

This change fixes a crash caused by spawning a CreateDebris object with an assigned Shadow by initializing the shadow name to an empty string.

When the shadow name is uninitialized, checks for '\0' and strlen <= 1 fail and garbage data is instead passed to various locations that do not expect it nor know how to deal with it.

@Stubbjax Stubbjax self-assigned this Jan 30, 2026
@Stubbjax Stubbjax added Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Stability Concerns stability of the runtime Crash This is a crash, very bad Mod Relates to Mods or modding labels Jan 30, 2026
@greptile-apps
Copy link

greptile-apps bot commented Jan 30, 2026

Greptile Overview

Greptile Summary

Fixed a critical crash caused by uninitialized Shadow::ShadowTypeInfo struct members by adding a default constructor that initializes all fields to safe values. The crash occurred when creating debris objects with shadows because uninitialized m_ShadowName contained garbage data that bypassed validation checks (m_ShadowName[0] != '\0' and strlen <= 1), causing invalid texture names to be passed to the shadow system.

The fix introduces a constructor for ShadowTypeInfo that:

  • Initializes m_ShadowName[0] to '\0' (empty string)
  • Sets m_type to SHADOW_NONE
  • Initializes all boolean and numeric fields to safe defaults

All instantiation sites across 13 files have been updated to use constructor initialization (Shadow::ShadowTypeInfo()) instead of uninitialized struct declarations. This change also allowed removal of redundant manual zero assignments in several locations, making the code cleaner while being more robust.

The fix addresses the root cause systematically by ensuring all ShadowTypeInfo instances start with valid, predictable values.

Confidence Score: 5/5

  • This PR is safe to merge - it fixes a critical crash bug with a clean, comprehensive solution
  • The fix is textbook-perfect for addressing uninitialized memory bugs. It adds proper initialization at the type level (constructor), then updates all usage sites to leverage it. The changes are consistent across both Generals and GeneralsMD codebases, reduce code duplication, and eliminate the undefined behavior that caused crashes.
  • No files require special attention

Important Files Changed

Filename Overview
Generals/Code/GameEngine/Include/GameClient/Shadow.h Added default constructor to ShadowTypeInfo that initializes all members to safe defaults, preventing use of garbage data
GeneralsMD/Code/GameEngine/Include/GameClient/Shadow.h Added default constructor to ShadowTypeInfo that initializes all members to safe defaults, preventing use of garbage data
Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DDebrisDraw.cpp Changed to use constructor initialization instead of uninitialized struct, removing redundant manual zero assignments
GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DDebrisDraw.cpp Changed to use constructor initialization instead of uninitialized struct, removing redundant manual zero assignments

Sequence Diagram

sequenceDiagram
    participant Code as Calling Code
    participant ST as ShadowTypeInfo
    participant SM as W3DShadowManager
    participant PS as W3DProjectedShadow
    
    Note over Code,PS: Before Fix: Uninitialized Memory
    Code->>ST: Shadow::ShadowTypeInfo shadowInfo
    Note over ST: m_ShadowName contains garbage data
    Code->>ST: shadowInfo.m_type = SHADOW_DECAL
    Code->>SM: addShadow(&shadowInfo)
    SM->>PS: Check shadowInfo->m_ShadowName[0] != '\0'
    Note over PS: Garbage data causes check to pass!
    PS->>PS: strlen(shadowInfo->m_ShadowName)
    Note over PS: strlen reads garbage, may exceed bounds
    PS->>PS: strcpy(texture_name, shadowInfo->m_ShadowName)
    Note over PS: Invalid texture name copied
    PS-->>Code: CRASH! Invalid texture name used
    
    Note over Code,PS: After Fix: Properly Initialized
    Code->>ST: Shadow::ShadowTypeInfo shadowInfo = Shadow::ShadowTypeInfo()
    Note over ST: Constructor sets m_ShadowName[0] = '\0'
    Note over ST: All members initialized to safe defaults
    Code->>ST: shadowInfo.m_type = SHADOW_DECAL
    Code->>SM: addShadow(&shadowInfo)
    SM->>PS: Check shadowInfo->m_ShadowName[0] != '\0'
    Note over PS: Check fails (empty string)
    PS->>PS: Uses default texture name instead
    PS-->>Code: Success! Shadow created safely
Loading

@Caball009
Copy link

Caball009 commented Jan 30, 2026

Perhaps there should be a default constructor for Shadow::ShadowTypeInfo where this is handled, instead of relying on each call construction site to do the right thing.

@Stubbjax
Copy link
Author

Perhaps there should be a default constructor for Shadow::ShadowTypeInfo where this is handled, instead of relying on each call construction site to do the right thing.

Good thinking. Updated!

@Mauller
Copy link

Mauller commented Jan 30, 2026

Does this tend to only get hit under mod use?

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 Gen Relates to Generals Minor Severity: Minor < Major < Critical < Blocker Mod Relates to Mods or modding Stability Concerns stability of the runtime ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ObjectCreationList CreateDebris object with SHADOW_DECAL Shadow parameter has null texture

3 participants