Crossfire Mailing List Archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

CF: Bug found in crossfire 0.92.4




I have already fixed a few bugs in Crossfire 0.92.4 (patches coming
very soon), but one of them got me puzzled for a while.  I got the
error "Trying to remove removed object" several times, and I couldn't
find why.  Now I understand, but I don't know what is the best way to
fix it.  That's why I'm reporting the bug to the list, hoping that
someone will make sensible suggestions.

Here is the description of the bug: if you cast a spell that leaves a
deadly object on the map (such as "pool of chaos", "firewall", "wall
of thorns", etc.) and a multi-square monster gets killed when moving
over it, the game crashes with the error "Trying to remove removed
object".  This happens because the monster is moved by removing it
from its old position, then re-inserting it in the new position.
While doing that, the routine insert_ob_in_map() calls check_walk_on()
to see if the monster is stepping over a special object.  If the
monster gets killed by this object, the routine hit_player() tries to
remove it, but it crashes because the monster (or at least parts of
it) has already been removed and is not yet completely re-inserted in
the map.

Here is a backtrace of what happens when a dragon steps over a wall of
thorns:

>  gdb crossfire core
(gdb) bt
#0  0xef621c1c in _kill ()
#1  0xef5ed834 in abort ()
#2  0x719ec in remove_ob (op=0x289ce8) at object.c:854
#3  0x25098 in hit_player (op=0x289ce8, dam=514, hitter=0x22c510, type=1) at attack.c:792
#4  0x20574 in apply (op=0x28a168, tmp=0x293958) at apply.c:1257
#5  0x73784 in check_walk_on (op=0x28a168) at object.c:1567
#6  0x72a48 in insert_ob_in_map (op=0x28a168, m=0x242260) at object.c:1231
#7  0x725d8 in insert_ob_in_map (op=0x28a048, m=0x242260) at object.c:1143
#8  0x725d8 in insert_ob_in_map (op=0x289f28, m=0x242260) at object.c:1143
#9  0x725d8 in insert_ob_in_map (op=0x289e08, m=0x242260) at object.c:1143
#10 0x725d8 in insert_ob_in_map (op=0x289ce8, m=0x242260) at object.c:1143
#11 0x3b99c in move_object (op=0x289ce8, dir=6) at monster.c:1061
#12 0x399f8 in move_monster (op=0x289ce8) at monster.c:289
#13 0x58b1c in process_object (op=0x289ce8) at time.c:653
#14 0x388dc in process_events (map=0x0) at main.c:692
#15 0x38e74 in main (argc=4, argv=0xeffffaa4, env=0xeffffab8) at main.c:876

In frame #11, move_object() calls insert_ob_in_map() after having
removed it.  In frame #5, insert_ob_in_map() calls check_walk_on(),
which in turn calls hit_player().  Since the dragon's health is below
0, hit_player() tries to remove it and crashes because the dragon has
not been re-inserted in the map yet.

Now my question is: how can we fix that?  A very ugly solution would
be to have yet another global variable which is used as a flag.  This
flag would be set when entering check_walk_on() and reset on exit.  If
the flag is set when some object dies from hit_player(), then
remove_ob() would not be called.  But there must be a better way to do
that...  I'm waiting for your suggestions...

-Raphael