Skip to content

Commit

Permalink
game.cpp: Fix loading commander droids without psGroup
Browse files Browse the repository at this point in the history
When a commander transitions from an offworld mission,
it will currently lose its group (actually, this is kind of
a bug, too), i.e. its `psGroup` is `nullptr`.

If a player attempts to save the game right after
this transition and then loads the savegame again,
the game will crash.

`loadSaveDroid()` function will try to allocate
a new group for these "orphaned" returning
commanders.

But this new group ID is not in sync with other
group IDs that may already be present in the
currently-processed "droid.json" file and thus
may clash with other groups, leading to various
memory-related bugs.

For example, this may happen when there is
a commander back at the players' base with
some commander group assigned.

There is a non-zero probability that the
commander which returns from an offworld
mission, will try to allocate the same group ID
as the commander back at the base.

Signed-off-by: Pavel Solodovnikov <[email protected]>
  • Loading branch information
ManManson committed Jan 11, 2024
1 parent e40b8ee commit 8bb06a0
Showing 1 changed file with 11 additions and 1 deletion.
12 changes: 11 additions & 1 deletion src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5552,10 +5552,16 @@ static bool loadSaveDroid(const char *pFileName, PerPlayerDroidLists& ppsCurrent
// Sort list so transports are loaded first, since they must be loaded before the droids they contain.
std::vector<std::pair<int, WzString>> sortedList;
bool missionList = fName.compare("mdroid");
// This will be set to the largest group ID found throughout the droid file + 1.
//
// This helps to allocate non-conflicting group IDs for commanders which
// happen to lose their group, e.g. when transitioning from an offworld mission.
int nextFreeGroupID = 0;
for (size_t i = 0; i < list.size(); ++i)
{
ini.beginGroup(list[i]);
DROID_TYPE droidType = (DROID_TYPE)ini.value("droidType").toInt();
int aigroup = ini.value("aigroup", -1).toInt();
int priority = 0;
switch (droidType)
{
Expand All @@ -5571,6 +5577,10 @@ static bool loadSaveDroid(const char *pFileName, PerPlayerDroidLists& ppsCurrent
{
++priority;
}
if (aigroup >= 0)
{
nextFreeGroupID = std::max(nextFreeGroupID, aigroup) + 1;
}
default:
break;
}
Expand Down Expand Up @@ -5701,7 +5711,7 @@ static bool loadSaveDroid(const char *pFileName, PerPlayerDroidLists& ppsCurrent
{
if (isTransporter(psDroid) || psDroid->droidType == DROID_COMMAND)
{
DROID_GROUP *psGroup = grpCreate();
DROID_GROUP *psGroup = grpCreate(nextFreeGroupID++);
psGroup->add(psDroid);
}
else
Expand Down

0 comments on commit 8bb06a0

Please sign in to comment.