<URL: http://bugs.freeciv.org/Ticket/Display.html?id=39472 >

After some investigation with gdb, it looks to me like the problem is in

void allot_island_improvs(void)
  int i;

  players_iterate(pplayer) {
    pplayer->island_improv = fc_realloc(pplayer->island_improv,
                                        (map.num_continents + 1)
                                        * game.num_impr_types
                                        * sizeof(Impr_Status));
    freelog(LOG_NORMAL, "allot_island_improvs: map.num_continents == %d,
array size == %d",
                        map.num_continents, (map.num_continents + 1) *
    /* We index into this array with the continent number, so don't use
zero */
    for (i = 1; i <= map.num_continents; i++) {
      improvement_status_init(&pplayer->island_improv[i *

    /* Fill the lists with existent improvements with Island equiv_range */
    city_list_iterate(pplayer->cities, pcity) {
      Continent_id cont = map_get_continent(pcity->tile);
      freelog(LOG_NORMAL, "allot_island_improvs: cont == %d, array index
== %d", cont, cont * game.num_impr_types);
      Impr_Status *improvs = 
                           &pplayer->island_improv[cont *

      built_impr_iterate(pcity, id) {
        if (improvement_types[id].equiv_range != IR_ISLAND) {
        improvs[id] = pcity->improvements[id];
      } built_impr_iterate_end;
    } city_list_iterate_end;
  } players_iterate_end;

  improvements_update_redundant(NULL, NULL, 0, IR_WORLD);  

According to the log output this function is called several times at the
beginning of a turn, with the number of continents (map.num_continents)
starting at a low number and increasing to the total number of
continents in the following calls. With the provided savegame the number
started at 1 and went till 220 in the first turn (after loading the
game) and so the "pplayer->island_improv" array was finally reallocated
to 221*68 = 15028 entries.

In the first call at the beginning of the next turn, map.num_continents
was 5 and so the array was reallocated to 6*68 = 408 entries. But for
the following city list iteration the log output shows continent numbers
(cont) of 71, 53 and 64, which means that the array was accessed at
positions (4828, 3604, 4352) that formally no longer belonged to it
since it was reallocated to 408 entries a few lines ago.

The same happens later in fill_ranges_improv_lists() which fills the
"equiv_list" array with values from the "pplayer->island_improv" array.
When the crash happened, map.num_continents had different values at each
run, but everytime I tried, equiv_list[IR_ISLAND] was filled with a
value from an array position that was calculated from a continent number
higher than map.num_continents. For example, last time I tried,
map.num_continents was 42 and cont was 104.

When I exchanged "(map.num_continents + 1)" in the fc_realloc() call in
allot_island_improvs() by a constant "250", the crash didn't occur
anymore, so I'm quite sure that something is wrong with this function.
But unfortunately I'm not familiar enough with this part of the code to
be able to fix it. Anyone?

Freeciv-dev mailing list

Reply via email to