Skip to content

Commit

Permalink
checkReferences: More exhaustive checks, also check mission lists
Browse files Browse the repository at this point in the history
  • Loading branch information
past-due committed Mar 3, 2024
1 parent 2dce1a5 commit b3ed776
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 48 deletions.
131 changes: 84 additions & 47 deletions src/objmem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,78 +90,115 @@ void objmemShutdown()

// Check that psVictim is not referred to by any other object in the game. We can dump out some extra data in debug builds that help track down sources of dangling pointer errors.
#ifdef DEBUG
#define BADREF(func, line) "Illegal reference to object %d from %s line %d", psVictim->id, func, line
#define BADREF(func, line) "Illegal reference to object %d from %s line %d in %s[%u]", psVictim->id, func, line, listName, player
#else
#define BADREF(func, line) "Illegal reference to object %d", psVictim->id
#define BADREF(func, line) "Illegal reference to object %d in %s[%u]", psVictim->id, listName, player
#endif
static bool checkReferences(BASE_OBJECT *psVictim)

static bool _checkStructReferences(BASE_OBJECT *psVictim, const PlayerObjectList<STRUCTURE>& psPlayerStructList, unsigned player, const char* listName)
{
for (int plr = 0; plr < MAX_PLAYERS; ++plr)
for (const STRUCTURE *psStruct : psPlayerStructList)
{
for (const STRUCTURE *psStruct : apsStructLists[plr])
if (psStruct == psVictim)
{
if (psStruct == psVictim)
{
continue; // Don't worry about self references.
}
continue; // Don't worry about self references.
}

for (unsigned i = 0; i < psStruct->numWeaps; ++i)
{
ASSERT_OR_RETURN(false, psStruct->psTarget[i] != psVictim, BADREF(psStruct->targetFunc[i], psStruct->targetLine[i]));
}
for (unsigned i = 0; i < psStruct->numWeaps; ++i)
{
ASSERT_OR_RETURN(false, psStruct->psTarget[i] != psVictim, BADREF(psStruct->targetFunc[i], psStruct->targetLine[i]));
}

if (psStruct->pFunctionality && psStruct->pStructureType)
if (psStruct->pFunctionality && psStruct->pStructureType)
{
switch (psStruct->pStructureType->type)
{
switch (psStruct->pStructureType->type)
case REF_FACTORY:
case REF_CYBORG_FACTORY:
case REF_VTOL_FACTORY:
{
case REF_FACTORY:
case REF_CYBORG_FACTORY:
case REF_VTOL_FACTORY:
{
FACTORY *psFactory = &psStruct->pFunctionality->factory;
ASSERT_OR_RETURN(false, psFactory->psCommander != psVictim, "Illegal reference to object %" PRIu32 " in FACTORY.psCommander", psFactory->psCommander->id);
break;
}
case REF_REPAIR_FACILITY:
{
REPAIR_FACILITY *psRepairFac = &psStruct->pFunctionality->repairFacility;
ASSERT_OR_RETURN(false, psRepairFac->psObj != psVictim, "Illegal reference to object %" PRIu32 " in REPAIR_FACILITY.psObj", psRepairFac->psObj->id);
break;
}
case REF_REARM_PAD:
FACTORY *psFactory = &psStruct->pFunctionality->factory;
ASSERT_OR_RETURN(false, psFactory->psCommander != psVictim, "Illegal reference to object %" PRIu32 " in FACTORY.psCommander in %s[%u]", psFactory->psCommander->id, listName, player);
break;
}
case REF_POWER_GEN:
{
POWER_GEN *powerGen = &psStruct->pFunctionality->powerGenerator;
for (int i = 0; i < NUM_POWER_MODULES; ++i)
{
REARM_PAD *psReArmPad = &psStruct->pFunctionality->rearmPad;
ASSERT_OR_RETURN(false, psReArmPad->psObj != psVictim, "Illegal reference to object %" PRIu32 " in REARM_PAD.psObj", psReArmPad->psObj->id);
break;
ASSERT_OR_RETURN(false, powerGen->apResExtractors[i] != psVictim, "Illegal reference to object %" PRIu32 " in POWER_GEN.apResExtractors[%d] in %s[%u]", powerGen->apResExtractors[i]->id, i, listName, player);
}
default:
break;
break;
}
case REF_RESOURCE_EXTRACTOR:
{
RES_EXTRACTOR *psResExtracter = &psStruct->pFunctionality->resourceExtractor;
ASSERT_OR_RETURN(false, psResExtracter->psPowerGen != psVictim, "Illegal reference to object %" PRIu32 " in RES_EXTRACTOR.psPowerGen in %s[%u]", psResExtracter->psPowerGen->id, listName, player);
break;
}
case REF_REPAIR_FACILITY:
{
REPAIR_FACILITY *psRepairFac = &psStruct->pFunctionality->repairFacility;
ASSERT_OR_RETURN(false, psRepairFac->psObj != psVictim, "Illegal reference to object %" PRIu32 " in REPAIR_FACILITY.psObj in %s[%u]", psRepairFac->psObj->id, listName, player);
break;
}
case REF_REARM_PAD:
{
REARM_PAD *psReArmPad = &psStruct->pFunctionality->rearmPad;
ASSERT_OR_RETURN(false, psReArmPad->psObj != psVictim, "Illegal reference to object %" PRIu32 " in REARM_PAD.psObj in %s[%u]", psReArmPad->psObj->id, listName, player);
break;
}
default:
break;
}
}
for (const DROID *psDroid : apsDroidLists[plr])
}
return true;
}

static bool _checkDroidReferences(BASE_OBJECT *psVictim, const PlayerObjectList<DROID>& psPlayerDroidList, unsigned player, const char* listName)
{
for (const DROID *psDroid : psPlayerDroidList)
{
if (psDroid == psVictim)
{
if (psDroid == psVictim)
{
continue; // Don't worry about self references.
}
continue; // Don't worry about self references.
}

ASSERT_OR_RETURN(false, psDroid->order.psObj != psVictim, "Illegal reference to object %d", psVictim->id);
ASSERT_OR_RETURN(false, psDroid->order.psObj != psVictim, "Illegal reference to object %d in order.psObj in %s[%u]", psVictim->id, listName, player);

ASSERT_OR_RETURN(false, psDroid->psBaseStruct != psVictim, "Illegal reference to object %d", psVictim->id);
ASSERT_OR_RETURN(false, psDroid->psBaseStruct != psVictim, "Illegal reference to object %d in psBaseStruct in %s[%u]", psVictim->id, listName, player);

for (unsigned i = 0; i < psDroid->numWeaps; ++i)
for (unsigned i = 0; i < psDroid->numWeaps; ++i)
{
if (psDroid->psActionTarget[i] == psVictim)
{
if (psDroid->psActionTarget[i] == psVictim)
{
ASSERT_OR_RETURN(false, psDroid->psActionTarget[i] != psVictim, BADREF(psDroid->actionTargetFunc[i], psDroid->actionTargetLine[i]));
}
ASSERT_OR_RETURN(false, psDroid->psActionTarget[i] != psVictim, BADREF(psDroid->actionTargetFunc[i], psDroid->actionTargetLine[i]));
}
}
}
return true;
}

#define checkPlrStructReferences(psVictim, psPerPlayerStructLists) \
_checkStructReferences(psVictim, psPerPlayerStructLists[plr], plr, #psPerPlayerStructLists)

#define checkPlrDroidReferences(psVictim, psPerPlayerDroidLists) \
_checkDroidReferences(psVictim, psPerPlayerDroidLists[plr], plr, #psPerPlayerDroidLists)

static bool checkReferences(BASE_OBJECT *psVictim)
{
for (unsigned plr = 0; plr < MAX_PLAYERS; ++plr)
{
checkPlrStructReferences(psVictim, apsStructLists);
checkPlrStructReferences(psVictim, mission.apsStructLists);

checkPlrDroidReferences(psVictim, apsDroidLists);
checkPlrDroidReferences(psVictim, mission.apsDroidLists);
}
return true;
}

/* Remove an object from the destroyed list, finally freeing its memory
* Hopefully by this time, no pointers still refer to it! */
static bool objmemDestroy(BASE_OBJECT *psObj)
Expand Down
5 changes: 4 additions & 1 deletion src/objmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@
#include <array>
#include <list>

template <typename ObjectType>
using PlayerObjectList = std::list<ObjectType*>;

/* The lists of objects allocated */
template <typename ObjectType, unsigned PlayerCount>
using PerPlayerObjectLists = std::array<std::list<ObjectType*>, PlayerCount>;
using PerPlayerObjectLists = std::array<PlayerObjectList<ObjectType>, PlayerCount>;

using PerPlayerDroidLists = PerPlayerObjectLists<DROID, MAX_PLAYERS>;
using DroidList = typename PerPlayerDroidLists::value_type;
Expand Down

0 comments on commit b3ed776

Please sign in to comment.