Added memory allocation tracker. Enable with CFLAGS="-DMEMALLOC_TRACK"
This commit is contained in:
parent
4bd7d81e80
commit
e77ea64738
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
28
src/main.c
28
src/main.c
@ -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
|
||||
}
|
||||
|
54
src/photo.c
54
src/photo.c
@ -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;
|
||||
}
|
||||
|
210
src/util.c
210
src/util.c
@ -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;
|
||||
}
|
||||
|
72
src/varray.c
72
src/varray.c
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user