Keep in mind that these are my fixes and might or might not be implemented in the standard RoM-distribution.
Autologoff
Problem
When a player gets auto-logged off other playerfiles can get corrupted.
Cause
The for-loop in char_update doesn’t keep track of the possibility of pets. If a player is auto-logged off and his pet is the next ch_next, player-characters in the freed-characterslist might be saved with invalid strings in their playerfiles.
Patch
In update.c/update_char(), add the following
/*
* Autosave and autoquit.
* Check that these chars still exist.
*/
for ( ch = char_list; ch != NULL; ch = ch_next ) {
+ if (!IS_VALID(ch)) {
+ bug('update_char: Trying to work with an invalidated character.\n');
+ break;
+ }
ch_next = ch->next;
To be sure it never happens again, add this to save.c/save_char_obj():
if ( IS_NPC(ch) )
return;
+ //
+ // Don't save if the character is invalidated.
+ // This might happen during the auto-logoff of players.
+ // (or other places not yet found out)
+ //
+ if ( !IS_VALID(ch)) {
+ bug("save_char_obj: Trying to save an invalidated character.\n");
+ return;
+ }
if ( ch->desc != NULL && ch->desc->original != NULL )
ch = ch->desc->original;
force
Problem
Entering force all quit can corrupt playerfiles.
Cause
The for-loop in the do_force() command doesn’t keep track of the possibility of pets. If a player is forced to quit and his pet is the next vch_next, all player-characters in the freed-characterslist will be saved with invalid strings in their playerfiles.
Patch
Replace in act_wiz.c/do_force():
if ( !str_cmp( arg, "all" ) )
{
CHAR_DATA *vch;
CHAR_DATA *vch_next;
if (get_trust(ch) < MAX_LEVEL - 3) {
send_to_char("Not at your level!\n\r",ch);
return;
}
for ( vch = char_list; vch != NULL; vch = vch_next ) {
vch_next = vch->next;
if ( !IS_NPC(vch) && get_trust( vch ) < get_trust( ch ) ) {
act( buf, ch, NULL, vch, TO_VICT );
interpret( vch, argument );
}
}
}
with
if ( !str_cmp( arg, "all" ) )
{
DESCRIPTOR_DATA *desc,*desc_next;
if (get_trust(ch) < MAX_LEVEL - 3) {
send_to_char("Not at your level!\n\r",ch);
return;
}
for ( desc = descriptor_list; desc != NULL; desc = desc_next ) {
desc_next = desc->next;
if (desc->connected==CON_PLAYING &&
get_trust( desc->character ) < get_trust( ch ) ) {
act( buf, ch, NULL, desc->character, TO_VICT );
interpret( desc->character, argument );
}
}
}
Same thing should be done for the players-force and the gods-force.
$p
Problem
Entering delete $p
crashes the mud.
Cause
When a $p is printed on wiznet, it’s expanded in act_new while it the information required by this expansing isn’t available or valid. This can cause the mud to crash (it will most of the time).
Checking
Login in your mud, make sure you have wiznet on, login with another character, type delete $p. If your mud doesn’t crash you’re not vulnerable.
Patch
In interp.c/interpret(), replace
if ( ( !IS_NPC(ch) && IS_SET(ch->act, PLR_LOG) )
|| fLogAll
|| cmd_table[cmd].log == LOG_ALWAYS )
{
sprintf( log_buf, "Log %s: %s", ch->name, logline );
wiznet(log_buf,ch,NULL,WIZ_SECURE,0,get_trust(ch));
log_string( log_buf );
}
with
if ( ( !IS_NPC(ch) && IS_SET(ch->act, PLR_LOG) )
|| fLogAll
|| cmd_table[cmd].log == LOG_ALWAYS )
{
char s[2*MAX_INPUT_LENGTH],*ps;
int i;
ps=s;
sprintf( log_buf, "Log %s: %s", ch->name, logline );
/* Make sure that was is displayed is what is typed */
for (i=0;log_buf[i];i++) {
*ps++=log_buf[i];
if (log_buf[i]=='$')
*ps++='$';
if (log_buf[i]=='{')
*ps++='{';
}
*ps=0;
wiznet(s,ch,NULL,WIZ_LOGS,0,get_trust(ch));
log_string( log_buf );
}
More $
Problem
It seemed that the $-problem in the previous paragraph gave also problems in the act_new()-function, when you get a string with a $ dollar in it. Perhaps the previous fix was not enough on it’s on, with this is it.
Cause
In act_new(), it’s assumed that all pointers are valid.
Checking
Take a mortal character, let him say “cast ‘bless’ $p” for about 40 times and make sure you have the wiznet-spam option on. If your mud crashes you have to apply the following patch.
Patch
Check the pointers before using them:
case 't': i = (char *) arg1; break;
case 'T': i = (char *) arg2; break;
case 'n': i = PERS( ch, to ); break;
case 'N': i = PERS( vch, to ); break;
case 'e': i = he_she [URANGE(0, ch ->sex, 2)]; break;
etc...
should become
case 't': if (arg1) i=(char *)arg1;
else bug("Act: bad code $t for 'arg1'",0);
break;
case 'T': if (arg2) i=(char *)arg2;
else bug("Act: bad code $T for 'arg2'",0);
break;
case 'n': if (ch&&to) i=PERS(ch,to);
else bug("Act: bad code $n for 'ch' or 'to'",0);
break;
case 'N': if (vch&&to) i=PERS(vch,to);
else bug("Act: bad code $N for 'ch' or 'to'",0);
break;
case 'e': if (ch) i=he_she[URANGE(0,ch->sex,2)];
else bug("Act: bad code $e for 'ch'",0);
break;
etc...
break;
break;
break; // BREAK IT! :-)
Thanks
Thanks to the guy from primenet for telling me the problem (although it was already fixed in our code :-)
Alias
Problem
When assigning alias x to goto 3001 and executing the command x it comes back with a No such location.
Cause
When expanding an alias substitute_alias() always adds a space and the arguments to the command. do_goto() then checks if “goto 3001 “ is an valid location (which it isn’t).
Checking
Login to your mud, alias x to goto 3001, execute
x. If you get No such location
, you have to apply
the patch.
Patch
In alias.c/substitute_alias(), replace
buf[0] = '\0';
strcat(buf,ch->pcdata->alias_sub[alias]);
strcat(buf," ");
strcat(buf,point);</pre>
with
buf[0] = '\0';
strcat(buf,ch->pcdata->alias_sub[alias]);
if (point[0]) {
strcat(buf," ");
strcat(buf,point);
}
More alias’s
Problem
When entering an alias with a ‘ (tick) in it, it will screw up the player-file.
Checking
Create an alias with a ‘ in it, for example ’ ‘hi. Quit the character and enter the mud again. If you type alias, it will display a lot of skill/inventory information also in the alias-list.
Patch
In alias.c/do_alias(), add the following lines:
if (!str_prefix("una",arg) || !str_cmp("alias",arg)) {
send_to_char("Sorry, that word is reserved.\n\r",ch);
return;
}
+ if (strchr(arg,' ')||strchr(arg,'"')||strchr(arg,'\'')) {
+ send_to_char("The word to be aliased should not contain a space, "
+ "a tick or a double-quote.\n\r",ch);
+ return;
+ }
if (argument[0] == '\0')
{
Notes
Problem
When continueing with a note which is too long the mud crashes.
Cause
The function string.c/string_addline() checked for the length of
the variable buf which while this should have been
*ch->desc->pString
.
Checking
Make a note. A long note. A very long note. Wait until it’s long
enough to get the message String too long, last line skipped.
.
Type note edit. Add a line. If the mud now crashes you have
to apply the patch.
Patch
In string.c/string_addline(), replace
/*
* Truncate strings to MAX_STRING_LENGTH.
* --------------------------------------
*/
if ( strlen( buf ) + strlen( argument ) >= ( MAX_STRING_LENGTH - 4 ) )
{
send_to_char( "String too long, last line skipped.\n\r", ch );
with
/*
* Truncate strings to MAX_STRING_LENGTH.
* --------------------------------------
*/
if ( strlen( *ch->desc->pString ) + strlen( argument ) >= ( MAX_STRING_LENGTH - 4 ) )
{
send_to_char( "String too long, last line skipped.\n\r", ch );
Double newbies
Problem
If a person opens two telnet sessions and enters twice the same newbie-name, two players with that name are created on the mud.
Cause
It’s a race-problem: as long as the player-file isn’t saved to disc newbies with this name are accepted.
Checking
Open two telnet-sessions to your mud, in both fill in the same name. Complete the creation procedure for both. Check with who who is online.
Patch
I’ve patched it by adding a new check to comm.c/check_parse_name() function:
/*
* check names of people playing. Yes, this is necessary for multiple
* newbies with the same name (thanks Saro)
*/
if (descriptor_list) {
count=0;
for (d = descriptor_list; d != NULL; d = dnext) {
dnext=d->next;
if (d->connected!=CON_PLAYING&&d->character&&d->character->name
&& d->character->name[0] && !str_cmp(d->character->name,name)) {
count++;
close_socket(d);
}
}
if (count) {
sprintf(log_buf,"Double newbie alert (%s)",name);
wiznet(log_buf,NULL,NULL,WIZ_LOGINS,0,0);
return FALSE;
}
}
Ghost-pets
Problem
Sometimes a player seems to have two or more pets in his group. These pets are not locatable via mwhere.
Cause
It is not sure in how much this is the only cause, but it’s related to getting linkdead, disappearing into void and reconnecting.
Checking
Extend do_mwhere() with the following code:
/* all the mobs without a room */
if (!str_cmp(argument,"nowhere")) {
buffer = new_buf();
found=FALSE;
count=0;
for ( victim = char_list; victim != NULL; victim = victim->next ) {
if (victim->in_room==NULL) {
found = TRUE;
count++;
sprintf( buf, "%3d) [%5d] %-28s %lx\n\r", count,
IS_NPC(victim) ? victim->pIndexData->vnum : 0,
IS_NPC(victim) ? victim->short_descr : victim->name,
(unsigned long)victim);
add_buf(buffer,buf);
}
}
if (found)
page_to_char(buf_string(buffer),ch);
else
send_to_char("No mobs without rooms found.\n\r",ch);
free_buf(buffer);
return;
}
This will display, when you enter mwhere nowhere, all the mobs who aren’t in a room.
Now login with a test-puppet, let him buy a pet, make him link-dead, let him disappear into void and reconnect. Then do the *mwhere nowhere command, you’ll see that one mob is in there (perhaps try it more than once, also reconnecting without making linkdead gives often the same effect).
Patch
In comm.c, add this code to check_reconnect():
else {
+ if (d->character->pet) {
+ CHAR_DATA *pet=d->character->pet;
+
+ char_to_room(pet,get_room_index( ROOM_VNUM_LIMBO));
+ stop_follower(pet);
+ extract_char(pet,TRUE);
+ }
free_char( d->character );
d->character = ch;
ch->desc = d;</pre>
Cause
It seemed that if you enter the game but type the wrong password, there also will popup a ghost-pet.
Patch
In comm.c/nanny, add this code to the CON_GET_OLD_PASSWORD case:
if ( strcmp( crypt( argument, ch->pcdata->pwd ), ch->pcdata->pwd ))
{
sprintf( log_buf, "Denying access to %s@%s (bad password).",
ch->name, d->host );
log_string( log_buf );
wiznet(log_buf,NULL,NULL,WIZ_LOGINS,0,get_trust(ch));
write_to_buffer( d, "Wrong password.\n\r", 0 );
+ if (d->character->pet) {
+ CHAR_DATA *pet=d->character->pet;
+
+ char_to_room(pet,get_room_index( ROOM_VNUM_LIMBO));
+ stop_follower(pet);
+ extract_char(pet,TRUE);
+ }
close_socket( d );
return;
}
Prefix
Problem
When having a prefix and the command entered is too long, the mud will crash.
Cause
The length of the prefix and the length of the command are incorrectly checked against the length of the string they have to form.
Checking
Set your prefix to : and enter a command too long. First a function in comm.c will complain, then your mud will crash.
Patch
In alias.c/substitute_alias(), fix the next lines:
/* check for prefix */
if (ch->prefix[0] != '\0' && str_prefix("prefix",argument)) {
- if (strlen(ch->prefix) + strlen(argument) > MAX_INPUT_LENGTH)
+ if (strlen(ch->prefix) + strlen(argument) > MAX_INPUT_LENGTH-2)
send_to_char("Line to long, prefix not processed.\r\n",ch);
else {
sprintf(prefix,"%s %s",ch->prefix,argument);
argument = prefix;
}
}