Complete.Org: Mailing Lists: Archives: freeciv-dev: November 2005:
[Freeciv-Dev] (PR#14638) Segfault at common/city.c:756
Home

[Freeciv-Dev] (PR#14638) Segfault at common/city.c:756

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#14638) Segfault at common/city.c:756
From: "Guillaume Melquiond" <guillaume.melquiond@xxxxxxxxx>
Date: Sat, 19 Nov 2005 06:16:11 -0800
Reply-to: bugs@xxxxxxxxxxx

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

This transaction appears to have no content
The function city_can_be_built_here does the following test at line 756:
if (ptile->owner && ptile->owner != punit->owner)

Unfortunately, it doesn't check the validity of punit before deferencing it.
And punit can explicitely be null: "punit is the founding unit, which may be
NULL in some cases (e.g., cities from huts)". Grepping through the source
files shows that "cities from huts" is actually the only case where null can
happen. This is done in the function hut_get_city at
server/unitttools.c:2222.

As a consequence, if the tile of the hut is owned, the server crashes. The
caller is:
if (city_can_be_built_here(punit->tile, NULL))

But hut_get_city obviously knows the unit, so it should just pass it to
city_can_be_built_here. And this function would then simply assert that
punit is not null instead of trying to cope with it. Attached is a patch
against revision 11249.
The function city_can_be_built_here does the following test at line 756:
  if (ptile->owner && ptile->owner != punit->owner)

Unfortunately, it doesn't check the validity of punit before deferencing it. And punit can explicitely be null: "punit is the founding unit, which may be NULL in some cases ( e.g., cities from huts)". Grepping through the source files shows that "cities from huts" is actually the only case where null can happen. This is done in the function hut_get_city at server/unitttools.c:2222.

As a consequence, if the tile of the hut is owned, the server crashes. The caller is:
  if (city_can_be_built_here(punit->tile, NULL))

But hut_get_city obviously knows the unit, so it should just pass it to city_can_be_built_here. And this function would then simply assert that punit is not null instead of trying to cope with it. Attached is a patch against revision 11249.
Index: server/unittools.c
===================================================================
--- server/unittools.c  (révision 11249)
+++ server/unittools.c  (copie de travail)
@@ -2219,7 +2219,7 @@
 {
   struct player *pplayer = unit_owner(punit);
 
-  if (city_can_be_built_here(punit->tile, NULL)) {
+  if (city_can_be_built_here(punit->tile, punit)) {
     notify_player(pplayer, punit->tile, E_HUT_CITY,
                     _("You found a friendly city."));
     create_city(pplayer, punit->tile,
Index: common/city.c
===================================================================
--- common/city.c       (révision 11249)
+++ common/city.c       (copie de travail)
@@ -735,19 +735,20 @@
 
 /**************************************************************************
   Returns TRUE if the given unit can build a city at the given map
-  coordinates.  punit is the founding unit, which may be NULL in some
-  cases (e.g., cities from huts).
+  coordinates.  punit is the founding unit.
 **************************************************************************/
 bool city_can_be_built_here(const struct tile *ptile, const struct unit *punit)
 {
   int citymindist;
 
+  assert(punit);
+
   if (terrain_has_flag(ptile->terrain, TER_NO_CITIES)) {
     /* No cities on this terrain. */
     return FALSE;
   }
 
-  if (punit && !can_unit_exist_at_tile(punit, ptile)) {
+  if (!can_unit_exist_at_tile(punit, ptile)) {
     /* We allow land units to build land cities and sea units to build
      * ocean cities. Air units can build cities anywhere. */
     return FALSE;

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#14638) Segfault at common/city.c:756, Guillaume Melquiond <=