Skip to content

Commit 3e6a718

Browse files
bugfix(loadscreen): Prevent null dereference in ChallengeLoadScreen::init from invalid campaign/mission
1 parent 28c93dd commit 3e6a718

1 file changed

Lines changed: 33 additions & 4 deletions

File tree

Core/GameEngine/Source/GameClient/GUI/LoadScreen.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -929,16 +929,45 @@ void ChallengeLoadScreen::activatePiecesMinSpec(const GeneralPersona *generalPla
929929

930930
void ChallengeLoadScreen::init( GameInfo *game )
931931
{
932-
const Campaign *campaign = TheCampaignManager->getCurrentCampaign();
933-
const Mission *mission = TheCampaignManager->getCurrentMission();
932+
const Campaign *campaign = TheCampaignManager ? TheCampaignManager->getCurrentCampaign() : NULL;
933+
const Mission *mission = TheCampaignManager ? TheCampaignManager->getCurrentMission() : NULL;
934+
935+
// Guard against null campaign/mission. In release builds DEBUG_ASSERTCRASH is
936+
// compiled out, so without these checks the AsciiString copy constructor below
937+
// would dereference a null pointer and crash (see Sentry CLIENT-33Q).
938+
if (campaign == NULL || mission == NULL)
939+
{
940+
DEBUG_CRASH(("ChallengeLoadScreen::init invoked with null campaign (%p) or mission (%p); aborting load.",
941+
campaign, mission));
942+
return;
943+
}
944+
945+
if (mission->m_generalName.isEmpty())
946+
{
947+
DEBUG_CRASH(("ChallengeLoadScreen::init: mission has empty m_generalName, check Campaign.ini; aborting load."));
948+
return;
949+
}
950+
951+
if (TheChallengeGenerals == NULL)
952+
{
953+
DEBUG_CRASH(("ChallengeLoadScreen::init: TheChallengeGenerals is null; aborting load."));
954+
return;
955+
}
934956

935957
// the player general is tied to the campaign
936958
const GeneralPersona* generalPlayer = TheChallengeGenerals->getPlayerGeneralByCampaignName( campaign->m_name );
937959

938960
// the opponent general is tied to the mission
939-
DEBUG_ASSERTCRASH(mission->m_generalName.isNotEmpty(), ("No GeneralName associated with this mission, check Campaign.ini"));
940961
const GeneralPersona* generalOpponent = TheChallengeGenerals->getGeneralByGeneralName( mission->m_generalName );
941962

963+
if (generalPlayer == NULL || generalOpponent == NULL)
964+
{
965+
DEBUG_CRASH(("ChallengeLoadScreen::init: failed to resolve generals (player=%p, opponent=%p) for campaign '%s' / mission general '%s'; aborting load.",
966+
generalPlayer, generalOpponent,
967+
campaign->m_name.str(), mission->m_generalName.str()));
968+
return;
969+
}
970+
942971
// create the layout of the load screen
943972
m_loadScreen = TheWindowManager->winCreateFromScript( "Menus/ChallengeLoadScreen.wnd" );
944973
DEBUG_ASSERTCRASH(m_loadScreen, ("Can't initialize the single player loadscreen"));
@@ -953,7 +982,7 @@ void ChallengeLoadScreen::init( GameInfo *game )
953982
m_ambientLoop.setEventName("LoadScreenAmbient");
954983

955984
// create the new background video stream
956-
m_videoStream = TheVideoPlayer->open( TheCampaignManager->getCurrentMission()->m_movieLabel );
985+
m_videoStream = TheVideoPlayer->open( mission->m_movieLabel );
957986

958987
// Create the new buffer
959988
m_videoBuffer = TheDisplay->createVideoBuffer();

0 commit comments

Comments
 (0)