<URL: http://bugs.freeciv.org/Ticket/Display.html?id=40033 >
Some helpful debugging improvements, and other niceties found along the way: * sanity checking with file and line * clear city and unit pointers on free() * always pair create_unit_virtual() with destroy_unit_virtual() * moved kill_dying_players() out of player packet handling (plrhand.c) into server main (srv_main.c), the only place it's called now (3 times). * for MacOSX, die() doesn't give a traceback. Fake a bad memory access. Only in nation_of_player(). Probably should do this elsewhere, too.
Index: server/srv_main.c =================================================================== --- server/srv_main.c (revision 14266) +++ server/srv_main.c (working copy) @@ -557,6 +557,33 @@ } players_iterate_end; } +/**************************************************************************** + Check all players to see whether they are dying. + + WARNING: do not call this while doing any handling of players, units, + etc. If a player dies, all his units will be wiped and other data will + be overwritten. + + FIXME: merge is_alive (105) with is_dying (8) and surrendered (7)? +****************************************************************************/ +static void kill_dying_players(void) +{ + players_iterate(pplayer) { + if (pplayer->is_alive) { + /* cities or units remain? */ + if (0 == city_list_size(pplayer->cities) + && 0 == unit_list_size(pplayer->units)) { + pplayer->is_dying = TRUE; + } + /* also F_GAMELOSS in unittools server_remove_unit() */ + if (pplayer->is_dying) { + pplayer->is_dying = FALSE; /* Can't get more dead than this. */ + kill_player(pplayer); + } + } + } players_iterate_end; +} + /************************************************************************** Called at the start of each (new) phase to do AI activities. **************************************************************************/ Index: server/settlers.c =================================================================== --- server/settlers.c (revision 14266) +++ server/settlers.c (working copy) @@ -1343,7 +1343,7 @@ -result.result : result.result); pcity->ai.founder_boat = result.overseas; } - free(virtualunit); + destroy_unit_virtual(virtualunit); } /************************************************************************** @@ -1377,7 +1377,7 @@ NULL); want = (want - unit_food_upkeep(virtualunit) * FOOD_WEIGHTING) * 100 / (40 + unit_foodbox_cost(virtualunit)); - free(virtualunit); + destroy_unit_virtual(virtualunit); /* Massage our desire based on available statistics to prevent * overflooding with worker type units if they come cheap in Index: server/sanitycheck.c =================================================================== --- server/sanitycheck.c (revision 14266) +++ server/sanitycheck.c (working copy) @@ -25,41 +25,47 @@ #include "map.h" #include "movement.h" #include "player.h" +#include "specialist.h" #include "terrain.h" #include "unit.h" #include "unitlist.h" #include "citytools.h" #include "maphand.h" -#include "sanitycheck.h" +#include "srv_main.h" #include "unittools.h" +#include "sanitycheck.h" + #ifdef SANITY_CHECKING #define SANITY_CHECK(x) \ do { \ if (!(x)) { \ - freelog(LOG_ERROR, "Failed sanity check: %s (%s:%d)", \ - #x, __FILE__,__LINE__); \ + freelog(LOG_ERROR, "Failed %s:%d (%s:%d): %s", \ + __FILE__,__LINE__, file, line, #x); \ } \ } while(0) #define SANITY_TILE(ptile, check) \ do { \ if (!(check)) { \ - freelog(LOG_ERROR, "Failed sanity check at %s (%d, %d): " \ - "%s (%s:%d)", ptile->city ? city_name(ptile->city) \ - : ptile->terrain->name.vernacular, TILE_XY(ptile), \ - #check, __FILE__,__LINE__); \ + struct city *pcity = tile_get_city(ptile); \ + freelog(LOG_ERROR, "Failed %s:%d (%s:%d) at %s (%d,%d): %s", \ + __FILE__,__LINE__, file, line, \ + NULL != pcity ? city_name(pcity) \ + : terrain_rule_name(tile_get_terrain(ptile)), \ + TILE_XY(ptile), #check); \ } \ } while(0) #define SANITY_CITY(pcity, check) \ do { \ if (!(check)) { \ - freelog(LOG_ERROR, "Failed sanity check in %s[%d](%d, %d): " \ - "%s (%s:%d)", city_name(pcity), pcity->size, \ - TILE_XY(pcity->tile), #check, __FILE__,__LINE__); \ + freelog(LOG_ERROR, "Failed %s:%d (%s:%d) in %s[%d](%d,%d): %s", \ + __FILE__,__LINE__, file, line, \ + city_name(pcity), (pcity)->size, \ + TILE_XY((pcity)->tile), #check); \ } \ } while(0) @@ -67,7 +73,7 @@ /************************************************************************** Sanity checking on map (tile) specials. **************************************************************************/ -static void check_specials(void) +static void check_specials(const char *file, int line) { whole_map_iterate(ptile) { const struct terrain *pterrain = tile_get_terrain(ptile); @@ -93,7 +99,7 @@ /************************************************************************** Sanity checking on fog-of-war (visibility, shared vision, etc.). **************************************************************************/ -static void check_fow(void) +static void check_fow(const char *file, int line) { whole_map_iterate(ptile) { players_iterate(pplayer) { @@ -109,9 +115,9 @@ * defined. */ if (game.info.fogofwar) { if (plr_tile->seen_count[v] > 0) { - SANITY_TILE(ptile, BV_ISSET(ptile->tile_seen[v], pplayer->player_no)); + SANITY_TILE(ptile, BV_ISSET(ptile->tile_seen[v], player_index(pplayer))); } else { - SANITY_TILE(ptile, !BV_ISSET(ptile->tile_seen[v], pplayer->player_no)); + SANITY_TILE(ptile, !BV_ISSET(ptile->tile_seen[v], player_index(pplayer))); } } @@ -134,7 +140,7 @@ /************************************************************************** Miscellaneous sanity checks. **************************************************************************/ -static void check_misc(void) +static void check_misc(const char *file, int line) { int nbarbs = 0; players_iterate(pplayer) { @@ -151,7 +157,7 @@ /************************************************************************** Sanity checks on the map itself. See also check_specials. **************************************************************************/ -static void check_map(void) +static void check_map(const char *file, int line) { whole_map_iterate(ptile) { struct city *pcity = tile_get_city(ptile); @@ -161,7 +167,7 @@ CHECK_MAP_POS(ptile->x, ptile->y); CHECK_NATIVE_POS(ptile->nat_x, ptile->nat_y); - if (ptile->city) { + if (NULL != pcity) { SANITY_TILE(ptile, tile_owner(ptile) != NULL); } if (tile_owner(ptile) != NULL) { @@ -344,13 +350,13 @@ /************************************************************************** Sanity checks on all cities in the world. **************************************************************************/ -static void check_cities(void) +static void check_cities(const char *file, int line) { players_iterate(pplayer) { city_list_iterate(pplayer->cities, pcity) { SANITY_CITY(pcity, city_owner(pcity) == pplayer); - sanity_check_city(pcity); + real_sanity_check_city(pcity, file, line); } city_list_iterate_end; } players_iterate_end; @@ -378,7 +384,7 @@ /************************************************************************** Sanity checks on all units in the world. **************************************************************************/ -static void check_units(void) { +static void check_units(const char *file, int line) { players_iterate(pplayer) { unit_list_iterate(pplayer->units, punit) { struct tile *ptile = punit->tile; @@ -446,11 +452,12 @@ /************************************************************************** Sanity checks on all players. **************************************************************************/ -static void check_players(void) +static void check_players(const char *file, int line) { int player_no; players_iterate(pplayer) { + int one = player_index(pplayer); int found_palace = 0; if (!pplayer->is_alive) { @@ -467,11 +474,12 @@ } city_list_iterate_end; players_iterate(pplayer2) { - SANITY_CHECK(pplayer->diplstates[pplayer2->player_no].type - == pplayer2->diplstates[pplayer->player_no].type); - if (pplayer->diplstates[pplayer2->player_no].type == DS_CEASEFIRE) { - SANITY_CHECK(pplayer->diplstates[pplayer2->player_no].turns_left - == pplayer2->diplstates[pplayer->player_no].turns_left); + int two = player_index(pplayer2); + SANITY_CHECK(pplayer->diplstates[two].type + == pplayer2->diplstates[one].type); + if (pplayer->diplstates[two].type == DS_CEASEFIRE) { + SANITY_CHECK(pplayer->diplstates[two].turns_left + == pplayer2->diplstates[one].turns_left); } if (pplayer->is_alive && pplayer2->is_alive @@ -517,7 +525,7 @@ /**************************************************************************** Sanity checking on teams. ****************************************************************************/ -static void check_teams(void) +static void check_teams(const char *file, int line) { int count[MAX_NUM_TEAMS], i; @@ -538,7 +546,7 @@ /************************************************************************** Sanity checking on connections. **************************************************************************/ -static void check_connections(void) +static void check_connections(const char *file, int line) { /* est_connections is a subset of all_connections */ SANITY_CHECK(conn_list_size(game.all_connections) @@ -554,21 +562,21 @@ can't call it in the middle of an operation that is supposed to be atomic. **************************************************************************/ -void sanity_check(void) +void real_sanity_check(const char *file, int line) { if (!map_is_empty()) { /* Don't sanity-check the map if it hasn't been created yet (this * happens when loading scenarios). */ - check_specials(); - check_map(); - check_cities(); - check_units(); - check_fow(); + check_specials(file, line); + check_map(file, line); + check_cities(file, line); + check_units(file, line); + check_fow(file, line); } - check_misc(); - check_players(); - check_teams(); - check_connections(); + check_misc(file, line); + check_players(file, line); + check_teams(file, line); + check_connections(file, line); } #endif /* SANITY_CHECKING */ Index: server/sanitycheck.h =================================================================== --- server/sanitycheck.h (revision 14266) +++ server/sanitycheck.h (working copy) @@ -25,7 +25,8 @@ # define sanity_check_city(x) real_sanity_check_city(x, __FILE__, __LINE__) void real_sanity_check_city(struct city *pcity, const char *file, int line); -void sanity_check(void); +# define sanity_check() real_sanity_check(__FILE__, __LINE__) +void real_sanity_check(const char *file, int line); #else /* SANITY_CHECKING */ Index: server/plrhand.c =================================================================== --- server/plrhand.c (revision 14266) +++ server/plrhand.c (working copy) @@ -97,36 +97,15 @@ send_global_city_turn_notifications(dest); } -/**************************************************************************** - Check all players to see if they are dying. Kill them if so. - - WARNING: do not call this while doing any handling of players, units, - etc. If a player dies, all his units will be wiped and other data will - be overwritten. -****************************************************************************/ -void kill_dying_players(void) -{ - players_iterate(pplayer) { - if (pplayer->is_alive) { - if (unit_list_size(pplayer->units) == 0 - && city_list_size(pplayer->cities) == 0) { - pplayer->is_dying = TRUE; - } - if (pplayer->is_dying) { - kill_player(pplayer); - } - } - } players_iterate_end; -} - /************************************************************************** Murder a player in cold blood. + + Called only from srv_main kill_dying_players() **************************************************************************/ void kill_player(struct player *pplayer) { bool palace; - pplayer->is_dying = FALSE; /* Can't get more dead than this. */ pplayer->is_alive = FALSE; /* Remove shared vision from dead player to friends. */ @@ -1146,7 +1125,8 @@ void make_contact(struct player *pplayer1, struct player *pplayer2, struct tile *ptile) { - int player1 = player_number(pplayer1), player2 = player_number(pplayer2); + int player1 = player_index(pplayer1); + int player2 = player_index(pplayer2); if (pplayer1 == pplayer2 || !pplayer1->is_alive Index: server/plrhand.h =================================================================== --- server/plrhand.h (revision 14266) +++ server/plrhand.h (working copy) @@ -33,7 +33,6 @@ bool initmap, bool needs_team); void server_remove_player(struct player *pplayer); void kill_player(struct player *pplayer); -void kill_dying_players(void); void update_revolution(struct player *pplayer); struct nation_type *pick_a_nation(struct nation_type **choices, Index: common/unit.c =================================================================== --- common/unit.c (revision 14266) +++ common/unit.c (working copy) @@ -1454,6 +1454,7 @@ void destroy_unit_virtual(struct unit *punit) { free_unit_orders(punit); + memset(punit, 0, sizeof(*punit)); /* ensure no pointers remain */ free(punit); } Index: common/city.c =================================================================== --- common/city.c (revision 14266) +++ common/city.c (working copy) @@ -2526,5 +2526,6 @@ void remove_city_virtual(struct city *pcity) { unit_list_free(pcity->units_supported); + memset(pcity, 0, sizeof(*pcity)); /* ensure no pointers remain */ free(pcity); } Index: common/game.c =================================================================== --- common/game.c (revision 14266) +++ common/game.c (working copy) @@ -138,9 +138,7 @@ pcity = player_find_city_by_id(unit_owner(punit), punit->homecity); if (pcity) { unit_list_unlink(pcity->units_supported, punit); - } - if (pcity) { freelog(LOG_DEBUG, "home city %s, %s, (%d %d)", city_name(pcity), nation_rule_name(nation_of_city(pcity)), Index: common/nation.c =================================================================== --- common/nation.c (revision 14266) +++ common/nation.c (working copy) @@ -252,13 +252,18 @@ /**************************************************************************** Return the nation of a player. ****************************************************************************/ -struct nation_type *nation_of_player(const struct player *plr) +struct nation_type *nation_of_player(const struct player *pplayer) { - assert(plr != NULL); - if (!bounds_check_nation(plr->nation, LOG_FATAL, "nation_of_player")) { + assert(NULL != pplayer); + if (!bounds_check_nation(pplayer->nation, LOG_FATAL, "nation_of_player")) { +#if defined(__APPLE__) + /* force trace log */ + return ((struct nation_type **)pplayer)[0]; +#else die("bad nation"); +#endif } - return plr->nation; + return pplayer->nation; } /**************************************************************************** Index: client/agents/sha.c =================================================================== --- client/agents/sha.c (revision 14266) +++ client/agents/sha.c (working copy) @@ -89,6 +89,9 @@ assert(pold_unit); unit_list_unlink(previous_units, pold_unit); + /* list pointers were struct copied, cannot destroy_unit_virtual() */ + memset(pold_unit, 0, sizeof(*pold_unit)); /* ensure no pointers remain */ + free(pold_unit); } /**************************************************************************
_______________________________________________ Freeciv-dev mailing list Freeciv-dev@gna.org https://mail.gna.org/listinfo/freeciv-dev