23 Mar, 2009, Korax wrote in the 1st comment:
Votes: 0
I thought I'd post this here since my mud is a godwars deriv.
A memory leak has been crashing my mud for sometime now every couple of hours and I believe I've tracked it down in valgrind but I don't have the knowledge to fix it. Any help in fixing it would be greatly appreciated.

==01:06:33:56.291 420== 393,216 bytes in 6 blocks are still reachable in loss record 88 of 103
==01:06:33:56.291 420== at 0x4C206F4: calloc (vg_replace_malloc.c:397)
==01:06:33:56.291 420== by 0x46C823: zlib_alloc (mccp.c:71)
==01:06:33:56.291 420== by 0x4E2BFB8: deflateInit2_ (in /usr/lib/libz.so.1.2.3.3)
==01:06:33:56.291 420== by 0x4E2C113: deflateInit_ (in /usr/lib/libz.so.1.2.3.3)
==01:06:33:56.291 420== by 0x46C8FB: compressStart (mccp.c:107)
==01:06:33:56.291 420== by 0x486008: read_from_buffer (comm.c:1532)
==01:06:33:56.291 420== by 0x484A37: game_loop_unix (comm.c:863)
==01:06:33:56.291 420== by 0x48439F: main (comm.c:497)


zlib_alloc (mccp.c:71)  =  return calloc(items, size);
compressStart (mccp.c:107) = if (deflateInit(s, 9) != Z_OK) {
read_from_buffer (comm.c:1532) = compressStart(d);


Complete functions bellow.

void *zlib_alloc(void *opaque, unsigned int items, unsigned int size)
{
/* memory tracking */
mccp_mem_usage += size;

/* return memory pointer */
return calloc(items, size);
}


/*
* Begin compressing data on `desc'
*/
bool compressStart(DESCRIPTOR_DATA *desc)
{
z_stream *s;

if (desc->out_compress) /* already compressing */
return TRUE;

/* allocate and init stream, buffer */
s = (z_stream *)alloc_mem(sizeof(*s));
desc->out_compress_buf = (unsigned char *)alloc_mem(COMPRESS_BUF_SIZE);

s->next_in = NULL;
s->avail_in = 0;

s->next_out = desc->out_compress_buf;
s->avail_out = COMPRESS_BUF_SIZE;

s->zalloc = zlib_alloc;
s->zfree = zlib_free;
s->opaque = NULL;

if (deflateInit(s, 9) != Z_OK) {
/* problems with zlib, try to clean up */
free_mem(desc->out_compress_buf, COMPRESS_BUF_SIZE);
free_mem(s, sizeof(z_stream));
return FALSE;
}

write_to_descriptor(desc, compress_start, strlen(compress_start));

/* now we're compressing */
desc->out_compress = s;
return TRUE;
}

/*
* Transfer one line from input buffer to input line.
*/
void read_from_buffer( DESCRIPTOR_DATA *d )
{
int i, j, k;
char buf[MSL];

/*
* Hold horses if pending command already.
*/
if ( d->incomm[0] != '\0' )
return;

/*
* Look for at least one new line.
*/
for ( i = 0; d->inbuf[i] != '\n' && d->inbuf[i] != '\r'; i++ )
{
if ( d->inbuf[i] == '\0' )
return;
}

/*
* Canonical input processing.
*/
for ( i = 0, k = 0; d->inbuf[i] != '\n' && d->inbuf[i] != '\r'; i++ )
{
if ( k >= MAX_INPUT_LENGTH - 2 )
{
write_to_descriptor( d, "Line too long.\n\r", 0 );

/* skip the rest of the line */
for ( ; d->inbuf[i] != '\0'; i++ )
{
if ( d->inbuf[i] == '\n' || d->inbuf[i] == '\r' )
break;
}
d->inbuf[i] = '\n';
d->inbuf[i+1] = '\0';
break;
}
if ( d->inbuf[i] == '\b' && k > 0 )
–k;
else if ( isascii(d->inbuf[i]) && isprint(d->inbuf[i]) )
d->incomm[k++] = d->inbuf[i];
/* handling vt100 feedback */
else if (d->inbuf[i] == '\e')
{
char xbuf[30]; // plenty
char *xptr;
int xk = 1;

xbuf[0] = '\0';
xptr = xbuf;

/* first we scan to see if this is really a reply to our request */
while (d->inbuf[i+xk] != 'R' && xk < 10) xk++;

/* I'm sure most screens use at most 999x999 chars */
if (xk < 10)
{
i += 2; xk = 0;
while (d->inbuf[i] != ';' && d->inbuf[i] != '\0' && ++xk < 30)
{
*xptr = d->inbuf[i];
xptr++; i++;
}
*xptr = '\0';
init_vt100(d, xbuf);
}
}
else if (d->inbuf[i] == (signed char)IAC) {
if (!memcmp(&d->inbuf[i], compress_do, strlen(compress_do))) {
i += strlen(compress_do) - 1;
compressStart(d);
}
else if (!memcmp(&d->inbuf[i], compress_dont, strlen(compress_dont))) {
i += strlen(compress_dont) - 1;
compressEnd2(d);
}
}

}

/*
* Finish off the line.
*/
if ( k == 0 )
d->incomm[k++] = ' ';
d->incomm[k] = '\0';

/*
* Deal with bozos with #repeat 1000 …
*/
if ( k > 1 || d->incomm[0] == '!' )
{
if ( d->incomm[0] != '!' && strcmp( d->incomm, d->inlast ) )
{
d->repeat = 0;
}
else
{
if ( ++d->repeat >= 40 )
{
if (d != NULL && d->character != NULL) {
xprintf( buf, "%s input overflow!", d->character->lasthost );
wiznet( buf, NULL, NULL, WIZ_SECURE, 0, 0 );
log_string( LOG_SECURITY, log_buf );
}
else if (d->lookup_status != STATUS_LOOKUP) {
xprintf( buf, "%s input overflow!", d->host );
wiznet( buf, NULL, NULL, WIZ_SECURE, 0, 0 );
log_string( LOG_SECURITY, log_buf );
}
write_to_descriptor( d,
"\n\r*** PUT A LID ON IT!!! ***\n\r", 0 );
xprintf( d->incomm, "quit" );
}
}
}

/*
* Do '!' substitution.
*/
if ( d->incomm[0] == '!' )
strcpy( d->incomm, d->inlast );
else
strcpy( d->inlast, d->incomm );

/*
* Shift the input buffer.
*/
while ( d->inbuf[i] == '\n' || d->inbuf[i] == '\r' )
i++;
for ( j = 0; ( d->inbuf[j] = d->inbuf[i+j] ) != '\0'; j++ )
;
return;
}
23 Mar, 2009, Guest wrote in the 2nd comment:
Votes: 0
I see a zlib_alloc function there but no zlib_free. Your code is indicating both should exist.
s->zalloc = zlib_alloc;
s->zfree = zlib_free;
s->opaque = NULL;


The segment of MCCP code from SmaugFUSS shows this instead:
s->zalloc = Z_NULL;
s->zfree = Z_NULL;
s->opaque = NULL;


To date no memory leaks have ever resulted from having MCCP support. Might be worth trying out the change in your code to see what comes of it.
23 Mar, 2009, Korax wrote in the 3rd comment:
Votes: 0
There is a zlib_free function in mccp.c. I'll take a look at SmaugFUSS' implementation and see if changing it helps but my version should be fine already.

void zlib_free(void *opaque, void *address)
{
/* memory tracking */
mccp_mem_freed += sizeof(*address);

/* free the cell */
free(address);
}


Edit: Seems there is more missing from the valgrind log that I missed which is directly related to this. I'll try to figure it out myself first before posting the part I missed.
23 Mar, 2009, David Haley wrote in the 4th comment:
Votes: 0
You say that a memory leak is causing your MUD to crash, but the valgrind output just shows the leak report, not the crash report. Where/how is the crash happening?
23 Mar, 2009, elanthis wrote in the 5th comment:
Votes: 0
make sure you call deflateEnd when you close the connection. otherwise zlib won't ever actually call the zlib_free function you pass it.
0.0/5