21 Nov, 2009, Mudder wrote in the 1st comment:
Votes: 0
/* function to keep argument safe in all commands – no static strings */
void do_function( CHAR_DATA *ch, DO_FUN *do_fun, const char *argument )
{
char *command_string = NULL;

/*
* copy the string
*/
command_string = str_dup( argument );

/*
* dispatch the command
*/
( *do_fun ) ( ch, command_string );

/*
* free the string
*/
free_string( command_string );
}


I noticed they used free_string on the pointer, but wouldn't it be destroyed once it's out of scope anyway? Or would it just sit there, inaccessible, until the program shut down?
21 Nov, 2009, David Haley wrote in the 2nd comment:
Votes: 0
Mudder said:
Or would it just sit there, inaccessible, until the program shut down?

Yup. The pointer itself is destroyed, but what it points to – namely, the duplicated string on line 9 – is not destroyed unless you free it explicitly (as in line 19).
21 Nov, 2009, Mudder wrote in the 3rd comment:
Votes: 0
So the only reason it needs to be done in this case is because of str_dup. Correct?

/*
* Duplicate a string into dynamic memory.
* Fread_strings are read-only and shared.
*/
char *str_dup( const char *str )
{
char *str_new = NULL;

if ( str[0] == '\0' )
return &str_empty[0];

if ( str >= string_space && str < top_string )
{
/*
* return str;
*/
return ( char * ) ( size_t ) str;
/*
* I can't believe I just did that cast… EVIL!
*/
}

str_new = ( char * ) alloc_mem( strlen( str ) + 1 );
strcpy( str_new, str );
return str_new;
}


The str_dup uses alloc_mem which allocates memory, which is then being freed by the first function. I'm trying to get a better handle on memory.

The alloc_mem function is a little above my head right now.

void *alloc_mem( size_t sMem )
{
void *pMem = NULL;
size_t *magic = NULL;
int iList = 0;

sMem += sizeof( *magic );

for ( iList = 0; iList < MAX_MEM_LIST; iList++ )
{
if ( sMem <= rgSizeList[iList] )
break;
}

if ( iList == MAX_MEM_LIST )
{
proper_exit( MUD_HALT, "Alloc_mem: size %zd too large.", sMem );
}

if ( rgFreeList[iList] == NULL )
{
pMem = alloc_perm( rgSizeList[iList] );
}
else
{
pMem = rgFreeList[iList];
rgFreeList[iList] = *( ( void ** ) rgFreeList[iList] );
}

magic = ( size_t * ) pMem;
*magic = MAGIC_NUM;
pMem = ( void * ) ( ( size_t ) pMem + ( size_t ) ( sizeof( *magic ) ) );

return pMem;
}


It looks to me as though when it starts *magic = NULL, but then the very first part adds *magic so sMem… So it's adding 0?

Then towards the bottom:

magic = ( size_t * ) pMem;
*magic = MAGIC_NUM;
:thinking:
21 Nov, 2009, David Haley wrote in the 4th comment:
Votes: 0
I wouldn't worry too much about the internals of alloc_mem – it's basically a memory allocator, and (as has been discussed in threads recently) it's rather unclear that it is still appropriate to have such a thing for a MUD. It unnecessarily complicates things, as well.

Basically, what you need to remember is that when you allocate memory, you must (eventually) free it, otherwise it sits around inaccessible just wasting space.
21 Nov, 2009, quixadhal wrote in the 5th comment:
Votes: 0
Just be extra careful when poking at strings in many of these codebases. Back in the dark ages, when we had less RAM in our entire Computer Science department than I have on my cell phone, lots of complicated tricks were used to try and minimize the memory footprint of the game. Shared strings is one of those tricks, and you have to be careful to use the supplied API to allocate and free them. If you actually free the memory via the system's resources, bad things may happen later, since you don't have a good way (in C) to know how many other pointers actually point to a particular block of memory.

While I always advocate trying to be efficient, over the years I've chosen simplicity over cleverness for one simple reason. When I was in school (during the golden age of MUDs), our Computer Science department file server hosted every project for every faculty/grad/undergrad on a single 9G SCSI drive. My desktop has 8G of RAM in it. I don't think the complexity buys you very much unless you're really hitting the limits of your available resources. I would be surprised if more than a dozen MUDs in the world actually tax their machine's resources these days.
22 Nov, 2009, Tyche wrote in the 6th comment:
Votes: 0
Mudder said:
It looks to me as though when it starts *magic = NULL, but then the very first part adds *magic so sMem… So it's adding 0?


No. sizeof(*magic) is sizeof(size_t) which is probably 4 or 8.
I don't know why this code was converted from the original int to size_t.

Mudder said:
magic = ( size_t * ) pMem;
*magic = MAGIC_NUM;
:thinking:


Each block of memory is prepended with an integer constant MAGIC_NUM, well size_t in this case, so the allocator knows it allocated it. When the memory is to be freed, the prepended integer is checked to make sure it's MAGIC_NUM or it throws an error.
22 Nov, 2009, Runter wrote in the 7th comment:
Votes: 0
You could replace the memory recycling it uses for straight calloc/frees and be fine, and better for it.
0.0/7