Warning: This message is somewhat long, it describes the steps to
reproduce a bug, and discusses a way to fix it.
I have found a bug on CircleMUD 3.0 bpl18, envolving the
close_socket() and the SWITCH command. Here is a simple way
to reproduce it (greetings and motds stripped):
--
First: find a mob to switch into.
--
500H 100M 82V > go aglandiir
[ 3375] The Lair [ INDOORS NO_TRACK PRIVATE ]
(...)
The Dragon Prince, Aglandiir, sits here looking at you curiously.
...he glows with a bright light!
500H 100M 82V > switch aglandiir
Okay.
Aglandiir>
--
At this point, we break our connection.
--
^]
telnet> close
Connection closed.
Jun 16 21:38:30 :: WARNING: EOF on socket read (connection broken by
peer)
Jun 16 21:38:30 :: Closing link to: God.
Jun 16 21:38:30 :: No connections. Going to sleep.
--
And reconnect...
--
$ telnet localhost 5000
Trying 127.0.0.1...
Jun 16 21:38:32 :: New connection. Waking up.
Connected to localhost.
Escape character is '^]'.
(...)
By what name do you wish to be known? God
Password:
Jun 16 21:38:35 :: God [localhost] has reconnected.
Reconnecting.
500H 100M 82V > switch aglandiir
You can't do that, the body is already in use!
--
Hugh?! Who is using its body???
--
500H 100M 82V > purge aglandiir
Okay.
500H 100M 82V >
Welcome to CircleMUD!
0) Exit from CircleMUD.
1) Enter the game.
2) Enter description.
3) Read the background story.
4) Change password.
5) Delete this character.
Make your choice:
--
Mmmm... something is wrong... I have been sent to the menu...
--
Make your choice: 1
Connection closed by foreign host.
[1]+ Segmentation fault (core dumped) bin/circle 5000
--
Oops...
--
I have found the bug in the close_socket() function:
(...)
if (d->character) {
/*
* Plug memory leak, from Eric Green.
*/
if (!IS_NPC(d->character) && PLR_FLAGGED(d->character, PLR_MAILING)
&& d->str) {
if (*(d->str))
free(*(d->str));
free(d->str);
}
if (STATE(d) == CON_PLAYING || STATE(d) == CON_DISCONNECT) {
struct char_data *link_challenged = d->original ? d->original :
d->character;
/* We are guaranteed to have a person. */
act("$n has lost $s link.", TRUE, link_challenged, 0, 0, TO_ROOM);
save_char(link_challenged, NOWHERE);
sprintf(buf, "Closing link to: %s.", GET_NAME(link_challenged));
mudlog(buf, NRM, MAX(LVL_IMMORT, GET_INVIS_LEV(link_challenged)),
TRUE);
link_challenged->desc = NULL;
} else {
(...)
On the above case, d->original points to the God character,
d->character points to Aglandiir. d->original->desc is already NULL,
because CircleMUD considers linkless a player while it is switched.
close_socket() sets link_challenged->desc to NULL, and leaves
d->character->desc pointing to the descriptor that will be freed on
the end of the function.
Changing the code to...
/*
link_challenged->desc = NULL;
*/
if (d->original && d->original->desc == d)
d->original->desc = NULL;
if (d->character->desc == d)
d->character->desc = NULL;
...fixed the bug for me. Probably, there is no need for doing the
check and the clean on d->original->desc. I couldn't be able to imagine
any circumstance where a character on d->original is linked to a
descriptor. The SWITCH command does a 'ch->desc = NULL;' among other
things. But a sanity check is better than running the risk. The second
check, before doing the clean on d->character->desc, is a sanity check
too. I think that is always expected that 'd->character->desc == d' and
'ch->desc->character == ch' on any normal circumstances.
Regards,
Juliano R Ferraz
Captain ... one .. harmless ... little ... Tribble?
I'm at the corner of Walk and Don't Walk.
--
+---------------------------------------------------------------+
| FAQ: http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html |
| Archives: http://post.queensu.ca/listserv/wwwarch/circle.html |
+---------------------------------------------------------------+
This archive was generated by hypermail 2b30 : 12/05/01 PST