I'm having an issue in my MUD where players sometimes will inadvertantly crash us by killing a mob. It is random, and it takes time for it to happen but it seems to happen without fail eventually.
I booted up the mud in GDB and got this feedback.
Program received signal SIGSEGV, Segmentation fault.
0x000000000045e4c5 in act (AType=1045,
format=0x20000000d <Address 0x20000000d out of bounds>, ch=0xd63e50,
arg1=0x0, arg2=0x0, type=0) at comm.c:3167
3167 if ( !format || format[0] == '\0' )
has this happened to anyone else? how was it resolved? help please!
I didn't find anything about this particular one at www.smaugmuds.org, but it'd probably be a pretty good place to look, even if you're not using SmaugFUSS (though I'd have to say that you'd have far less trouble, in general, if you were, but I also understand that sometimes it's not practical to change codebases that way). I can't say that I've seen this particular one myself before but perhaps if you could give us a little more info? Maybe show us a few lines of the code in your comm.c before and after that one?
/*
* Discard null and zero-length messages.
*/
if ( !format || format[0] == '\0' )
return;
if ( !ch )
{
bug( "Act: null ch. (%s)", format );
return;
}
// Do some proper type checking here.. Sort of. We base it on the $* params.
// This is kinda lame really, but I suppose in some weird sense it beats having
// to pass like 8 different NULL parameters every time we need to call act()..
for (str = format; *str; ++str)
{
if (*str == '$')
{
if (!*++str)
break;
switch(*str)
{
default:
bug( "Act: bad code %c for format %s.", *str, format );
break;
case 't':
flags1 |= ACTF_TXT;
obj1 = NULL;
break;
case 'T':
case 'd':
flags2 |= ACTF_TXT;
vch = NULL;
obj2 = NULL;
break;
case 'n': case 'e': case 'm': case 's': case 'q':
break;
case 'N': case 'E': case 'M': case 'S': case 'Q':
flags2 |= ACTF_CH;
obj2 = NULL;
break;
if (flags1 != ACTF_NONE && flags1 != ACTF_TXT && flags1 != ACTF_CH && flags1 != ACTF_OBJ)
{
bug("Act: arg1 has more than one type in format %s. Setting all NULL.", format);
obj1 = NULL;
}
if (flags2 != ACTF_NONE && flags2 != ACTF_TXT && flags2 != ACTF_CH && flags2 != ACTF_OBJ)
{
bug("Act: arg2 has more than one type in format %s. Setting all NULL.", format);
vch = NULL;
obj2 = NULL;
}
if ( !ch->in_room )
to = NULL;
else if ( type == TO_CHAR )
to = ch;
else
to = ch->in_room->first_person;
/*
* ACT_SECRETIVE handling
*/
if ( IS_NPC(ch) && xIS_SET(ch->act, ACT_SECRETIVE) && type != TO_CHAR )
return;
if ( type == TO_VICT )
{
if ( !vch )
{
bug( "Act: null vch with TO_VICT." );
bug( "%s (%s)", ch->name, format );
return;
}
if ( !vch->in_room )
{
bug( "Act: vch in NULL room!" );
bug( "%s -> %s (%s)", ch->name, vch->name, format );
return;
}
to = vch;
/* to = vch->in_room->first_person;*/
}
if ( MOBtrigger && type != TO_CHAR && type != TO_VICT && to )
{
OBJ_DATA *to_obj;
/* Anyone feel like telling me the point of looping through the whole
room when we're only sending to one char anyways..? -- Alty */
for ( ; to; to = (type == TO_CHAR || type == TO_VICT)
? NULL : to->next_in_room )
{
if ((!to->desc
&& ( IS_NPC(to) && !HAS_PROG(to->pIndexData, ACT_PROG) ))
|| !IS_AWAKE(to) )
continue;
if ( type == TO_CHAR && to != ch )
continue;
if ( type == TO_VICT && ( to != vch || to == ch ) )
continue;
if ( type == TO_ROOM && to == ch )
continue;
if ( type == TO_NOTVICT && (to == ch || to == vch) )
continue;
if ( type == TO_CANSEE && ( to == ch ||
(!IS_NPC(ch) && (xIS_SET(ch->act, PLR_WIZINVIS)
&& (get_trust(to) < (ch->pcdata ? ch->pcdata->wizinvis : 0) ) ) ) ) )
continue;
if ( IS_IMMORTAL(to) )
txt = act_string (format, to, ch, arg1, arg2, STRING_IMM);
else
txt = act_string (format, to, ch, arg1, arg2, STRING_NONE);
if (to->desc)
{
if ( AType == AT_COLORIZE )
{
if ( txt[0] == '&' )
send_to_char_color( txt, to );
else
{
set_char_color(AT_MAGIC, to );
write_to_buffer( to->desc, txt, strlen(txt) );
}
}
else {
set_char_color(AType, to);
write_to_buffer( to->desc, txt, strlen(txt) );
}
}
if (MOBtrigger)
{
/* Note: use original string, not string with ANSI. -- Alty */
mprog_act_trigger( txt, to, ch, (OBJ_DATA *)arg1, (void *)arg2 );
}
}
MOBtrigger = TRUE;
return;
}
If you log into the forum (in the top RH corner of this message) you can delete your own messages.
Program received signal SIGSEGV, Segmentation fault.
0x000000000045e4c5 in act (AType=1045,
format=0x20000000d <Address 0x20000000d out of bounds>, ch=0xd63e50,
arg1=0x0, arg2=0x0, type=0) at comm.c:3167
3167 if ( !format || format[0] == '\0' )
You can do a backtrace by typing "bt" in gdb once you see this message. See my posting at http://mushclient.com/gdb for using gdb.
Judging by what little I see here, in comm.c at line 3167, it is accessing the pointer "format" which is not nil, however its value looks invalid to me (0x20000000d) which probably means it is corrupted. For example 20 is a space and 0d is a carriage-return.
Since the function you posted has not changed format at that point, it has been corrupted earlier, which is why you need to see the backtrace. However memory corruption can be a funny thing, the real culprit might have happened a few minutes earlier.
If possible I would upgrade to SmaugFUSS, Smaug 1.4a has lots of known bugs, which is why SmaugFUSS (fixed up smaug source) was released.
Failing that, possibly you might detect it with a hardware watch point, which detects when variables change. If the variable (format) always changes to 0x20000000d and not some random value, then watching it for that particular value might show the exact moment it gets corrupted (look for "watch" in my gdb posting).
Also read the gdb post for conditional breakpoints. Maybe one of those would detect the corruption of format before it got too far away to see why it happened.
(gdb) bt
#0 0x000000000045e563 in act (AType=1045, format=0x20000000d <Address 0x20000000d out of bounds>, ch=0xe451c0, arg1=0x0, arg2=0x0, type=0)
at comm.c:3178
#1 0x000000000047732f in death_cry (ch=0xe451c0) at fight.c:6387
#2 0x00000000004b5c1a in mprog_death_trigger (killer=<value optimized out>, mob=0xe451c0) at mud_prog.c:2435
#3 0x0000000000477ab5 in raw_kill (ch=0xf85da0, victim=0xe451c0) at fight.c:6544
#4 0x000000000047be68 in damage (ch=0xf85da0, victim=0xe451c0, dam=1344, dt=1006) at fight.c:4674
#5 0x000000000047d47a in one_hit (ch=0xf85da0, victim=0xe451c0, dt=1006) at fight.c:2576
#6 0x00000000004d4c56 in do_hitall (ch=0xf85da0, argument=<value optimized out>) at skills.c:8109
#7 0x00000000004de6bf in check_skill (ch=0xf85da0, command=<value optimized out>, argument=0x7fffffffe196 "") at skills.c:795
#8 0x000000000048fc19 in interpret (ch=0xf85da0, argument=0x7fffffffe196 "") at interp.c:660
#9 0x0000000000463017 in game_loop () at comm.c:684
#10 0x0000000000463847 in main (argc=<value optimized out>, argv=0x7fffffffe758) at comm.c:331
(gdb)
I'm thinking it is in the death cry since or death triggers since it happens when something is about to die... I've googled up, this doesn't seem to be a common smaug error. As far as switching bases - not really likely... I've been working on this code for 4 years... this has just always been something we've sort of dealt with. It really needs to get fixed... blahhhh. This is confusing
Make sure you rm *.o (or make clean) to get each file compiled without the optimization.
You seem to be calling act from the function death_cry at fight.c line 6387 with an invalid value for format. Can you show the lines around that spot in fight.c - especially where it establishes a value for format?
That makes sense... Since it seems random, could be a longer death cry crashing it -- I did do a make clean... the lines it is calling to are as follows---
I just commented the whole thing out - I think it was something as simple as the wrong vnum in there to generate body parts, but I saw little importance of having that code anyway.