19 Dec, 2008, Banner wrote in the 1st comment:
Votes: 0
This bug has been randomly crashing my MUD for a few weeks now and I just now got a gdb stack from it. I'm not sure what the problem is, so all help is appreciated. It's from a mob prog on a bounty mob. When the mob dies, it loads another mob, forces that mob to load a corpse object, object, forces the mob to drop the corpse object, then transfers that mob to a purge room.

Frame 4:
(gdb) bt
#0 0x0000003b492305c5 in raise () from /lib64/libc.so.6
#1 0x0000003b49232070 in abort () from /lib64/libc.so.6
#2 0x00000000004bcbd0 in SegVio () at comm.c:431
#3 <signal handler called>
#4 0x000000000054f52c in mprog_driver (com_list=0xb18980 "mpmload 329\n\rmpforce mobslave mpoload 10212\n\rmpforce mobslave drop all\n\rmptransfer mobslave 7\n\r",
mob=0x14e16b0, actor=0x18a77c0, obj=0x0, vo=0x0, single_step=0 '\0') at mud_prog.c:1516
#5 0x00000000005511f3 in mprog_percent_check (mob=0x14e16b0, actor=0x18a77c0, obj=0x0, vo=0x0, type=16) at mud_prog.c:2250
#6 0x00000000005517fb in mprog_death_trigger (killer=0x18a77c0, mob=0x14e16b0) at mud_prog.c:2423
#7 0x00000000004edff9 in raw_kill (ch=0x18a77c0, victim=0x14e16b0) at fight.c:2298
#8 0x00000000004ecf6e in damage (ch=0x18a77c0, victim=0x14e16b0, dam=1592, dt=1003) at fight.c:1847
#9 0x00000000004eabfb in one_hit (ch=0x18a77c0, victim=0x14e16b0, dt=1003) at fight.c:1196
#10 0x00000000004b58b8 in do_hitall (ch=0x18a77c0, argument=0x7fff1d7fca16 "") at combat.c:719
#11 0x000000000057d17e in check_skill (ch=0x18a77c0, command=0x7fff1d7fc4e0 "hitall", argument=0x7fff1d7fca16 "") at skills.c:395
#12 0x0000000000519886 in interpret (ch=0x18a77c0, argument=0x7fff1d7fca16 "") at interp.c:376
#13 0x00000000004bdd1d in game_loop () at comm.c:788
#14 0x00000000004bc92e in main (argc=2, argv=0x7fff1d7fcf48) at comm.c:302


(gdb) frame 4
#4 0x000000000054f52c in mprog_driver (com_list=0xb18980 "mpmload 329\n\rmpforce mobslave mpoload 10212\n\rmpforce mobslave drop all\n\rmptransfer mobslave 7\n\r",
mob=0x14e16b0, actor=0x18a77c0, obj=0x0, vo=0x0, single_step=0 '\0') at mud_prog.c:1516
1516 for( vch = mob->in_room->first_person; vch; vch = vch->next_in_room )
(gdb) list
1511 * you may be chosen as the random player. -Narn
1512 *
1513 */
1514
1515 count = 0;
1516 for( vch = mob->in_room->first_person; vch; vch = vch->next_in_room )
1517 if( !IS_NPC( vch ) )
1518 {
1519 if( number_range( 0, count ) == 0 )
1520 rndm = vch;
(gdb) print mob->name
$5 = 0xb188e0 "Toodan"
(gdb) print vch->name
Cannot access memory at address 0x180
(gdb) print *vch
Cannot access memory at address 0x0
(gdb)


mud_prog.c, 1516:
for( vch = mob->in_room->first_person; vch; vch = vch->next_in_room ) /* Line 1516 */
if( !IS_NPC( vch ) )
{
if( number_range( 0, count ) == 0 )
rndm = vch;
count++;
}


It appears to be crashing because vch is null, and my suggested fix would be to put "vch &&" in the ifcheck, but it's crashing on the for statement and not the ifcheck. What should I do?
19 Dec, 2008, Davion wrote in the 2nd comment:
Votes: 0
It looks like this mprog is being called after the mob is killed. The memory might not even be allocated ATM. Try looking in raw_kill to see exactly where the death trigger is called, and what happens prior to the call. Might have something to do with the mob being freed before it has time to execute. It may also be because the mob is being removed from the room prior to the prog call. I'd start in raw_kill, and step through the code and see exactly what's going on. Also, from frame 4, you might wanna try printing mob->in_room, and mob->in_room->first_person
19 Dec, 2008, Hades_Kane wrote in the 3rd comment:
Votes: 0
I believe in most for loops in my game, we have it set up more like:

for( vch = mob->in_room->first_person; vch != NULL; vch = vch->next_in_room )


Note the "vch != NULL" there in the middle. I don't know if that might be the problem or not. I know a lot of times, putting these in the form of (vch) or (!vch) works to determine whether or not they are NULL, but adding in the '!= NULL' shouldn't hurt to try.

Also something else I've noticed in loops like that is that my game seems to prefer them written like:

for( vch = mob->in_room->first_person; vch != NULL; vch = vch_next )
{
vch_next = vch->next_in_room;


I'm not sure why exactly, but I've found the for loops to be much more stable when written like that.

I'm sure someone could give a bit better advice, but those are two things about the checks that looked funny to me.

Also, not to call into question your methods, but is there any particular reason why you are relying on a secondary mob to perform all of the actions of what I think the original, dying mob, should be able to handle?
19 Dec, 2008, Banner wrote in the 4th comment:
Votes: 0
Frame 4
(gdb) frame 4
#4 0x000000000054f52c in mprog_driver (com_list=0xb18980 "mpmload 329\n\rmpforce mobslave mpoload 10212\n\rmpforce mobslave drop all\n\rmptransfer mobslave 7\n\r",
mob=0x14e16b0, actor=0x18a77c0, obj=0x0, vo=0x0, single_step=0 '\0') at mud_prog.c:1516
1516 for( vch = mob->in_room->first_person; vch; vch = vch->next_in_room )
(gdb) print mob->in_room
$1 = (ROOM_INDEX_DATA *) 0x0
(gdb) print mob->in_room->first_person
Cannot access memory at address 0x10
(gdb) q


And I went to raw_kill and found where the death_trigger is called. The mob, for all intents and purposes, should still be in the room. This prog only crashes sometimes. It works whenever I try to duplicate it and mostly when players use it, but it crashes randomly for some odd reason. I know it's something obscure and hard to find. -_-

Raw_kill:
void raw_kill( CHAR_DATA * ch, CHAR_DATA * victim )
{

CHAR_DATA *victmp;
CHAR_DATA *vendor;
HISCORE *table;
CHAR_DATA *owner;
CLAN_DATA *clan;
FELLOW_DATA *fellow;
char buf[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
char arg[MAX_STRING_LENGTH];
char cmd[MSL];
OBJ_DATA *obj, *obj_next;
SHIP_DATA *ship;


if( !victim )
{
bug( "raw_kill: null victim!", 0 );
return;
}

strcpy( arg, victim->name );

stop_fighting( victim, TRUE );

if( ch && !IS_NPC( ch ) && !IS_NPC( victim ) )
claim_disintigration( ch, victim );

/* Take care of polymorphed chars */
if( IS_NPC( victim ) && IS_SET( victim->act, ACT_POLYMORPHED ) )
if( IS_NPC( victim ) && IS_SET( victim->act, ACT_POLYMORPHED ) )
{
char_from_room( victim->desc->original );
char_to_room( victim->desc->original, victim->in_room );
victmp = victim->desc->original;
do_revert( victim, "" );
raw_kill( ch, victmp );
return;
}

if( !IS_NPC(victim) && IS_SET( victim->act, PLR_AFK) && !IS_SET( victim->pcdata->flags, PCFLAG_TWIT))
{
sprintf( buf, "%s being passed through raw_kill .. %s is AFK!!", victim->name, victim->name );
log_string_plus( buf, LOG_NORMAL, sysdata.log_level );
}

if( victim->in_room && IS_NPC( victim ) && victim->vip_flags != 0 && victim->in_room->area
&& victim->in_room->area->planet )
{
victim->in_room->area->planet->population–;
victim->in_room->area->planet->population = UMAX( victim->in_room->area->planet->population, 0 );
victim->in_room->area->planet->pop_support -= ( float )( 1 + 1 / ( victim->in_room->area->planet->population + 1 ) );
if( victim->in_room->area->planet->pop_support < -100 )
victim->in_room->area->planet->pop_support = -100;
}


if( IS_NPC( victim ) && !IS_SET( victim->act, ACT_NOKILL ) )
{
mprog_death_trigger( ch, victim );
if( char_died( victim ) )
return;
}


if( IS_NPC( victim ) && !IS_SET( victim->act, ACT_NOKILL ) )
{
rprog_death_trigger( ch, victim );
if( char_died( victim ) )
return;
}
19 Dec, 2008, Banner wrote in the 5th comment:
Votes: 0
Hades_Kane said:
I believe in most for loops in my game, we have it set up more like:

for( vch = mob->in_room->first_person; vch != NULL; vch = vch->next_in_room )


Whereas I've never seen that kind of for statement before, that may actually solve my problem since it appears vch is null. I may have to try that.

Hades_Kane said:
for( vch = mob->in_room->first_person; vch != NULL; vch = vch_next )
{
vch_next = vch->next_in_room;


Minus the vch != NULL part, I have one instance of that in my code. I'm not sure why it does it either, because as long as it's not freeing that data up, I'm unsure as to why it would do that to begin with.

Hades_Kane said:
Also, not to call into question your methods, but is there any particular reason why you are relying on a secondary mob to perform all of the actions of what I think the original, dying mob, should be able to handle?

I'm not quite sure, but I don't think it works when you do it that way. I was always taught to invoke a second mob to perform actions instead of using the dying mob.
19 Dec, 2008, Davion wrote in the 6th comment:
Votes: 0
What about prior to the raw_kill call in damage()? Just guessing… This bug is really odd. Usually randomness points to some flaw in the memory, but it does infact look like the mob is removed from the room before it dies.
19 Dec, 2008, Banner wrote in the 7th comment:
Votes: 0
Hades_Kane said:
Also, not to call into question your methods, but is there any particular reason why you are relying on a secondary mob to perform all of the actions of what I think the original, dying mob, should be able to handle?

Banner said:
I'm not quite sure, but I don't think it works when you do it that way. I was always taught to invoke a second mob to perform actions instead of using the dying mob.

I actually just tested it and the corpse object stays on the original corpse, and since the bounty mob needs to be nocorpse (so the players won't be confused, and instead pick up the newly generate corpsed object to claim for BH experience), that wouldn't entirely work.
19 Dec, 2008, Scandum wrote in the 8th comment:
Votes: 0
Davion said:
What about prior to the raw_kill call in damage()? Just guessing… This bug is really odd. Usually randomness points to some flaw in the memory, but it does infact look like the mob is removed from the room before it dies.

Yup, in_room is NULL so that's why it crashes in the for loop. Guess he'll have to figure out why the mob is removed from the room.
19 Dec, 2008, Scandum wrote in the 9th comment:
Votes: 0
Banner said:
I'm not quite sure, but I don't think it works when you do it that way. I was always taught to invoke a second mob to perform actions instead of using the dying mob.

You might need to alter the deathprog code for commands like drop to work. Pseudo code:

mprog_death_trigger( )
{
mob->position = POS_STANDING;

mprog_percent_check (mob, bli, bla, blo, DEATH_PROG);

mob->position = POS_DEAD;
}
19 Dec, 2008, Davion wrote in the 10th comment:
Votes: 0
Banner said:
Hades_Kane said:
I believe in most for loops in my game, we have it set up more like:

for( vch = mob->in_room->first_person; vch != NULL; vch = vch->next_in_room )


Whereas I've never seen that kind of for statement before, that may actually solve my problem since it appears vch is null. I may have to try that.

I find this highly unlikely. It looks though that you aren't crashing because of the lack of vch, but because in_room is NULL. When you try to access a member of a NULL pointer, you will crash. It -does- crash in the for loop, but not because of "vch = vch->next_in_room" it crashes because of vch = mob->in_room->first_person.
19 Dec, 2008, Banner wrote in the 11th comment:
Votes: 0
Davion said:
What about prior to the raw_kill call in damage()? Just guessing… This bug is really odd. Usually randomness points to some flaw in the memory, but it does infact look like the mob is removed from the room before it dies.

There is nothing moving anyone up above that line either.
19 Dec, 2008, Davion wrote in the 12th comment:
Votes: 0
Post your mprog_death_trigger. Seems to also call another prog from there anyways. May be in there that things are snarfed (after all, there's a check in raw_kill to see if the player has died.)
19 Dec, 2008, Banner wrote in the 13th comment:
Votes: 0
Davion said:
Post your mprog_death_trigger. Seems to also call another prog from there anyways. May be in there that things are snarfed (after all, there's a check in raw_kill to see if the player has died.)


mprog_death_trigger
void mprog_death_trigger( CHAR_DATA * killer, CHAR_DATA * mob )
{
if( IS_NPC( mob ) && killer != mob && ( mob->pIndexData->progtypes & DEATH_PROG ) )
{
mprog_percent_check( mob, killer, NULL, NULL, DEATH_PROG );
}
death_cry(mob);
return;
}
19 Dec, 2008, Davion wrote in the 14th comment:
Votes: 0
And farther still! Post mprog_percent_check. Also, maybe step through all those frames checking mob's (aka, 0x14e16b0) in_room to see if it's NULL to begin with, or if it happens somewhere after the prog is triggered.
19 Dec, 2008, Banner wrote in the 15th comment:
Votes: 0
Davion said:
And farther still! Post mprog_percent_check. Also, maybe step through all those frames checking mob's (aka, 0x14e16b0) in_room to see if it's NULL to begin with, or if it happens somewhere after the prog is triggered.


mprog_percent_check
void mprog_percent_check( CHAR_DATA * mob, CHAR_DATA * actor, OBJ_DATA * obj, void *vo, int type ) 
{
MPROG_DATA *mprg;

for( mprg = mob->pIndexData->mudprogs; mprg; mprg = mprg->next )
if( ( mprg->type & type ) && ( number_percent( ) <= atoi( mprg->arglist ) ) )
{
mprog_driver( mprg->comlist, mob, actor, obj, vo, FALSE );
if( type != GREET_PROG && type != ALL_GREET_PROG )
break;
}

return;

}


How do I step through like you said?
19 Dec, 2008, Banner wrote in the 16th comment:
Votes: 0
gdb output for first_person:
(gdb) frame 8
#8 0x00000000004ecf6e in damage (ch=0x18a77c0, victim=0x14e16b0, dam=1592, dt=1003) at fight.c:1847
1847 raw_kill( ch, victim );
(gdb) print mob->in-room
No symbol "mob" in current context.
(gdb) print victim->in_room
$1 = (ROOM_INDEX_DATA *) 0x0
(gdb) frame 9
#9 0x00000000004eabfb in one_hit (ch=0x18a77c0, victim=0x14e16b0, dt=1003) at fight.c:1196
1196 if( ( retcode = damage( ch, victim, dam, dt ) ) != rNONE )
(gdb) print victim->in_room
$2 = (ROOM_INDEX_DATA *) 0x0
(gdb) frame 10
#10 0x00000000004b58b8 in do_hitall (ch=0x18a77c0, argument=0x7fff1d7fca16 "") at combat.c:719
719 global_retcode = one_hit( ch, vch, TYPE_UNDEFINED );
(gdb) print vch->in_room
$3 = (ROOM_INDEX_DATA *) 0x0
(gdb) print ch->in_room
$4 = (ROOM_INDEX_DATA *) 0xb22f80
(gdb) print ch->in_room->first_person->name
$5 = 0x977dd0 "Tarki"
(gdb) print vh->in_room->first_person->name
No symbol "vh" in current context.
(gdb) print vch->in_room->first_person->name
Cannot access memory at address 0x10
(gdb) frame 11
#11 0x000000000057d17e in check_skill (ch=0x18a77c0, command=0x7fff1d7fc4e0 "hitall", argument=0x7fff1d7fca16 "") at skills.c:395
395 ( *skill_table[sn]->skill_fun ) ( ch, argument );
(gdb)


Appears to be null to begin with, although I don't see how it can be since the player and the mob are in the same room.. :rolleyes:
19 Dec, 2008, Davion wrote in the 17th comment:
Votes: 0
#0  0x0000003b492305c5 in raise () from /lib64/libc.so.6
#1 0x0000003b49232070 in abort () from /lib64/libc.so.6
#2 0x00000000004bcbd0 in SegVio () at comm.c:431
#3 <signal handler called>
#4 0x000000000054f52c in mprog_driver (com_list=0xb18980 "mpmload 329\n\rmpforce mobslave mpoload 10212\n\rmpforce mobslave drop all\n\rmptransfer mobslave 7\n\r",
mob=0x14e16b0, actor=0x18a77c0, obj=0x0, vo=0x0, single_step=0 '\0') at mud_prog.c:1516
#5 0x00000000005511f3 in mprog_percent_check (mob=0x14e16b0, actor=0x18a77c0, obj=0x0, vo=0x0, type=16) at mud_prog.c:2250
#6 0x00000000005517fb in mprog_death_trigger (killer=0x18a77c0, mob=0x14e16b0) at mud_prog.c:2423
#7 0x00000000004edff9 in raw_kill (ch=0x18a77c0, victim=0x14e16b0) at fight.c:2298
#8 0x00000000004ecf6e in damage (ch=0x18a77c0, victim=0x14e16b0, dam=1592, dt=1003) at fight.c:1847
#9 0x00000000004eabfb in one_hit (ch=0x18a77c0, victim=0x14e16b0, dt=1003) at fight.c:1196
#10 0x00000000004b58b8 in do_hitall (ch=0x18a77c0, argument=0x7fff1d7fca16 "") at combat.c:719
#11 0x000000000057d17e in check_skill (ch=0x18a77c0, command=0x7fff1d7fc4e0 "hitall", argument=0x7fff1d7fca16 "") at skills.c:395
#12 0x0000000000519886 in interpret (ch=0x18a77c0, argument=0x7fff1d7fca16 "") at interp.c:376
#13 0x00000000004bdd1d in game_loop () at comm.c:788
#14 0x00000000004bc92e in main (argc=2, argv=0x7fff1d7fcf48) at comm.c:302

Ok, those pound signs with a corresponding number are your frame numbers. You can enter -any- frame if you have the number via 'frame <number' from gdb. Once in there, you have access to all the local variables (you can type 'info locals' I believe to view all of them) So first off start in raw_kill (frame 7) and print victim->in_room (who is 0x14e16b0). Then hop into frame 6, via "frame 6" and print mob->in_room (who is now our 0x14e16b0), so on and so forth. Untill you find the point where in_room is 0x0 (or NULL.) Don't let these hex numbers(0x14e16b0) confuse you, they're just a memory address and help you keep track of which pointer points where. So when the variable name changes, you know exactly which mob it is.
19 Dec, 2008, Davion wrote in the 18th comment:
Votes: 0
Ok… post do_hitall. If this yields nothing, then it may be safe to say that this mob isn't in the room (atleast from the mobs point of view) to begin with…
19 Dec, 2008, Banner wrote in the 19th comment:
Votes: 0
do_hitall:
/* External from fight.c */
ch_ret one_hit args( ( CHAR_DATA * ch, CHAR_DATA * victim, int dt ) );
void do_hitall( CHAR_DATA * ch, char *argument )
{
CHAR_DATA *vch;
CHAR_DATA *vch_next;
sh_int nvict = 0;
sh_int nhit = 0;
sh_int percent;

if( IS_SET( ch->in_room->room_flags, ROOM_SAFE ) )
{
send_to_char( "You cannot do that here.\n\r", ch );
return;
}

if( !ch->in_room->first_person )
{
send_to_char( "There's no one here!\n\r", ch );
return;
}
percent = IS_NPC( ch ) ? 80 : ch->pcdata->learned[gsn_hitall];
for( vch = ch->in_room->first_person; vch; vch = vch_next )
{
vch_next = vch->next_in_room;
if( is_same_group( ch, vch ) || !is_legal_kill( ch, vch ) || !can_see( ch, vch ) || is_safe( ch, vch )
|| !IS_NPC( vch ) )
continue;
if( ++nvict > ch->skill_level[COMBAT_ABILITY] / 5 )
break;
if( chance( ch, percent ) )
{
nhit++;
global_retcode = one_hit( ch, vch, TYPE_UNDEFINED );
}
else
global_retcode = damage( ch, vch, 0, TYPE_UNDEFINED );
/*
* Fireshield, etc. could kill ch too.. :>.. – Altrag
*/
if( global_retcode == rCHAR_DIED || global_retcode == rBOTH_DIED || char_died( ch ) )
return;
}
if( !nvict )
{
send_to_char( "There's no one here!\n\r", ch );
return;
}
ch->move = UMAX( 0, ch->move - nvict * 3 + nhit );
if( nhit )
learn_from_success( ch, gsn_hitall );
else
learn_from_failure( ch, gsn_hitall );
return;
}
19 Dec, 2008, Davion wrote in the 20th comment:
Votes: 0
Well… I'm going to blame Altrag *grin*. All I can say is it looks like your mob, somewhere down the line is being removed from the room, but not the list. And I honestly have no clue how that could ever happen. Somehow mob->in_room is being set to NULL, but not axed from the list. It's very peculiar. I take it that this is a core, and you're not able to recreate this crash?
0.0/67