Permalink
Browse files

backport r7136, & r7149 to netplay

---
Introduce ASSERT_OR_RETURN, a macro to assert on an expression, and assert() and then return if it fails,
but only assert() in debug builds.
--
Fix compile on MSVC. Cannot use #ifdef inside a macro.

git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/branches/netplay@7577 4a71c877-e1ca-e34f-864e-861f7616d084
  • Loading branch information...
1 parent e52692a commit ab65cf7953bec9e576e0887b2fb2bc5754a4b411 @buginator buginator committed May 28, 2009
Showing with 66 additions and 148 deletions.
  1. +24 −13 lib/framework/debug.h
  2. +12 −31 src/droid.c
  3. +10 −18 src/feature.c
  4. +2 −2 src/feature.h
  5. +18 −84 src/game.c
View
@@ -54,9 +54,19 @@ extern char last_called_script_event[MAX_EVENT_NAME_LEN];
/** Whether asserts are currently enabled. */
extern bool assertEnabled;
+/** Deals with failure in an assert. Expression is (re-)evaluated for output in the assert() call. */
+#define ASSERT_FAILURE(expr, expr_string, location_description, function, ...) \
+ ( \
+ (void)_debug(LOG_ERROR, function, __VA_ARGS__), \
+ (void)_debug(LOG_ERROR, function, "Assert in Warzone: %s (%s), last script event: '%s'", \
+ location_description, expr_string, last_called_script_event), \
+ ( assertEnabled ? assert(expr) : (void)0 )\
+ )
+
/**
- * ASSERT helper macro to allow some debug functions to use an alternate
- * calling location.
+ * Internal assert helper macro to allow some debug functions to use an alternate calling location.
+ * Expression is only evaluated once if true, if false it is evaluated another time to provide decent
+ * feedback on OSes that have good GUI facilities for asserts and lousy backtrace facilities.
*
* \param expr Expression to assert on.
* \param location_description A string describing the calling location, e.g.:
@@ -71,17 +81,10 @@ extern bool assertEnabled;
*/
#define ASSERT_HELPER(expr, location_description, function, ...) \
( \
- ( \
- (expr) ? /* if (expr) */ \
- (void)0 \
- : /* else */\
- ( \
- (void)_debug(LOG_ERROR, function, __VA_ARGS__), \
- (void)_debug(LOG_ERROR, function, "Assert in Warzone: %s (%s), last script event: '%s'", \
- location_description, (#expr), last_called_script_event) \
- ) \
- ), \
- assertEnabled ? assert(expr) : (void)0 \
+ (expr) ? /* if (expr) */ \
+ (void)0 \
+ : /* else */\
+ ASSERT_FAILURE(expr, #expr, location_description, function, __VA_ARGS__) \
)
/**
@@ -94,6 +97,14 @@ extern bool assertEnabled;
#define ASSERT(expr, ...) \
ASSERT_HELPER(expr, AT_MACRO, __FUNCTION__, __VA_ARGS__)
+/**
+ *
+ * Assert-or-return-zero, macro that returns zero (can also be interpreted as false or NULL) on failure,
+ * and also provides asserts and debug output for debugging.
+ */
+#define ASSERT_OR_RETURN(retval, expr, ...) \
+ do { bool _wzeval = (expr); if (!_wzeval) { ASSERT_FAILURE(expr, #expr, AT_MACRO, __FUNCTION__, __VA_ARGS__); return retval; } } while (0)
+
/**
* Compile time assert
View
@@ -215,7 +215,13 @@ float droidDamage(DROID *psDroid, UDWORD damage, UDWORD weaponClass, UDWORD weap
return relativeDamage;
}
-// Check that psVictimDroid is not referred to by any other object in the game
+// Check that psVictimDroid 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 DROIDREF(func, line) "Illegal reference to droid from %s line %d", func, line
+#else
+#define DROIDREF(func, line) "Illegal reference to droid"
+#endif
BOOL droidCheckReferences(DROID *psVictimDroid)
{
int plr;
@@ -231,49 +237,24 @@ BOOL droidCheckReferences(DROID *psVictimDroid)
for (i = 0; i < psStruct->numWeaps; i++)
{
- if ((DROID *)psStruct->psTarget[i] == psVictimDroid)
- {
-#ifndef DEBUG
- debug(LOG_ERROR, "droidCheckReferences: Illegal reference to droid");
-#else
- ASSERT(!"Illegal reference to droid", "Illegal reference to droid from %s line %d",
- psStruct->targetFunc[i], psStruct->targetLine[i]);
-#endif
- return false;
- }
+ ASSERT_OR_RETURN(false, (DROID *)psStruct->psTarget[i] != psVictimDroid, DROIDREF(psStruct->targetFunc[i], psStruct->targetLine[i]));
}
}
for (psDroid = apsDroidLists[plr]; psDroid != NULL; psDroid = psDroid->psNext)
{
unsigned int i;
- if ((DROID *)psDroid->psTarget == psVictimDroid && psVictimDroid != psDroid)
- {
-#ifndef DEBUG
- debug(LOG_ERROR, "droidCheckReferences: Illegal reference to droid");
-#else
- ASSERT(!"Illegal reference to droid", "Illegal reference to droid from %s line %d",
- psDroid->targetFunc, psDroid->targetLine);
-#endif
- return false;
- }
+ ASSERT_OR_RETURN(false, (DROID *)psDroid->psTarget != psVictimDroid || psVictimDroid == psDroid, DROIDREF(psDroid->targetFunc, psDroid->targetLine));
for (i = 0; i < psDroid->numWeaps; i++)
{
- if ((DROID *)psDroid->psActionTarget[i] == psVictimDroid && psVictimDroid != psDroid)
- {
-#ifndef DEBUG
- debug(LOG_ERROR, "droidCheckReferences: Illegal action reference to droid");
-#else
- ASSERT(!"Illegal reference to droid", "Illegal action reference to droid from %s line %d",
- psDroid->actionTargetFunc[i], psDroid->actionTargetLine[i]);
-#endif
- return false;
- }
+ ASSERT_OR_RETURN(false, (DROID *)psDroid->psActionTarget[i] != psVictimDroid || psVictimDroid == psDroid,
+ DROIDREF(psDroid->actionTargetFunc[i], psDroid->actionTargetLine[i]));
}
}
}
return true;
}
+#undef DROIDREF
/* droidRelease: release all resources associated with a droid -
* should only be called by objmem - use vanishDroid preferably
View
@@ -220,7 +220,7 @@ float featureDamage(FEATURE *psFeature, UDWORD damage, UDWORD weaponClass, UDWOR
{
float relativeDamage;
- ASSERT(psFeature != NULL, "featureDamage: Invalid feature pointer");
+ ASSERT_OR_RETURN(0.0, psFeature != NULL, "Invalid feature pointer");
debug(LOG_ATTACK, "featureDamage(%d): body %d armour %d damage: %d",
psFeature->id, psFeature->body, psFeature->armour[impactSide][weaponClass], damage);
@@ -374,7 +374,7 @@ FEATURE * buildFeature(FEATURE_STATS *psStats, UDWORD x, UDWORD y,BOOL FromSave)
}
- assert(psFeature->sDisplay.imd); // make sure we have an imd.
+ ASSERT_OR_RETURN(NULL, psFeature->sDisplay.imd, "No IMD for feature"); // make sure we have an imd.
for (width = 0; width <= psStats->baseWidth; width++)
{
@@ -478,30 +478,20 @@ void featureUpdate(FEATURE *psFeat)
// free up a feature with no visual effects
-void removeFeature(FEATURE *psDel)
+bool removeFeature(FEATURE *psDel)
{
UDWORD mapX, mapY, width,breadth, player;
MESSAGE *psMessage;
Vector3i pos;
- ASSERT( psDel != NULL,
- "removeFeature: invalid feature pointer\n" );
-
- if (psDel->died)
- {
- // feature has already been killed, quit
- ASSERT( false,
- "removeFeature: feature already dead" );
- return;
- }
-
+ ASSERT_OR_RETURN(false, psDel != NULL, "Invalid feature pointer");
+ ASSERT_OR_RETURN(false, !psDel->died, "Feature already dead");
if(bMultiPlayer && !ingame.localJoiningInProgress)
{
SendDestroyFeature(psDel); // inform other players of destruction
}
-
//remove from the map data
mapX = map_coord(psDel->pos.x - psDel->psStats->baseWidth * TILE_UNITS / 2);
mapY = map_coord(psDel->pos.y - psDel->psStats->baseBreadth * TILE_UNITS / 2);
@@ -548,10 +538,12 @@ void removeFeature(FEATURE *psDel)
gridRemoveObject((BASE_OBJECT *)psDel);
killFeature(psDel);
+
+ return true;
}
/* Remove a Feature and free it's memory */
-void destroyFeature(FEATURE *psDel)
+bool destroyFeature(FEATURE *psDel)
{
UDWORD widthScatter,breadthScatter,heightScatter, i;
EFFECT_TYPE explosionSize;
@@ -560,8 +552,7 @@ void destroyFeature(FEATURE *psDel)
UDWORD mapX,mapY;
UDWORD texture;
- ASSERT( psDel != NULL,
- "destroyFeature: invalid feature pointer\n" );
+ ASSERT_OR_RETURN(false, psDel != NULL, "Invalid feature pointer");
/* Only add if visible and damageable*/
if(psDel->visible[selectedPlayer] && psDel->psStats->damageable)
@@ -660,6 +651,7 @@ void destroyFeature(FEATURE *psDel)
//---------------------------------------------------------------------------------------
removeFeature(psDel);
+ return true;
}
View
@@ -49,10 +49,10 @@ extern void featureRelease(FEATURE *psFeature);
extern void featureUpdate(FEATURE *psFeat);
// free up a feature with no visual effects
-extern void removeFeature(FEATURE *psDel);
+extern bool removeFeature(FEATURE *psDel);
/* Remove a Feature and free it's memory */
-extern void destroyFeature(FEATURE *psDel);
+extern bool destroyFeature(FEATURE *psDel);
/* get a feature stat id from its name */
extern SDWORD getFeatureStatFromName(const char *pName);
Oops, something went wrong.

0 comments on commit ab65cf7

Please sign in to comment.