There are 2 issues as i can see it now. On my live game i have had several players type aliases out. The issue here is that when they exceed 256 characters it now rolls over into the next buffer. I have confirmed it by logging the replacement buffer and watched it leak over into they type buffer.
Nov 27 17:41:00 2017 :: 1) read_aliases: abuf = lvleq - count = 99, i = 0
Nov 27 17:41:00 2017 :: 2) read_aliases: rbuf =
get jade orange*get jade orange*rem al*rem al*wear jade*wear jade*get runed orange*get runed orange*wield runed*hold runed* wear hover*get ra orange*get ra orange*rem void*wear ra*wear ra*get cape orange*wear cape*get gloves orange*wear gloves*g
Nov 27 17:41:00 2017 :: 3) read_aliases:
tbuf = et rook orange*wear rook
The issue at hand is: rbuf and tbuf from read_aliases_ascii set up the buffers to be 512. However, get_line() only allows 256 characters. We have no check when we create the alias in do_alias() so you can over subscribe the replication buffer. Once it happens, all your aliases now corrupt. I can share with any of the admin if they care to see it.
I had many ideas on how to solve it, but in the end i went with making a new function that allowed up to MAX_INPUT_LENGTH and than added a check in do_alias().
Code:
static void read_aliases_ascii(FILE *file, struct char_data *ch, int count)
{
int i = 0;
if (count == 0) {
GET_ALIASES(ch) = NULL;
return; /* No aliases in the list. */
}
/* This code goes both ways for the old format (where alias and replacement start at the
* first character on the line) and the new (where they are prepended by a space in order
* to avoid the possibility of a * at the start of the line */
for (i = 0; i < count; i++) {
char abuf[MAX_INPUT_LENGTH+1], rbuf[MAX_INPUT_LENGTH+1], tbuf[MAX_INPUT_LENGTH];
/* Read the aliased command. */
get_line(file, abuf);
/* Read the replacement. This needs to have a space prepended before placing in
* the in-memory struct. The space may be there already, but we can't be certain! */
rbuf[0] = ' ';
get_line_long(file, rbuf+1); ====> made a new function
/* read the type */
get_line(file, tbuf);
if (abuf[0] && rbuf[1] && *tbuf) {
struct alias_data *temp;
CREATE(temp, struct alias_data, 1);
temp->alias = strdup(abuf[0] == ' ' ? abuf+1 : abuf);
temp->replacement = strdup(rbuf[1] == ' ' ? rbuf+1 : rbuf);
temp->type = atoi(tbuf);
temp->next = GET_ALIASES(ch);
GET_ALIASES(ch) = temp;
}
}
}
Code:
int get_line_long(FILE *fl, char *buf)
{
char temp[MAX_INPUT_LENGTH];
int lines = 0;
int sl;
do {
if (!fgets(temp, MAX_INPUT_LENGTH, fl))
return (0);
lines++;
} while (*temp == '*' || *temp == '\n' || *temp == '\r');
/* Last line of file doesn't always have a \n, but it should. */
sl = strlen(temp);
while (sl > 0 && (temp[sl - 1] == '\n' || temp[sl - 1] == '\r'))
temp[--sl] = '\0';
strcpy(buf, temp);
return (lines);
}
In do_alias() I added.
Code:
ACMD(do_alias)
===snippet ===
if (strlen(repl) >= MAX_INPUT_LENGTH){
send_to_char(ch, "You alias is too long, please revise.\r\n");
return;
}
CREATE(a, struct alias_data, 1);
a->alias = strdup(arg);
delete_doubledollar(repl);
a->replacement = strdup(repl);
if (strchr(repl, ALIAS_SEP_CHAR) || strchr(repl, ALIAS_VAR_CHAR))
a->type = ALIAS_COMPLEX;
else
a->type = ALIAS_SIMPLE;
a->next = GET_ALIASES(ch);
GET_ALIASES(ch) = a;
save_char(ch);
send_to_char(ch, "Alias ready.\r\n");