Added memory allocation tracker. Enable with CFLAGS="-DMEMALLOC_TRACK"

This commit is contained in:
Stuart Longland 2008-02-21 16:02:05 +10:00
parent 4bd7d81e80
commit e77ea64738
8 changed files with 358 additions and 135 deletions

View File

@ -3,9 +3,51 @@
#include <sys/types.h>
#include <stdarg.h>
#include <stdlib.h>
/* Various utility functions for the gallery */
/* Memory management functions.
*
* These wrappers around malloc/calloc, realloc and free internally
* monitor the usage of memory chunks. It keeps track of all allocated
* pointers, allowing for garbage collection to occur at the end when
* all pointers should be unused.
*
* For performance, these can be disabled at compile time. Their prime focus is
* for development... to track where allocations are being made. It shouldn't
* be necessary in production -- if it is, there's a memory leakage bug.
*/
#ifdef MEMALLOC_TRACK
/* Memory allocation tracking enabled */
void* gcmalloc( size_t size );
void* gccalloc( size_t nmemb, size_t size );
void* gcrealloc( void* ptr, size_t size );
void gcfree( void* ptr );
void gcfreeall();
char* gcstrdup( const char* str );
char* gcreport();
/* The pointers are tracked in this linked list */
struct mem_chunk {
void* ptr;
size_t size;
struct mem_chunk* prev;
struct mem_chunk* next;
};
static struct mem_chunk* gc_head = NULL;
static struct mem_chunk* gc_tail = NULL;
static size_t gc_count = 0;
#else
/* Memory allocation tracking disabled */
#define gcmalloc( size ) malloc( size )
#define gccalloc( size, num ) calloc( size, num )
#define gcrealloc( ptr, size ) realloc( ptr, size )
#define gcfree( ptr ) free( ptr )
#define gcstrdup( size ) strdup( size )
#endif
/* Sanitise a given name. Names may only contain alpha-numeric
* characters, hyphens, underscores and full stop characters.
*
@ -68,10 +110,10 @@ char* construct_path( const char* format, ...);
#define CONSTRUCT_PATH_FIELD_WIDTH 64
/* Obtain the CGI filesystem directory */
char* get_cgidir();
const char* get_cgidir();
/* Obtain the CGI directory URI */
char* get_cgiuri();
const char* get_cgiuri();
/* Local versions of dirname and basename. These allocate and return copies of
* the strings passed to them.

View File

@ -453,7 +453,7 @@ struct static_double_array* export_double_array( struct vararray* va);
* If free_content is specified, then elements is cast to void**, and each
* pointer in the array elements, is freed as well.
*/
void destroy_array( void* container, size_t length,
void destroy_array( struct static_obj_array* container, size_t length,
void* elements, int free_content );
/* Free an object array. ptr_member should be set to the structure member (e.g.

View File

@ -20,7 +20,7 @@
* insufficient memory.
*
* dest specifies an existing struct to be used. If this is set to NULL, a new
* struct is malloc()'d for use and returned.
* struct is gcmalloc()'d for use and returned.
*/
struct gallery_info* create_gallery_info(
const char* dir,
@ -33,17 +33,17 @@ struct gallery_info* create_gallery_info(
/* If we're not given a destination, allocate it */
if ( dest == NULL )
dest = (struct gallery_info*)
calloc(1, sizeof(struct gallery_info));
gccalloc(1, sizeof(struct gallery_info));
dprintf("create_gallery_info: place at location %p\n", dest );
if ( dest == NULL ) return NULL;
/* If we're still here, then allocation succeeded:
* copy in the strings
*/
dest->gallery_dir = strdup(dir);
dest->gallery_name = strdup(name);
dest->gallery_title= strdup(title);
dest->gallery_desc = strdup(desc);
dest->gallery_dir = gcstrdup(dir);
dest->gallery_name = gcstrdup(name);
dest->gallery_title= gcstrdup(title);
dest->gallery_desc = gcstrdup(desc);
/* Check none of them are null */
if ( (dest->gallery_dir == NULL) ||
@ -52,11 +52,11 @@ struct gallery_info* create_gallery_info(
(dest->gallery_desc == NULL) ) {
dprintf("create_gallery_info: name at %p, title at %p, desc at %p -> bailout!\n",
dest->gallery_name, dest->gallery_title, dest->gallery_desc);
if ( dest->gallery_dir != NULL ) free( dest->gallery_dir );
if ( dest->gallery_name != NULL ) free( dest->gallery_name );
if ( dest->gallery_title != NULL ) free( dest->gallery_title );
if ( dest->gallery_desc != NULL ) free( dest->gallery_desc );
free(dest);
if ( dest->gallery_dir != NULL ) gcfree( dest->gallery_dir );
if ( dest->gallery_name != NULL ) gcfree( dest->gallery_name );
if ( dest->gallery_title != NULL ) gcfree( dest->gallery_title );
if ( dest->gallery_desc != NULL ) gcfree( dest->gallery_desc );
gcfree(dest);
return NULL;
}
dprintf("create_gallery_info: gallery %s created at %p\n", name, dest);
@ -74,17 +74,17 @@ struct gallery_info* copy_gallery_info( struct gallery_info* info,
dest );
}
/* setting fields_only non-zero tells destroy_gallery_info to only free() the
/* setting fields_only non-zero tells destroy_gallery_info to only gcfree() the
* title, name and desc fields of the struct, rather than the struct itself.
* This is required when the struct is not allocated directly using malloc or
* This is required when the struct is not allocated directly using gcmalloc or
* similar commands.
*/
void destroy_gallery_info( struct gallery_info* info, int fields_only ) {
free( info->gallery_name );
free( info->gallery_title );
free( info->gallery_desc );
free( info->gallery_dir );
if ( !fields_only ) free( info );
gcfree( info->gallery_name );
gcfree( info->gallery_title );
gcfree( info->gallery_desc );
gcfree( info->gallery_dir );
if ( !fields_only ) gcfree( info );
}
/* Attempt to read the gallery information for a given directory. If it's not a
@ -104,7 +104,7 @@ struct gallery_info* read_gallery( const char* dir, struct gallery_info* dest )
if ( info_path == NULL ) return NULL;
struct txtinfo_chain* info_data = read_txtinfo_chain( info_path );
free(info_path);
gcfree(info_path);
dprintf( "read_gallery: read info file into structure at %p\n", info_data );
if ( info_data == NULL ) return NULL;
@ -112,16 +112,16 @@ struct gallery_info* read_gallery( const char* dir, struct gallery_info* dest )
char* title = get_txtinfo_chain_val( info_data, ".title" );
char* desc = get_txtinfo_chain_val( info_data, ".desc" );
/* We're done with the info_path chain... free it */
/* We're done with the info_path chain... gcfree it */
destroy_txtinfo_chain( info_data );
/* Okay, we should have all the data read in */
if ( title == NULL ) {
if ( desc != NULL ) free( desc );
if ( desc != NULL ) gcfree( desc );
return NULL;
}
if ( desc == NULL ) {
free( title );
gcfree( title );
return NULL;
}
@ -134,9 +134,10 @@ struct gallery_info* read_gallery( const char* dir, struct gallery_info* dest )
dest = create_gallery_info( dir, name, title, desc, dest );
/* Free our copy of the data and return */
free( name );
free( title );
free( desc );
gcfree( name );
gcfree( title );
gcfree( desc );
dprintf( "read_gallery: gallery read at %p\n\n", dest );
return dest;
}
@ -185,7 +186,7 @@ struct gallery_list* list_galleries() {
dprintf("list_galleries: read from %s\n",my_dir);
DIR* dir = opendir( my_dir );
if ( dir == NULL ) {
free( my_dir );
gcfree( my_dir );
destroy_vararray( va );
return NULL;
}
@ -223,26 +224,35 @@ struct gallery_list* list_galleries() {
read_gallery( de_path, &info );
/* If successful, add it here. */
if ( info_parsed != NULL ) {
dprintf("list_galleries: parsed gallery %s (%s)\n",
info.gallery_title, info.gallery_name);
dprintf("list_galleries: parsed gallery %s (%s) "
"-- adding to linked list at %p\n",
info.gallery_title, info.gallery_name, va);
push_vararray_ptr( va, &info );
destroy_gallery_info( &info, 1 );
}
free( de_path );
}
/* Free the directory name */
gcfree( de_path );
/* Get the next directory entry */
dprintf("list_galleries: moving on from %s (in %s)\n", de->d_name, my_dir);
de = readdir( dir );
if ( de != NULL )
dprintf("list_galleries: next is %s (in %s)\n", de->d_name, my_dir);
}
/* Now we have a variable array... we need a static array,
* so do the conversion
*/
dprintf("list_galleries: converting linked list at %p to static array\n", va);
struct gallery_list* list =
(struct gallery_list*)export_obj_array( va );
/* Once this is done, we can dispense with the
* variable array and return the static one.
*/
dprintf("list_galleries: got static array at %p, deleting linked list at %p\n", list, va);
destroy_vararray( va );
/* Sort the list before returning */
@ -250,5 +260,6 @@ struct gallery_list* list_galleries() {
if ( list->length > 1 )
sort_array( (void**)list->gallery, list->length,
&gallerycmp );
dprintf("list_galleries: sorted galleries at %p. Returning.\n\n", list);
return list;
}

View File

@ -24,7 +24,7 @@ struct gallery_contents* read_gallery_contents( struct gallery_info* gallery,
if ( dest == NULL )
dest = (struct gallery_contents*)
calloc( 1, sizeof( struct gallery_contents ) );
gccalloc( 1, sizeof( struct gallery_contents ) );
else free_struct = 0;
if ( dest == NULL ) return NULL;
@ -34,7 +34,7 @@ struct gallery_contents* read_gallery_contents( struct gallery_info* gallery,
struct vararray* list = create_vararray( NULL, 0, NULL, NULL );
if ( list == NULL ) {
dputs("read_gallery_contents: failed to allocate vararray\n");
if ( free_struct ) free( dest );
if ( free_struct ) gcfree( dest );
return NULL;
}
@ -42,7 +42,7 @@ struct gallery_contents* read_gallery_contents( struct gallery_info* gallery,
DIR* dir = opendir( gallery->gallery_dir );
if ( dir == NULL ) {
dprintf("read_gallery_contents: failed to opendir(\"%s\")\n", gallery->gallery_dir);
if ( free_struct ) free( dest );
if ( free_struct ) gcfree( dest );
return NULL;
}
@ -78,7 +78,7 @@ struct gallery_contents* read_gallery_contents( struct gallery_info* gallery,
/* Check for success... if not, free everything and return NULL */
if ( dest->photos == NULL ) {
dputs("read_gallery_contents: failed to list files\n");
if ( free_struct ) free( dest );
if ( free_struct ) gcfree( dest );
return NULL;
}
@ -94,7 +94,7 @@ struct gallery_contents* read_gallery_contents( struct gallery_info* gallery,
*/
void destroy_gallery_contents( struct gallery_contents* gc, int fields_only ) {
destroy_string_array( gc->photos );
free( gc );
gcfree( gc );
}
/* Duplicate a gallery_contents struct. A pre-allocated struct may be supplied.
@ -119,7 +119,7 @@ struct gallery_contents* copy_gallery_contents( struct gallery_contents* gc,
dest->photos = duplicate_static_obj_array( gc->photos,
struct static_string_array );
if ( dest->photos == NULL ) {
if ( free_struct ) free( dest );
if ( free_struct ) gcfree( dest );
return NULL;
}
return dest;

View File

@ -85,6 +85,7 @@ int main( int argc, char** argv ) {
if ( (path_info == NULL) || ( path_info->length < 1 ) ) {
/* Do the default action ... gallery listing */
destroy_vararray( path_info );
gallery_index();
return 0;
}
@ -108,7 +109,7 @@ int main( int argc, char** argv ) {
*/
if ( gallery_name[0] == '.' ) {
action_handler( &gallery_name[1], path_info );
free( gallery_name );
gcfree( gallery_name );
return 0;
}
@ -116,13 +117,13 @@ int main( int argc, char** argv ) {
char* gallery_path = construct_path( "s/s", dir, gallery_name );
dprintf( "main: gallery_path at %s\n", gallery_path );
struct gallery_info* gallery = read_gallery( gallery_path, NULL );
free( gallery_path );
gcfree( gallery_path );
/* If the pointer is not null, then we can pass onto the
* gallery handler. Otherwise, display an error page. */
if ( gallery != NULL ) {
gallery_handler( gallery, path_info );
free( gallery );
gcfree( gallery );
} else {
hdf_set_value( cgi->hdf, "error", "gallery_not_found" );
hdf_set_value( cgi->hdf, "what", gallery_name );
@ -130,7 +131,7 @@ int main( int argc, char** argv ) {
write_template( "error.cs" );
}
free( gallery_name );
gcfree( gallery_name );
return 0;
}
@ -162,6 +163,9 @@ void gallery_index() {
list->gallery[i]->gallery_desc );
}
/* Clean up list of galleries */
destroy_obj_array( list, gallery );
/* Render the page and display it */
write_template( "index.cs" );
}
@ -333,12 +337,12 @@ void action_rotation_preview( struct vararray* path_info ) {
MagickWriteImageFile( wand, stdout );
/* Clean up */
free( thumbnail_path );
gcfree( thumbnail_path );
destroy_photo_info( photo, 0 );
destroy_gallery_contents( gc, 0 );
destroy_gallery_info( gallery, 0 );
free( gallery_dir );
free( my_dir );
gcfree( gallery_dir );
gcfree( my_dir );
DestroyMagickWand( wand );
}
@ -489,6 +493,14 @@ void write_template( const char* template_name ) {
cgi_neo_error(cgi, err);
nerr_log_error(err);
}
free( template );
gcfree( template );
gcfree( master );
}
#ifdef MEMALLOC_TRACK
/* Memory allocation report */
char* malloc_rpt = gcreport();
fputs( malloc_rpt, stderr );
free( malloc_rpt );
#endif
}

View File

@ -25,7 +25,7 @@ struct photo_info* read_photo_info( struct gallery_contents* gallery,
if ( filename == NULL ) return NULL;
if ( dest == NULL ) {
dest = (struct photo_info*)
calloc( 1, sizeof(struct photo_info) );
gccalloc( 1, sizeof(struct photo_info) );
dprintf( "read_photo_info: allocated struct at %p\n", dest );
if ( dest == NULL ) return NULL;
} else {
@ -38,7 +38,7 @@ struct photo_info* read_photo_info( struct gallery_contents* gallery,
char* filepath = construct_path( "s/s",
gallery->info->gallery_dir, filename );
if ( filepath == NULL ) {
if ( free_struct ) free( dest );
if ( free_struct ) gcfree( dest );
return NULL;
}
dprintf( "read_photo_info: full path at %s\n", filepath );
@ -47,8 +47,8 @@ struct photo_info* read_photo_info( struct gallery_contents* gallery,
struct photo_meta* meta =
read_photo_meta( filepath, &dest->meta );
if ( meta == NULL ) {
free( filepath );
if ( free_struct ) free( dest );
gcfree( filepath );
if ( free_struct ) gcfree( dest );
return NULL;
}
dprintf( "read_photo_info: metadata loaded to %p\n", meta );
@ -93,7 +93,7 @@ struct photo_info* read_photo_info( struct gallery_contents* gallery,
filename );
if ( thumbnail != NULL ) {
dest->thumbnail = substitute_ext( thumbnail, ".jpg" );
free( thumbnail );
gcfree( thumbnail );
}*/
dprintf( "read_photo_info: thumbnail at %s (%p)\n",
dest->thumbnail, dest->thumbnail );
@ -133,7 +133,7 @@ struct photo_info* read_photo_info( struct gallery_contents* gallery,
}
fclose( annotations );
}
free( ann_file );
gcfree( ann_file );
}
/* If we still haven't located the annotation yet... try method (2). */
@ -154,7 +154,7 @@ struct photo_info* read_photo_info( struct gallery_contents* gallery,
/* Read the file in */
struct txtinfo_chain* annotations =
read_txtinfo_chain( ann_file );
free( ann_file );
gcfree( ann_file );
if ( annotations != NULL ) {
dest->annotation =
@ -206,7 +206,7 @@ struct photo_info* copy_photo_info( struct photo_info* src,
if ( src == NULL ) return NULL;
if ( dest == NULL ) {
dest = (struct photo_info*)
malloc( sizeof(struct photo_info) );
gcmalloc( sizeof(struct photo_info) );
if ( dest == NULL ) return NULL;
} else {
free_struct = 0;
@ -234,11 +234,11 @@ struct photo_info* copy_photo_info( struct photo_info* src,
/* Destroy photo information struct. */
void destroy_photo_info( struct photo_info* photo, int fields_only ) {
destroy_photo_meta( &photo->meta, 1 );
if ( photo->previous != NULL ) free( photo->previous );
if ( photo->next != NULL ) free( photo->next );
if ( photo->thumbnail != NULL ) free( photo->thumbnail );
if ( photo->annotation != NULL ) free( photo->annotation );
if ( !fields_only ) free( photo );
if ( photo->previous != NULL ) gcfree( photo->previous );
if ( photo->next != NULL ) gcfree( photo->next );
if ( photo->thumbnail != NULL ) gcfree( photo->thumbnail );
if ( photo->annotation != NULL ) gcfree( photo->annotation );
if ( !fields_only ) gcfree( photo );
}
/* Read photo metadata. This takes a full path to an image or movie, and
@ -255,7 +255,7 @@ struct photo_meta* read_photo_meta( const char* filename,
if ( filename == NULL ) return NULL;
if ( dest == NULL ) {
dest = (struct photo_meta*)
malloc( sizeof(struct photo_meta) );
gcmalloc( sizeof(struct photo_meta) );
dprintf("read_photo_meta: allocated struct at %p\n", dest);
if ( dest == NULL ) return NULL;
} else {
@ -268,13 +268,13 @@ struct photo_meta* read_photo_meta( const char* filename,
/* Gallery name should be the directory containing the photo */
char* dirname = get_dirname( filename );
if ( dirname == NULL ) {
if ( free_struct ) free( dest );
if ( free_struct ) gcfree( dest );
return NULL;
}
char* gallery = get_basename( dirname );
free( dirname );
gcfree( dirname );
if ( gallery == NULL ) {
if ( free_struct ) free( dest );
if ( free_struct ) gcfree( dest );
return NULL;
}
dest->gallery_name = gallery;
@ -309,8 +309,8 @@ struct photo_meta* read_photo_meta( const char* filename,
if (MagickReadImage( wand, filename ) == MagickFalse) {
/* Failure. Free everything and return */
DestroyMagickWand( wand );
free( gallery );
if ( free_struct ) free( dest );
gcfree( gallery );
if ( free_struct ) gcfree( dest );
return NULL;
}
/* Okay, image read in... get the dimensions */
@ -358,9 +358,9 @@ struct photo_meta* copy_photo_meta( struct photo_meta* src,
* zero) the struct itself.
*/
void destroy_photo_meta( struct photo_meta* meta, int fields_only ) {
if ( meta->gallery_name != NULL ) free( meta->gallery_name );
if ( meta->filepath != NULL ) free( meta->filepath );
if ( !fields_only ) free( meta );
if ( meta->gallery_name != NULL ) gcfree( meta->gallery_name );
if ( meta->filepath != NULL ) gcfree( meta->filepath );
if ( !fields_only ) gcfree( meta );
}
/* Helper function... calculate size of resized photo */
@ -435,7 +435,7 @@ char* resize_photo( struct photo_meta* dest,
char* dir = get_cgidir();
char* cache_path = construct_path( "s/s", dir, cache_file );
free( dir );
gcfree( dir );
/* Check if the file already exists... if it does, return now */
struct stat cache_stat;
@ -444,7 +444,7 @@ char* resize_photo( struct photo_meta* dest,
if ( stat( dest->filepath, &orig_stat ) == 0 ) {
if ( orig_stat.st_mtime <= cache_stat.st_mtime ) {
/* Recent cache already exists */
free( cache_path );
gcfree( cache_path );
return cache_file;
}
}
@ -456,7 +456,7 @@ char* resize_photo( struct photo_meta* dest,
ExceptionType severity;
char* description=MagickGetException(wand,&severity);
dprintf("%s %s %ld %s\n",GetMagickModule(),description);
free( cache_file );
gcfree( cache_file );
return NULL;
}
@ -486,12 +486,12 @@ char* resize_photo( struct photo_meta* dest,
ExceptionType severity;
char* description=MagickGetException(wand,&severity);
dprintf("%s %s %ld %s\n",GetMagickModule(),description);
free( cache_file );
gcfree( cache_file );
cache_file = NULL;
}
DestroyMagickWand( wand );
free( cache_path );
gcfree( cache_path );
dprintf( "resize_photo: resized photo at %s (%p)\n", cache_file, cache_file );
return cache_file;
}

View File

@ -6,6 +6,156 @@
#include <errno.h>
#include <dprintf.h>
/* Memory management -- helpers */
#ifdef MEMALLOC_TRACK
struct mem_chunk* gc_find_chunk( void* ptr ) {
dprintf("gc_find_chunk: locating chunk for ptr %p\n", ptr);
struct mem_chunk* chunk = gc_head;
while( chunk != NULL )
if ( chunk->ptr == ptr )
return chunk;
else
chunk = chunk->next;
return NULL;
}
struct mem_chunk* gc_new_chunk( void* ptr, size_t size ) {
dprintf("gc_new_chunk: new chunk: %d at %p\n", size, ptr);
struct mem_chunk* chunk= (struct mem_chunk*)
calloc( sizeof(struct mem_chunk), 1 );
if ( chunk == NULL ) return NULL;
chunk->ptr = ptr;
chunk->size= size;
return chunk;
}
void gc_free_chunk( struct mem_chunk* chunk ) {
dprintf("gc_free_chunk: removing %d at %p\n",
chunk->size, chunk->ptr);
struct mem_chunk* prev = chunk->prev;
struct mem_chunk* next = chunk->next;
if ( prev != NULL ) prev->next = next;
if ( next != NULL ) next->prev = prev;
if ( chunk == gc_head ) gc_head = next;
if ( chunk == gc_tail ) gc_tail = prev;
gc_count--;
free( chunk->ptr );
free( chunk );
}
/* Memory management functions */
void* gcmalloc( size_t size ) {
dprintf("gcmalloc: allocate %d bytes\n", size);
void* outchunk = malloc( size );
if ( outchunk == NULL ) return NULL;
struct mem_chunk* chunk = gc_new_chunk( outchunk, size );
chunk->prev = gc_tail;
if ( gc_tail != NULL )
gc_tail->next = chunk;
if ( gc_head == NULL )
gc_head = chunk;
gc_tail = chunk;
gc_count++;
dprintf("gcmalloc: allocated %d bytes at %p\n", size, outchunk);
return outchunk;
}
void* gccalloc( size_t nmemb, size_t size ) {
void* ptr = gcmalloc( nmemb * size );
if ( ptr != NULL ) memset( ptr, 0x00, nmemb*size );
return ptr;
}
void* gcrealloc( void* ptr, size_t size ) {
struct mem_chunk* chunk = gc_find_chunk( ptr );
if ( chunk == NULL ) return NULL;
dprintf("gcrealloc: resize chunk at %p to %d\n", ptr, size);
ptr = realloc( ptr, size );
if ( ptr != NULL ) {
chunk->ptr = ptr;
chunk->size = size;
}
dprintf("gcrealloc: %p size %d\n", chunk->ptr, chunk->size);
return ptr;
}
void gcfree( void* ptr ) {
dprintf("gcfree: freeing memory at %p\n", ptr);
struct mem_chunk* chunk = gc_find_chunk( ptr );
if ( chunk == NULL ) {
free( ptr );
return;
}
gc_free_chunk( chunk );
}
void gcfreeall() {
while( gc_head != NULL )
gc_free_chunk( gc_head );
}
char* gcreport() {
/* Report is in the following format:
* 0x<SIZE>@0x<LOCATION>\n
*
* Thus need to accomodate:
* 10 chars for size in decimal
* 3 chars for @ symbol and '0x' prefix
* 8 chars for location in hex
* 1 space
* 16 bytes "sample"
* 1 char for newline
* ... for each entry in the report.
*/
dprintf("gcreport: Generating report for %d allocations\n", gc_count);
char report_entry[80];
if ( gc_count == 0 ) return "Nothing to report.";
size_t length = gc_count * sizeof(report_entry);
char* report = (char*)calloc( length, 1 );
if ( report == NULL ) return "Can't allocate memory for report.";
dprintf("gcreport: report to be stored at %p\n", report);
struct mem_chunk* chunk = gc_head;
while ( chunk != NULL ) {
snprintf( report_entry, sizeof(report_entry),
"%10d@0x%08x %40s\n",
chunk->size,
chunk->ptr,
chunk->ptr);
strncat( report, report_entry, length );
chunk = chunk->next;
}
return report;
}
char* gcstrdup( const char* str ) {
size_t len = strlen( str ) + 1;
char* out = (char*)gcmalloc( sizeof(char) * len );
if ( out == NULL ) return NULL;
memcpy( out, str, len );
dprintf("gcstrdup: copied string at %p to %p\n", str, out);
return out;
}
#else
void gcfreeall() {
}
char* gcreport() {
return "Memory allocation tracking disabled -- nothing to report.";
}
#endif
/* Sanitise a given name. Names may only contain alpha-numeric
* characters, hyphens, underscores and full stop characters.
*
@ -37,8 +187,8 @@ char* str_concat( char* dest, const char* src ) {
/* Check we're given a source string... if not, just return dest */
if ( src == NULL ) return dest;
/* If we're given src, but not dest... just strdup src */
if ( dest == NULL ) return strdup( src );
/* If we're given src, but not dest... just gcstrdup src */
if ( dest == NULL ) return gcstrdup( src );
dprintf("str_concat: \"%s\" + \"%s\"\n", dest, src);
@ -50,11 +200,11 @@ char* str_concat( char* dest, const char* src ) {
char* orig_dest = dest;
dprintf("str_concat: realloc memory at %p to %d bytes\n",
dest, length*sizeof(char) );
dest = realloc( dest, length * sizeof(char) );
/*dest = (char*)calloc( length, sizeof(char) );
dest = gcrealloc( dest, length * sizeof(char) );
/*dest = (char*)gccalloc( length, sizeof(char) );
if ( dest != NULL ) {
memcpy( (void*)dest, (void*)orig_dest, length*sizeof(char) );
free( orig_dest );
gcfree( orig_dest );
}*/
dprintf("str_concat: old ptr %p, new %p\n", orig_dest, dest);
@ -178,7 +328,7 @@ char* construct_path( const char *format, ... ) {
}
/* Obtain the CGI filesystem directory */
char* get_cgidir() {
const char* get_cgidir() {
/* We store it here statically for speed */
static char* dir = NULL;
static char* script_filename = NULL;
@ -196,12 +346,13 @@ char* get_cgidir() {
dprintf( "get_cgidir: dirname=%s\n", dir );
}
char *out = strdup( dir );
return out;
/*char *out = gcstrdup( dir );
return out;*/
return dir;
}
/* Obtain the CGI directory URI */
char* get_cgiuri() {
const char* get_cgiuri() {
/* We store it here statically for speed */
static char* dir = NULL;
static char* script_filename = NULL;
@ -221,28 +372,29 @@ char* get_cgiuri() {
dir[ lastchar ] = 0;
}
char *out = strdup( dir );
return out;
/*char *out = gcstrdup( dir );
return out;*/
return dir;
}
/* Local versions of dirname and basename. These allocate and return copies of
* * the strings passed to them.
* */
char* get_basename( const char* path ) {
char* path_cp = strdup( path );
char* path_cp = gcstrdup( path );
if ( path_cp == NULL ) return NULL;
char* out = strdup(basename( path_cp ));
free( path_cp );
char* out = gcstrdup(basename( path_cp ));
gcfree( path_cp );
return out;
}
char* get_dirname( const char* path ) {
char* path_cp = strdup( path );
char* path_cp = gcstrdup( path );
if ( path_cp == NULL ) return NULL;
char* out = strdup(dirname( path_cp ));
free( path_cp );
char* out = gcstrdup(dirname( path_cp ));
gcfree( path_cp );
return out;
}
@ -256,7 +408,7 @@ char* substitute_ext( const char* filename, const char* new_ext ) {
* We'll realloc it down to size later.
*/
size_t length = strlen( filename ) + strlen( new_ext );
char* buffer = (char*)calloc( length, sizeof( char ) );
char* buffer = (char*)gccalloc( length, sizeof( char ) );
if ( buffer == NULL ) return NULL;
/* Copy the original filename in */
@ -289,13 +441,13 @@ char* substitute_ext( const char* filename, const char* new_ext ) {
/* Create a txtinfo_chain object */
struct txtinfo_chain* create_txtinfo_chain( const char* name, const char* val ){
struct txtinfo_chain* chain =
(struct txtinfo_chain*)calloc( 1,
(struct txtinfo_chain*)gccalloc( 1,
sizeof( struct txtinfo_chain ) );
if ( chain == NULL ) return NULL;
/* If given the content strings, copy them in */
if ( name != NULL ) chain->field_name = strdup( name );
if ( val != NULL ) chain->field_val = strdup( val );
if ( name != NULL ) chain->field_name = gcstrdup( name );
if ( val != NULL ) chain->field_val = gcstrdup( val );
return chain;
}
@ -305,9 +457,9 @@ void destroy_txtinfo_chain( struct txtinfo_chain* chain ) {
while( chain != NULL ) {
struct txtinfo_chain* next = chain->next;
if ( chain->field_name != NULL) free( chain->field_name );
if ( chain->field_val != NULL) free( chain->field_val );
free( chain );
if ( chain->field_name != NULL) gcfree( chain->field_name );
if ( chain->field_val != NULL) gcfree( chain->field_val );
gcfree( chain );
chain = next;
}
@ -330,7 +482,7 @@ char* get_txtinfo_chain_val( struct txtinfo_chain* chain, const char* name ) {
dprintf( "get_txtinfo_chain_val: node found at %p\n", c );
if ( c == NULL ) return NULL;
dprintf( "get_txtinfo_chain_val: value: %s", c->field_val );
return strdup(c->field_val);
return gcstrdup(c->field_val);
}
/* Read a file into a txtinfo_chain object. Returns NULL on failure. */
@ -403,7 +555,7 @@ int write_txtinfo_chain( const char* file, struct txtinfo_chain* chain ) {
while( chain != NULL ) {
char* name = chain->field_name;
char* value= strdup( chain->field_val );
char* value= gcstrdup( chain->field_val );
char* strtok_ptr;
/* Split up each line of 'value' */
@ -420,7 +572,7 @@ int write_txtinfo_chain( const char* file, struct txtinfo_chain* chain ) {
}
/* Move onto next element */
free( value );
gcfree( value );
chain = chain->next;
}
@ -429,13 +581,13 @@ int write_txtinfo_chain( const char* file, struct txtinfo_chain* chain ) {
}
/* Duplicate a structure in memory.
* This calls malloc to allocate a region of the specified size,
* This calls gcmalloc to allocate a region of the specified size,
* then does a memcpy from the supplied address.
*
* Returns the copy on success, or NULL on failure.
*/
void* memdup( void* ptr, size_t length ) {
void* out = malloc( length );
void* out = gcmalloc( length );
if ( out != NULL ) memcpy( out, ptr, length );
return out;
}

View File

@ -12,12 +12,12 @@
* for efficient indexing once the content is settled.
*/
/* Special strdup. This is used for string arrays, since the strings can be
* variable length. strdup takes one argument, so we make a wrapper to ignore
/* Special gcstrdup. This is used for string arrays, since the strings can be
* variable length. gcstrdup takes one argument, so we make a wrapper to ignore
* the object size (which should be zero).
*/
void* va_strdup( void* orig, size_t size ) {
return (void*)strdup( (char*)orig );
void* va_gcstrdup( void* orig, size_t size ) {
return (void*)gcstrdup( (char*)orig );
}
/* Create a new vararray
@ -34,7 +34,7 @@ struct vararray* create_vararray( struct vararray* dest, size_t obj_size,
dprintf( "create_vararray: create new variable array, dest %#lx\n", dest );
if ( dest == NULL ) {
dputs( "create_vararray: allocating structure\n" );
dest = (struct vararray*)calloc( 1, sizeof(struct vararray) );
dest = (struct vararray*)gccalloc( 1, sizeof(struct vararray) );
if ( dest == NULL ) return NULL;
}
@ -50,7 +50,7 @@ struct vararray* create_vararray( struct vararray* dest, size_t obj_size,
* and util.c
*/
else
dest->copy_func = &va_strdup;
dest->copy_func = &va_gcstrdup;
else
dest->copy_func = copy_func;
if ( destroy_func == NULL )
@ -75,14 +75,14 @@ void destroy_vararray( struct vararray* dest ) {
node = dest->head;
/* Free the master container */
free( dest );
gcfree( dest );
dprintf("destroy_vararray: container at %p gone\n", dest);
/* Now step through and free each node */
while( node != NULL ) {
struct vararray_node* next = node->next;
if ( node->using_ptr ) (*dest->destroy_func)( node->data.as_ptr );
free( node );
gcfree( node );
dprintf("destroy_vararray: node at %p gone, move on to %p\n", node, next);
node = next;
}
@ -207,7 +207,7 @@ inline char* get_vararray_string( struct vararray* array,
size_t index, int end ) {
struct vararray_node* node = fetch_vararray_node( array, index, end );
if ( node == NULL ) return NULL;
return strdup( node->data.as_string );
return gcstrdup( node->data.as_string );
}
#define VARRAY_FETCHVAL( type, name, member ) \
@ -266,7 +266,7 @@ static inline struct vararray_node* insert_node(
/* Create the node */
struct vararray_node* node = (struct vararray_node*)
calloc(1, sizeof(struct vararray_node));
gccalloc(1, sizeof(struct vararray_node));
dprintf( "insert_node: new node at %#lx\n", node );
if ( node == NULL ) return NULL;
node->prev = prev;
@ -312,7 +312,7 @@ inline int insert_vararray_string( struct vararray* array,
dprintf( "insert_va_string: array at %#lx, object at %#lx, "
"insert %d places from %s\n", array, str, index,
end ? "end" : "start" );
char* strcp = strdup( str );
char* strcp = gcstrdup( str );
dprintf( "insert_va_string: copy of object at %#lx\n", strcp );
if ( strcp == NULL ) return 0;
@ -374,13 +374,13 @@ inline int update_vararray_ptr( struct vararray* array,
inline int update_vararray_string( struct vararray* array,
char* str,
size_t index, int end ) {
void* strcp = strdup( str );
void* strcp = gcstrdup( str );
if ( strcp == NULL ) return 0;
struct vararray_node* node = fetch_vararray_node( array, index, end );
if ( node == NULL ) return 0;
free( node->data.as_string );
gcfree( node->data.as_string );
node->data.as_string = strcp;
node->using_ptr = 1;
return 1;
@ -426,7 +426,7 @@ inline int delete_vararray_node( struct vararray* array,
/* Free it */
if ( node->using_ptr ) (*array->destroy_func)( node->data.as_ptr );
free( node );
gcfree( node );
array->length--;
return 1;
}
@ -450,7 +450,7 @@ inline int delete_vararray_node( struct vararray* array,
array->tail = oldtail->prev; \
if ( array->tail != NULL ) array->tail->next = NULL; \
dprintf( "pop: array new tail at %#lx\n", array->tail ); \
free( oldtail ); \
gcfree( oldtail ); \
array->length--; \
dprintf( "pop: old tail freed, new length %d\n", array->length ); \
return out; \
@ -462,7 +462,7 @@ inline int delete_vararray_node( struct vararray* array,
type out = oldhead->data.member; \
array->head = oldhead->next; \
if ( array->head != NULL ) array->head->prev = NULL; \
free( oldhead ); \
gcfree( oldhead ); \
array->length--; \
return out; \
}
@ -585,15 +585,15 @@ struct static_obj_array* export_obj_array( struct vararray* va ) {
if ( va == NULL ) return NULL;
struct static_obj_array* sa = (struct static_obj_array*)
calloc(1, sizeof(struct static_obj_array));
gccalloc(1, sizeof(struct static_obj_array));
if ( sa == NULL ) return NULL;
dprintf("export_obj_array: static array container at %p\n", sa);
if ( va->length < 1 ) return sa;
sa->object = (void**)calloc( va->length, sizeof(void*) );
sa->object = (void**)gccalloc( va->length, sizeof(void*) );
if ( sa->object == NULL ) {
free( sa );
gcfree( sa );
return NULL;
}
dprintf("export_obj_array: static array at %p\n", sa->object);
@ -619,14 +619,14 @@ struct static_string_array* export_string_array( struct vararray* va ) {
if ( va == NULL ) return NULL;
struct static_string_array* sa = (struct static_string_array*)
calloc(1, sizeof(struct static_string_array));
gccalloc(1, sizeof(struct static_string_array));
if ( sa == NULL ) return NULL;
if ( va->length < 1 ) return sa;
sa->string = (char**)calloc( va->length, sizeof(char*) );
sa->string = (char**)gccalloc( va->length, sizeof(char*) );
if ( sa->string == NULL ) {
free( sa );
gcfree( sa );
return NULL;
}
sa->length = va->length;
@ -637,7 +637,7 @@ struct static_string_array* export_string_array( struct vararray* va ) {
struct vararray_node* node = va->head;
size_t index = 0;
while( node != NULL ) {
sa->string[index] = strdup( node->data.as_string );
sa->string[index] = gcstrdup( node->data.as_string );
index++;
node = node->next;
}
@ -648,12 +648,12 @@ struct static_string_array* export_string_array( struct vararray* va ) {
struct type* name( struct vararray* va ) { \
if ( va == NULL ) return NULL; \
struct type* sa = (struct type*) \
calloc(1, sizeof(struct type)); \
gccalloc(1, sizeof(struct type)); \
if ( sa == NULL ) return NULL; \
if ( va->length < 1 ) return sa; \
sa->value = (outtype*)calloc( va->length, sizeof(outtype) ); \
sa->value = (outtype*)gccalloc( va->length, sizeof(outtype) ); \
if ( sa->value == NULL ) { \
free( sa ); \
gcfree( sa ); \
return NULL; \
} \
sa->length = va->length; \
@ -691,18 +691,24 @@ EXPORT_TYPE_ARRAY( static_double_array, export_double_array, double, as_double )
* If free_content is specified, then elements is cast to void**, and each
* pointer in the array elements, is freed as well.
*/
void destroy_array( void* container, size_t length,
void destroy_array( struct static_obj_array* container, size_t length,
void* elements, int free_content ) {
if ( container != NULL ) free( container );
void (*destroy_func)(void* orig);
if ( container != NULL ) {
destroy_func = container->destroy_func;
gcfree( container );
} else {
destroy_func = &gcfree;
}
if ( elements != NULL ) {
if ( free_content ) {
void** array = (void**)elements;
size_t index;
for( index = 0; index < length; index++ )
if ( array[index] != NULL )
free( array[index] );
destroy_func( array[index] );
}
free( elements );
gcfree( elements );
}
}
@ -723,7 +729,7 @@ struct static_simple_array* duplicate_simple_array_impl(
/* Now, duplicate the data */
copy->value = memdup( src->value, data_size*src->length );
if ( copy->value == NULL ) {
free( copy );
gcfree( copy );
return NULL;
}
@ -741,9 +747,9 @@ struct static_obj_array* duplicate_obj_array_impl(
if ( copy == NULL ) return NULL;
/* Allocate the array itself */
copy->object = (void**)calloc( src->length, sizeof(void*) );
copy->object = (void**)gccalloc( src->length, sizeof(void*) );
if ( copy->object == NULL ) {
free( copy );
gcfree( copy );
return NULL;
}