Hello,
First of all, you did a great job tracking this bug down (yes, it is
actually a bug).
Since you already know what the bug does, and you narrowed it down to
the exact line causing the problem, I'm just going to try to explain
WHY it's doing what it's doing (and tell you the easy fix).
I'll start by explaining strcat(). Strcat acts similar to:
char * strcat(char *dest, const char *src)
{
int i = 0, j = 0;
/* find the end of dest by finding the NUL character */
while ( dest[i] != '\0' )
i++;
/* Copy src into dest */
while( src[j] != '\0' )
{
dest[i] = src[j];
i++;
j++;
}
/* Append a NUL character onto dest */
dest[i] = '\0';
return dest;
}
The first while loop in my example strcat is what's causing the problem.
It scans dest until it finds a NUL character. But bust_a_prompt never
puts a NUL character in buf, so only chance will decide if there is
one there or not. So this little loop runs along happily until it finds
one out in memory somewhere. (possibly somewhere in buf, possibly somewhere
later). Then it copies the string ("none" in this case) there, and appends
a NUL character on the end.
The next time the bust_a_prompt code in question runs the strcat, it might
do the same thing (assuming buf doesn't happen to have a NUL character
hanging around this time). But this time, the nul character it found
last time was overwritten, so it keeps scanning until it finds the next
one--the one strcat just put at the end. So it copies "none" just after
the last one. So you end up with "nonenone". The next time, it would
add another one on, etc.
Enough of the explanation of what's happening. On to why buf is in the
strcat. This part I don't know for sure. I'm just guessing what I think
happened.
Some weird feeling came into me and possessed me to download the rom
source and look up the code for do_exits. When I started looking
through the function, I noticed a great resemblance to the code I
had been looking at in the %e case of bust_a_prompt. The names were
changed, but the structure was not. Apparently whoever put the %e case
in bust_a_prompt copied and pasted from do_exits. The big difference in the
two was that do_exits used buf to print everything into, bust_a_prompt
did not. Since bust_a_prompt already had a variable named buf, whoever
copied the do_exits code into bust_a_prompt had to change the name.
Instead of using buf2 like the rest of the cases (which would have
been a cleaner solution, they added a new buffer to bust_a_prompt,
named doors. After using this buffer, they just copied it straight into
buf2 (using an sprintf for some reason). But, not all instances of "buf"
got changed to "doors". As you discovered, one of them never got changed
to doors.
At least this one has an easy fix. The easiest way to fix it is to
change 'strcat(buf,"none");' into 'strcat(doors,"none");'. The
cleaner way to fix it would be to remove the doors variable from
bust_a_prompt, change all instances of doors to buf2, and remove the
'sprintf(buf2,"%s",doors);' line.
I did a quick search on the web, and as far as I can tell, nobody's
pointed out this bug before. It looks like it probably exists on all
rom muds at least back to 2.4b4 (that's the oldest souce I could find
to look at).
I hope I didn't bore you too much with this nice long letter.
Once I started typing, it just didn't stop coming.
In summary: Using buf in the strcat line didn't make sense to you
because it is wrong. It should be doors (or buf2 if you want to just
completely remove the unnecessary doors variable altogether).
Hope this helps.
Dennis Reed
On Sat, 2 Feb 2002, Anarchangel wrote:
>
> Hello,
>
> My question is regarding bust_a_prompt and the %e (show exits in
> prompt) option.
>
> I know it works properly, because it's stock and there have never been any
> complaints about it on other muds (that I've seen). However, we've run
> into some problems with it over the years. Just to give a little backup
> information, any prior changes to the mud were not done by me, so I have
> no way of checking anything changed recently. It's been doing this for
> quite some time.
>
> Particularly, I've noticed we have buf as MAX_STRING_LENGTH. Further
> down, there is a check to see if str is null, and if so it sets to buf to
> a default prompt of <%ldhp %dm %dmv>. This is all good and well, and I
> understand this.
>
> However, when you check for case 'e' (again, to show exits in the
> prompt) there's a strcat for "none" if no exits are found. Why does it
> use buf, exactly? I realize it may be more efficient, since it does in
> fact work. This is confusing for me and I'm hoping one of you may have
> some insight.
>
> The problem we're having involves this instance of the word none. Every
> now and then some things will start showing up like "nonenonenone". It
> could be titles, roomins, descriptions, sockets.. just about anything
> relating to char_data. It's not always "nonenonenone". Sometimes it will
> be simply "none", or perhaps "onenonenonenone".. many possibilities,
> really. Other times, we'll crash and ch is 0x6e6f6e65, or maybe
> 0x6f6e656e. It's related to bust_a_prompt because I've determined that's
> where the "none" is coming from.
>
> Like I said, I know the problem isn't within bust_a_prompt. For the sake
> of keeping these strange occurences from happening though, I've commented
> it out until I've got the problem nailed down.
>
> If any of you could lend me some insight as to why buf is used as it is,
> that may help me track the problem down. Or better yet, why nonenone is
> happening in the first place.
>
> I apologize if my description isn't very clear, but I'll gladly send more
> information if need be. I don't have a gdb readout because that section
> of the code is commented out, and the problem is no longer happening. I
> suspect it will simply manifest itself elsewhere, though.
>
> Thanks for your time,
>
> Jimmy
>
>
>
>
>