diff --git a/ChangeLog b/ChangeLog index 1ba3ac983..91e3617eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2006-05-02 David Turner + + * include/freetype/fterrdef.h, include/freetype/config/ftconfig.h, + include/freetype/internal/ftmemory.h, src/base/ftdbgmem.c, + src/base/ftutil.c: udpating the memory management functions and + macros to safely deal with array size buffer overflows, this + corresponds to attemps to allocate arrays that are too large. For + an example, consider the following code: + + count = read_uint32_from_file(); + array = malloc( sizeof(Item) * count ); + for ( nn = 0; nn < count; nn++ ) + array[nn] = read_item_from_file(); + + if 'count' is larger than FT_UINT_MAX/sizeof(Item), the multiplication + will overflow and the array allocated will be smaller than the data + read from the file. In this case, the heap will be trashed, and this + can be used as a denial-of-service, or make the engine crash later. + + the FT_ARRAY_NEW and FT_ARRAY_RENEW macro now check that the new + count is no more than FT_INT_MAX/item_size, otherwise, a new error, + named 'FT_Err_Array_Too_Large' will be returned. + + note that the memory debugger now works again when FT_DEBUG_MEMORY + is defined, and FT_STRICT_ALIASING has disappeared, the corresponding + code being now the default. + 2006-04-30 suzuki toshiya Fix bug in Mac_Read_POST_Resource() to parse PFB font with MacOS diff --git a/include/freetype/config/ftconfig.h b/include/freetype/config/ftconfig.h index fe9ccfb50..f07fad895 100644 --- a/include/freetype/config/ftconfig.h +++ b/include/freetype/config/ftconfig.h @@ -267,7 +267,7 @@ FT_BEGIN_HEADER #ifdef __cplusplus #define FT_BASE_DEF( x ) extern "C" x #else -#define FT_BASE_DEF( x ) extern x +#define FT_BASE_DEF( x ) x #endif #endif /* !FT_BASE_DEF */ diff --git a/include/freetype/fterrdef.h b/include/freetype/fterrdef.h index 42115d284..ab8c3f7d9 100644 --- a/include/freetype/fterrdef.h +++ b/include/freetype/fterrdef.h @@ -52,6 +52,8 @@ "broken table" ) FT_ERRORDEF_( Invalid_Offset, 0x09, \ "broken offset within table" ) + FT_ERRORDEF_( Array_Too_Large, 0x0A, \ + "array allocation size too large" ) /* glyph/character errors */ diff --git a/include/freetype/internal/ftmemory.h b/include/freetype/internal/ftmemory.h index 024f87faf..1fc4f9977 100644 --- a/include/freetype/internal/ftmemory.h +++ b/include/freetype/internal/ftmemory.h @@ -57,8 +57,18 @@ FT_BEGIN_HEADER /*************************************************************************/ -#ifdef FT_STRICT_ALIASING +#ifdef FT_DEBUG_MEMORY +FT_BASE( const char* ) _ft_debug_file; +FT_BASE( long ) _ft_debug_lineno; + +# define FT_DEBUG_INNER(exp) ( _ft_debug_file = __FILE__, _ft_debug_lineno = __LINE__, (exp) ) + +#else /* !FT_DEBUG_MEMORY */ + +# define FT_DEBUG_INNER(exp) (exp) + +#endif /* * The allocation functions return a pointer, and the error code @@ -78,15 +88,17 @@ FT_BEGIN_HEADER FT_BASE( FT_Pointer ) ft_mem_realloc( FT_Memory memory, - FT_Long current, - FT_Long size, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, void* block, FT_Error *p_error ); FT_BASE( FT_Pointer ) ft_mem_qrealloc( FT_Memory memory, - FT_Long current, - FT_Long size, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, void* block, FT_Error *p_error ); @@ -95,367 +107,39 @@ FT_BEGIN_HEADER const void* P ); -#ifdef FT_DEBUG_MEMORY +#define FT_MEM_ALLOC(ptr,size) \ + FT_DEBUG_INNER( (ptr) = ft_mem_alloc( memory, (size), &error ) ) +#define FT_MEM_FREE(ptr) \ + FT_BEGIN_STMNT \ + ft_mem_free( memory, (ptr) ); \ + (ptr) = NULL; \ + FT_END_STMNT - FT_BASE( FT_Pointer ) - ft_mem_alloc_debug( FT_Memory memory, - FT_Long size, - FT_Error *p_error, - const char* file_name, - FT_Long line_no ); +#define FT_MEM_NEW(ptr) \ + FT_MEM_ALLOC( ptr, sizeof(*(ptr)) ) - FT_BASE( FT_Pointer ) - ft_mem_qalloc_debug( FT_Memory memory, - FT_Long size, - FT_Error *p_error, - const char* file_name, - FT_Long line_no ); +#define FT_MEM_REALLOC( ptr, cur, new ) \ + FT_DEBUG_INNER( (ptr) = ft_mem_realloc( memory, 1, (cur), (new), (ptr), &error ) ) - FT_BASE( FT_Pointer ) - ft_mem_realloc_debug( FT_Memory memory, - FT_Long current, - FT_Long size, - void* P, - FT_Error *p_error, - const char* file_name, - FT_Long line_no ); +#define FT_MEM_QALLOC(ptr,size) \ + FT_DEBUG_INNER( (ptr) = ft_mem_qalloc( memory, (size), &error ) ) - FT_BASE( FT_Pointer ) - ft_mem_qrealloc_debug( FT_Memory memory, - FT_Long current, - FT_Long size, - void* P, - FT_Error *p_error, - const char* file_name, - FT_Long line_no ); +#define FT_MEM_QNEW(ptr) \ + FT_MEM_QALLOC( ptr, sizeof(*(ptr)) ) - FT_BASE( void ) - ft_mem_free_debug( FT_Memory memory, - const void *P, - const char* file_name, - FT_Long line_no ); - - -#define FT_MEM_ALLOC( _pointer_, _size_ ) \ - (_pointer_) = ft_mem_alloc_debug( memory, _size_, &error, \ - __FILE__, __LINE__ ) - -#define FT_MEM_REALLOC( _pointer_, _current_, _size_ ) \ - (_pointer_) = ft_mem_realloc_debug( memory, _current_, _size_, \ - (_pointer_), &error, \ - __FILE__, __LINE__ ) - -#define FT_MEM_QALLOC( _pointer_, _size_ ) \ - (_pointer_) = ft_mem_qalloc_debug( memory, _size_, &error, \ - __FILE__, __LINE__ ) - -#define FT_MEM_QREALLOC( _pointer_, _current_, _size_ ) \ - (_pointer_) = ft_mem_qrealloc_debug( memory, _current_, _size_, \ - (_pointer_), &error, \ - __FILE__, __LINE__ ) - -#define FT_MEM_FREE( _pointer_ ) \ - FT_BEGIN_STMNT \ - if ( _pointer_ ) \ - { \ - ft_mem_free_debug( memory, (_pointer_), __FILE__, __LINE__ ); \ - (_pointer_) = NULL; \ - } \ - FT_END_STMNT - - -#else /* !FT_DEBUG_MEMORY */ - - -#define FT_MEM_ALLOC( _pointer_, _size_ ) \ - (_pointer_) = ft_mem_alloc( memory, _size_, &error ) - -#define FT_MEM_FREE( _pointer_ ) \ - FT_BEGIN_STMNT \ - if ( (_pointer_) ) \ - { \ - ft_mem_free( memory, (_pointer_) ); \ - (_pointer_) = NULL; \ - } \ - FT_END_STMNT - -#define FT_MEM_REALLOC( _pointer_, _current_, _size_ ) \ - (_pointer_) = ft_mem_realloc( memory, _current_, _size_, \ - (_pointer_), &error ) - -#define FT_MEM_QALLOC( _pointer_, _size_ ) \ - (_pointer_) = ft_mem_qalloc( memory, _size_, &error ) - -#define FT_MEM_QREALLOC( _pointer_, _current_, _size_ ) \ - (_pointer_) = ft_mem_qrealloc( memory, _current_, _size_, \ - (_pointer_), &error ) - -#endif /* !FT_DEBUG_MEMORY */ +#define FT_MEM_QREALLOC( ptr, cur, new ) \ + FT_DEBUG_INNER( (ptr) = ft_mem_qrealloc( memory, 1, (cur), (new), (ptr), &error ) ) +#define FT_MEM_QRENEW_ARRAY(ptr,cur,new) \ + FT_DEBUG_INNER( (ptr) = ft_mem_qrealloc( memory, sizeof(*(ptr)), (cur), (new), (ptr), &error ) ) #define FT_MEM_SET_ERROR( cond ) ( (cond), error != 0 ) -#else /* !FT_STRICT_ALIASING */ +#define FT_ALLOC(ptr,size) FT_MEM_SET_ERROR( FT_MEM_ALLOC(ptr,size) ) -#ifdef FT_DEBUG_MEMORY - - - FT_BASE( FT_Error ) - ft_mem_alloc_debug( FT_Memory memory, - FT_Long size, - void* *P, - const char* file_name, - FT_Long line_no ); - - FT_BASE( FT_Error ) - ft_mem_qalloc_debug( FT_Memory memory, - FT_Long size, - void* *P, - const char* file_name, - FT_Long line_no ); - - FT_BASE( FT_Error ) - ft_mem_realloc_debug( FT_Memory memory, - FT_Long current, - FT_Long size, - void* *P, - const char* file_name, - FT_Long line_no ); - - FT_BASE( FT_Error ) - ft_mem_qrealloc_debug( FT_Memory memory, - FT_Long current, - FT_Long size, - void* *P, - const char* file_name, - FT_Long line_no ); - - FT_BASE( void ) - ft_mem_free_debug( FT_Memory memory, - FT_Pointer block, - const char* file_name, - FT_Long line_no ); - - -#endif /* FT_DEBUG_MEMORY */ - - - /*************************************************************************/ - /* */ - /* */ - /* ft_mem_alloc */ - /* */ - /* */ - /* Allocates a new block of memory. The returned area is always */ - /* zero-filled; this is a strong convention in many FreeType parts. */ - /* */ - /* */ - /* memory :: A handle to a given `memory object' which handles */ - /* allocation. */ - /* */ - /* size :: The size in bytes of the block to allocate. */ - /* */ - /* */ - /* P :: A pointer to the fresh new block. It should be set to */ - /* NULL if `size' is 0, or in case of error. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - FT_BASE( FT_Error ) - ft_mem_alloc( FT_Memory memory, - FT_Long size, - void* *P ); - - - /*************************************************************************/ - /* */ - /* */ - /* ft_mem_qalloc */ - /* */ - /* */ - /* Allocates a new block of memory. The returned area is *not* */ - /* zero-filled, making allocation quicker. */ - /* */ - /* */ - /* memory :: A handle to a given `memory object' which handles */ - /* allocation. */ - /* */ - /* size :: The size in bytes of the block to allocate. */ - /* */ - /* */ - /* P :: A pointer to the fresh new block. It should be set to */ - /* NULL if `size' is 0, or in case of error. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - FT_BASE( FT_Error ) - ft_mem_qalloc( FT_Memory memory, - FT_Long size, - void* *p ); - - - /*************************************************************************/ - /* */ - /* */ - /* ft_mem_realloc */ - /* */ - /* */ - /* Reallocates a block of memory pointed to by `*P' to `Size' bytes */ - /* from the heap, possibly changing `*P'. The returned area is */ - /* zero-filled. */ - /* */ - /* */ - /* memory :: A handle to a given `memory object' which handles */ - /* reallocation. */ - /* */ - /* current :: The current block size in bytes. */ - /* */ - /* size :: The new block size in bytes. */ - /* */ - /* */ - /* P :: A pointer to the fresh new block. It should be set to */ - /* NULL if `size' is 0, or in case of error. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - /* */ - /* All callers of ft_mem_realloc() _must_ provide the current block */ - /* size as well as the new one. */ - /* */ - FT_BASE( FT_Error ) - ft_mem_realloc( FT_Memory memory, - FT_Long current, - FT_Long size, - void* *P ); - - - /*************************************************************************/ - /* */ - /* */ - /* ft_mem_qrealloc */ - /* */ - /* */ - /* Reallocates a block of memory pointed to by `*P' to `Size' bytes */ - /* from the heap, possibly changing `*P'. The returned area is *not* */ - /* zero-filled, making reallocation quicker. */ - /* */ - /* */ - /* memory :: A handle to a given `memory object' which handles */ - /* reallocation. */ - /* */ - /* current :: The current block size in bytes. */ - /* */ - /* size :: The new block size in bytes. */ - /* */ - /* */ - /* P :: A pointer to the fresh new block. It should be set to */ - /* NULL if `size' is 0, or in case of error. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - /* */ - /* All callers of ft_mem_realloc() _must_ provide the current block */ - /* size as well as the new one. */ - /* */ - FT_BASE( FT_Error ) - ft_mem_qrealloc( FT_Memory memory, - FT_Long current, - FT_Long size, - void* *p ); - - - /*************************************************************************/ - /* */ - /* */ - /* ft_mem_free */ - /* */ - /* */ - /* Releases a given block of memory allocated through ft_mem_alloc(). */ - /* */ - /* */ - /* memory :: A handle to a given `memory object' which handles */ - /* memory deallocation */ - /* */ - /* P :: This is the _address_ of a _pointer_ which points to the */ - /* allocated block. It is always set to NULL on exit. */ - /* */ - /* */ - /* If P or *P is NULL, this function should return successfully. */ - /* This is a strong convention within all of FreeType and its */ - /* drivers. */ - /* */ - FT_BASE( void ) - ft_mem_free( FT_Memory memory, - void* *P ); - - -#ifdef FT_DEBUG_MEMORY - - -#define FT_MEM_ALLOC( _pointer_, _size_ ) \ - ft_mem_alloc_debug( memory, _size_, \ - (void**)(void*)&(_pointer_), \ - __FILE__, __LINE__ ) - -#define FT_MEM_REALLOC( _pointer_, _current_, _size_ ) \ - ft_mem_realloc_debug( memory, _current_, _size_, \ - (void**)(void*)&(_pointer_), \ - __FILE__, __LINE__ ) - -#define FT_MEM_QALLOC( _pointer_, _size_ ) \ - ft_mem_qalloc_debug( memory, _size_, \ - (void**)(void*)&(_pointer_), \ - __FILE__, __LINE__ ) - -#define FT_MEM_QREALLOC( _pointer_, _current_, _size_ ) \ - ft_mem_qrealloc_debug( memory, _current_, _size_, \ - (void**)(void*)&(_pointer_), \ - __FILE__, __LINE__ ) - -#define FT_MEM_FREE( _pointer_ ) \ - ft_mem_free_debug( memory, (void**)(void*)&(_pointer_), \ - __FILE__, __LINE__ ) - - -#else /* !FT_DEBUG_MEMORY */ - - -#define FT_MEM_ALLOC( _pointer_, _size_ ) \ - ft_mem_alloc( memory, _size_, \ - (void**)(void*)&(_pointer_) ) - -#define FT_MEM_FREE( _pointer_ ) \ - ft_mem_free( memory, \ - (void**)(void*)&(_pointer_) ) - -#define FT_MEM_REALLOC( _pointer_, _current_, _size_ ) \ - ft_mem_realloc( memory, _current_, _size_, \ - (void**)(void*)&(_pointer_) ) - -#define FT_MEM_QALLOC( _pointer_, _size_ ) \ - ft_mem_qalloc( memory, _size_, \ - (void**)(void*)&(_pointer_) ) - -#define FT_MEM_QREALLOC( _pointer_, _current_, _size_ ) \ - ft_mem_qrealloc( memory, _current_, _size_, \ - (void**)(void*)&(_pointer_) ) - - -#endif /* !FT_DEBUG_MEMORY */ - - -#define FT_MEM_SET_ERROR( cond ) ( ( error = (cond) ) != 0 ) - - -#endif /* !FT_STRICT_ALIASING */ - #define FT_MEM_SET( dest, byte, count ) ft_memset( dest, byte, count ) @@ -468,6 +152,7 @@ FT_BEGIN_HEADER #define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) ) + #define FT_ARRAY_ZERO( dest, count ) \ FT_MEM_ZERO( dest, (count) * sizeof ( *(dest) ) ) @@ -494,92 +179,52 @@ FT_BEGIN_HEADER /* _typed_ in order to automatically compute array element sizes. */ /* */ -#define FT_MEM_NEW( _pointer_ ) \ - FT_MEM_ALLOC( _pointer_, sizeof ( *(_pointer_) ) ) +#define FT_MEM_NEW_ARRAY(ptr,count) \ + FT_DEBUG_INNER( (ptr) = ft_mem_realloc( memory, sizeof(*(ptr)), 0, (count), NULL, &error ) ) -#define FT_MEM_NEW_ARRAY( _pointer_, _count_ ) \ - FT_MEM_ALLOC( _pointer_, (_count_) * sizeof ( *(_pointer_) ) ) +#define FT_MEM_RENEW_ARRAY(ptr,cur,new) \ + FT_DEBUG_INNER( (ptr) = ft_mem_realloc( memory, sizeof(*(ptr)), (cur), (new), (ptr), &error ) ) -#define FT_MEM_RENEW_ARRAY( _pointer_, _old_, _new_ ) \ - FT_MEM_REALLOC( _pointer_, (_old_) * sizeof ( *(_pointer_) ), \ - (_new_) * sizeof ( *(_pointer_) ) ) +#define FT_MEM_QNEW_ARRAY(ptr,count) \ + FT_DEBUG_INNER( (ptr) = ft_mem_qrealloc( memory, sizeof(*(ptr)), 0, (count), NULL, &error ) ) -#define FT_MEM_QNEW( _pointer_ ) \ - FT_MEM_QALLOC( _pointer_, sizeof ( *(_pointer_) ) ) - -#define FT_MEM_QNEW_ARRAY( _pointer_, _count_ ) \ - FT_MEM_QALLOC( _pointer_, (_count_) * sizeof ( *(_pointer_) ) ) - -#define FT_MEM_QRENEW_ARRAY( _pointer_, _old_, _new_ ) \ - FT_MEM_QREALLOC( _pointer_, (_old_) * sizeof ( *(_pointer_) ), \ - (_new_) * sizeof ( *(_pointer_) ) ) +#define FT_MEM_QRENEW_ARRAY(ptr,cur,new) \ + FT_DEBUG_INNER( (ptr) = ft_mem_qrealloc( memory, sizeof(*(ptr)), (cur), (new), (ptr), &error ) ) - /*************************************************************************/ - /* */ - /* the following macros are obsolete but kept for compatibility reasons */ - /* */ +#define FT_ALLOC(ptr,size) \ + FT_MEM_SET_ERROR( FT_MEM_ALLOC(ptr,size) ) -#define FT_MEM_ALLOC_ARRAY( _pointer_, _count_, _type_ ) \ - FT_MEM_ALLOC( _pointer_, (_count_) * sizeof ( _type_ ) ) +#define FT_REALLOC(ptr,cursz,newsz) \ + FT_MEM_SET_ERROR( FT_MEM_REALLOC(ptr,cursz,newsz) ) -#define FT_MEM_REALLOC_ARRAY( _pointer_, _old_, _new_, _type_ ) \ - FT_MEM_REALLOC( _pointer_, (_old_) * sizeof ( _type ), \ - (_new_) * sizeof ( _type_ ) ) +#define FT_QALLOC(ptr,size) \ + FT_MEM_SET_ERROR( FT_MEM_QALLOC(ptr,size) ) +#define FT_QREALLOC(ptr,cursz,newsz) \ + FT_MEM_SET_ERROR( FT_MEM_QREALLOC(ptr,cursz,newsz) ) - /*************************************************************************/ - /* */ - /* The following macros are variants of their FT_MEM_XXXX equivalents; */ - /* they are used to set an _implicit_ `error' variable and return TRUE */ - /* if an error occured (i.e., if `error != 0'). */ - /* */ +#define FT_FREE(ptr) FT_MEM_FREE( ptr ) -#define FT_ALLOC( _pointer_, _size_ ) \ - FT_MEM_SET_ERROR( FT_MEM_ALLOC( _pointer_, _size_ ) ) +#define FT_NEW(ptr) \ + FT_MEM_SET_ERROR( FT_MEM_NEW(ptr) ) -#define FT_REALLOC( _pointer_, _current_, _size_ ) \ - FT_MEM_SET_ERROR( FT_MEM_REALLOC( _pointer_, _current_, _size_ ) ) +#define FT_NEW_ARRAY(ptr,count) \ + FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY(ptr,count) ) -#define FT_QALLOC( _pointer_, _size_ ) \ - FT_MEM_SET_ERROR( FT_MEM_QALLOC( _pointer_, _size_ ) ) +#define FT_RENEW_ARRAY(ptr,curcnt,newcnt) \ + FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY(ptr,curcnt,newcnt) ) -#define FT_QREALLOC( _pointer_, _current_, _size_ ) \ - FT_MEM_SET_ERROR( FT_MEM_QREALLOC( _pointer_, _current_, _size_ ) ) +#define FT_QNEW(ptr) \ + FT_MEM_SET_ERROR( FT_MEM_QNEW(ptr) ) +#define FT_QNEW_ARRAY(ptr,count) \ + FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY(ptr,count) ) -#define FT_FREE( _pointer_ ) \ - FT_MEM_FREE( _pointer_ ) +#define FT_QRENEW_ARRAY(ptr,curcnt,newcnt) \ + FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY(ptr,curcnt,newcnt) ) -#define FT_NEW( _pointer_ ) \ - FT_ALLOC( _pointer_, sizeof ( *(_pointer_) ) ) - -#define FT_NEW_ARRAY( _pointer_, _count_ ) \ - FT_ALLOC( _pointer_, sizeof ( *(_pointer_) ) * (_count_) ) - -#define FT_RENEW_ARRAY( _pointer_, _old_, _new_ ) \ - FT_REALLOC( _pointer_, sizeof ( *(_pointer_) ) * (_old_), \ - sizeof ( *(_pointer_) ) * (_new_) ) - -#define FT_QNEW( _pointer_ ) \ - FT_QALLOC( _pointer_, sizeof ( *(_pointer_) ) ) - -#define FT_QNEW_ARRAY( _pointer_, _count_ ) \ - FT_QALLOC( _pointer_, sizeof ( *(_pointer_) ) * (_count_) ) - -#define FT_QRENEW_ARRAY( _pointer_, _old_, _new_ ) \ - FT_QREALLOC( _pointer_, sizeof ( *(_pointer_) ) * (_old_), \ - sizeof ( *(_pointer_) ) * (_new_) ) - - -#define FT_ALLOC_ARRAY( _pointer_, _count_, _type_ ) \ - FT_ALLOC( _pointer_, (_count_) * sizeof ( _type_ ) ) - -#define FT_REALLOC_ARRAY( _pointer_, _old_, _new_, _type_ ) \ - FT_REALLOC( _pointer_, (_old_) * sizeof ( _type_ ), \ - (_new_) * sizeof ( _type_ ) ) - #ifdef FT_CONFIG_OPTION_OLD_INTERNALS diff --git a/src/base/ftdbgmem.c b/src/base/ftdbgmem.c index 632d5df0d..94996d7d1 100644 --- a/src/base/ftdbgmem.c +++ b/src/base/ftdbgmem.c @@ -36,6 +36,8 @@ #include #include + FT_BASE_DEF( const char* ) _ft_debug_file = 0; + FT_BASE_DEF( long ) _ft_debug_lineno = 0; extern void FT_DumpMemory( FT_Memory memory ); @@ -48,7 +50,10 @@ #define FT_MEM_VAL( addr ) ((FT_ULong)(FT_Pointer)( addr )) - + /* this structure holds statistics for a single allocation/release + * site. This is useful to know where memory operations happen the + * most. + */ typedef struct FT_MemSourceRec_ { const char* file_name; @@ -76,7 +81,12 @@ */ #define FT_MEM_SOURCE_BUCKETS 128 - + /* this structure holds information related to a single allocated + * memory block. if KEEPALIVE is defined, blocks that are freed by + * FreeType are never released to the system. Instead, their 'size' + * field is set to -size. This is mainly useful to detect double frees, + * at the price of large memory footprint during execution !! + */ typedef struct FT_MemNodeRec_ { FT_Byte* address; @@ -94,6 +104,9 @@ } FT_MemNodeRec; + /* the global structure, containing compound statistics and all hash + * tables + */ typedef struct FT_MemTableRec_ { FT_ULong size; @@ -113,9 +126,6 @@ FT_MemSource sources[FT_MEM_SOURCE_BUCKETS]; - const char* file_name; - FT_Long line_no; - FT_Bool keep_alive; FT_Memory memory; @@ -447,8 +457,8 @@ FT_MemSource node, *pnode; - hash = (FT_UInt32)(void*)table->file_name + - (FT_UInt32)( 5 * table->line_no ); + hash = (FT_UInt32)(void*)_ft_debug_file + + (FT_UInt32)( 5 * _ft_debug_lineno ); pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS]; for ( ;; ) @@ -457,8 +467,8 @@ if ( node == NULL ) break; - if ( node->file_name == table->file_name && - node->line_no == table->line_no ) + if ( node->file_name == _ft_debug_file && + node->line_no == _ft_debug_lineno ) goto Exit; pnode = &node->link; @@ -469,8 +479,8 @@ ft_mem_debug_panic( "not enough memory to perform memory debugging\n" ); - node->file_name = table->file_name; - node->line_no = table->line_no; + node->file_name = _ft_debug_file; + node->line_no = _ft_debug_lineno; node->cur_blocks = 0; node->max_blocks = 0; @@ -527,7 +537,7 @@ "org=%s:%d new=%s:%d\n", node->address, node->size, FT_FILENAME( node->source->file_name ), node->source->line_no, - FT_FILENAME( table->file_name ), table->line_no ); + FT_FILENAME( _ft_debug_file ), _ft_debug_lineno ); } } @@ -612,7 +622,7 @@ "freeing memory block at %p more than once at (%s:%ld)\n" "block allocated at (%s:%ld) and released at (%s:%ld)", address, - FT_FILENAME( table->file_name ), table->line_no, + FT_FILENAME( _ft_debug_file ), _ft_debug_lineno, FT_FILENAME( node->source->file_name ), node->source->line_no, FT_FILENAME( node->free_file_name ), node->free_line_no ); @@ -634,8 +644,8 @@ /* we simply invert the node's size to indicate that the node */ /* was freed. */ node->size = -node->size; - node->free_file_name = table->file_name; - node->free_line_no = table->line_no; + node->free_file_name = _ft_debug_file; + node->free_line_no = _ft_debug_lineno; } else { @@ -657,7 +667,7 @@ ft_mem_debug_panic( "trying to free unknown block at %p in (%s:%ld)\n", address, - FT_FILENAME( table->file_name ), table->line_no ); + FT_FILENAME( _ft_debug_file ), _ft_debug_lineno ); } } @@ -680,7 +690,7 @@ /* return NULL if this allocation would overflow the maximum heap size */ if ( table->bound_total && - table->alloc_current + (FT_ULong)size > table->alloc_total_max ) + table->alloc_total_max - table->alloc_current > (FT_ULong)size ) return NULL; block = (FT_Byte *)ft_mem_table_alloc( table, size ); @@ -691,8 +701,8 @@ table->alloc_count++; } - table->file_name = NULL; - table->line_no = 0; + _ft_debug_file = ""; + _ft_debug_lineno = 0; return (FT_Pointer)block; } @@ -707,8 +717,8 @@ if ( block == NULL ) ft_mem_debug_panic( "trying to free NULL in (%s:%ld)", - FT_FILENAME( table->file_name ), - table->line_no ); + FT_FILENAME( _ft_debug_file ), + _ft_debug_lineno ); ft_mem_table_remove( table, (FT_Byte*)block, 0 ); @@ -717,8 +727,8 @@ table->alloc_count--; - table->file_name = NULL; - table->line_no = 0; + _ft_debug_file = ""; + _ft_debug_lineno = 0; } @@ -733,8 +743,8 @@ FT_Pointer new_block; FT_Long delta; - const char* file_name = FT_FILENAME( table->file_name ); - FT_Long line_no = table->line_no; + const char* file_name = FT_FILENAME( _ft_debug_file ); + FT_Long line_no = _ft_debug_lineno; /* unlikely, but possible */ @@ -796,8 +806,8 @@ ft_mem_table_remove( table, (FT_Byte*)block, delta ); - table->file_name = NULL; - table->line_no = 0; + _ft_debug_file = ""; + _ft_debug_lineno = 0; if ( !table->keep_alive ) ft_mem_table_free( table, block ); @@ -887,217 +897,6 @@ } -#ifdef FT_STRICT_ALIASING - - - FT_BASE_DEF( FT_Pointer ) - ft_mem_alloc_debug( FT_Memory memory, - FT_Long size, - FT_Error *p_error, - const char* file_name, - FT_Long line_no ) - { - FT_MemTable table = (FT_MemTable)memory->user; - - - if ( table ) - { - table->file_name = file_name; - table->line_no = line_no; - } - - return ft_mem_alloc( memory, size, p_error ); - } - - - FT_BASE_DEF( FT_Pointer ) - ft_mem_realloc_debug( FT_Memory memory, - FT_Long current, - FT_Long size, - void* block, - FT_Error *p_error, - const char* file_name, - FT_Long line_no ) - { - FT_MemTable table = (FT_MemTable)memory->user; - - - if ( table ) - { - table->file_name = file_name; - table->line_no = line_no; - } - - return ft_mem_realloc( memory, current, size, block, p_error ); - } - - - FT_BASE_DEF( FT_Pointer ) - ft_mem_qalloc_debug( FT_Memory memory, - FT_Long size, - FT_Error *p_error, - const char* file_name, - FT_Long line_no ) - { - FT_MemTable table = (FT_MemTable)memory->user; - - - if ( table ) - { - table->file_name = file_name; - table->line_no = line_no; - } - - return ft_mem_qalloc( memory, size, p_error ); - } - - - FT_BASE_DEF( FT_Pointer ) - ft_mem_qrealloc_debug( FT_Memory memory, - FT_Long current, - FT_Long size, - void* block, - FT_Error *p_error, - const char* file_name, - FT_Long line_no ) - { - FT_MemTable table = (FT_MemTable)memory->user; - - - if ( table ) - { - table->file_name = file_name; - table->line_no = line_no; - } - - return ft_mem_qrealloc( memory, current, size, block, p_error ); - } - - - FT_BASE_DEF( void ) - ft_mem_free_debug( FT_Memory memory, - const void *P, - const char* file_name, - FT_Long line_no ) - { - FT_MemTable table = (FT_MemTable)memory->user; - - - if ( table ) - { - table->file_name = file_name; - table->line_no = line_no; - } - - ft_mem_free( memory, (void *)P ); - } - - -#else /* !FT_STRICT_ALIASING */ - - - FT_BASE_DEF( FT_Error ) - ft_mem_alloc_debug( FT_Memory memory, - FT_Long size, - void* *P, - const char* file_name, - FT_Long line_no ) - { - FT_MemTable table = (FT_MemTable)memory->user; - - - if ( table ) - { - table->file_name = file_name; - table->line_no = line_no; - } - - return ft_mem_alloc( memory, size, P ); - } - - - FT_BASE_DEF( FT_Error ) - ft_mem_realloc_debug( FT_Memory memory, - FT_Long current, - FT_Long size, - void* *P, - const char* file_name, - FT_Long line_no ) - { - FT_MemTable table = (FT_MemTable)memory->user; - - - if ( table ) - { - table->file_name = file_name; - table->line_no = line_no; - } - - return ft_mem_realloc( memory, current, size, P ); - } - - - FT_BASE_DEF( FT_Error ) - ft_mem_qalloc_debug( FT_Memory memory, - FT_Long size, - void* *P, - const char* file_name, - FT_Long line_no ) - { - FT_MemTable table = (FT_MemTable)memory->user; - - - if ( table ) - { - table->file_name = file_name; - table->line_no = line_no; - } - - return ft_mem_qalloc( memory, size, P ); - } - - - FT_BASE_DEF( FT_Error ) - ft_mem_qrealloc_debug( FT_Memory memory, - FT_Long current, - FT_Long size, - void* *P, - const char* file_name, - FT_Long line_no ) - { - FT_MemTable table = (FT_MemTable)memory->user; - - - if ( table ) - { - table->file_name = file_name; - table->line_no = line_no; - } - - return ft_mem_qrealloc( memory, current, size, P ); - } - - - FT_BASE_DEF( void ) - ft_mem_free_debug( FT_Memory memory, - FT_Pointer block, - const char* file_name, - FT_Long line_no ) - { - FT_MemTable table = (FT_MemTable)memory->user; - - - if ( table ) - { - table->file_name = file_name; - table->line_no = line_no; - } - - ft_mem_free( memory, (void **)block ); - } - - -#endif /* !FT_STRICT_ALIASING */ static int ft_mem_source_compare( const void* p1, diff --git a/src/base/ftutil.c b/src/base/ftutil.c index 824f92f8c..381fa81cd 100644 --- a/src/base/ftutil.c +++ b/src/base/ftutil.c @@ -46,31 +46,16 @@ /*************************************************************************/ -#ifdef FT_STRICT_ALIASING - - FT_BASE_DEF( FT_Pointer ) ft_mem_alloc( FT_Memory memory, FT_Long size, FT_Error *p_error ) { - FT_Error error = FT_Err_Ok; - FT_Pointer block = NULL; + FT_Error error; + FT_Pointer block = ft_mem_qalloc( memory, size, &error ); - - if ( size > 0 ) - { - block = memory->alloc( memory, size ); - if ( block == NULL ) - error = FT_Err_Out_Of_Memory; - else - FT_MEM_ZERO( block, size ); - } - else if ( size < 0 ) - { - /* may help catch/prevent nasty security issues */ - error = FT_Err_Invalid_Argument; - } + if ( !error && size > 0 ) + FT_MEM_ZERO( block, size ); *p_error = error; return block; @@ -105,45 +90,18 @@ FT_BASE_DEF( FT_Pointer ) ft_mem_realloc( FT_Memory memory, - FT_Long current, - FT_Long size, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, void* block, FT_Error *p_error ) { FT_Error error = FT_Err_Ok; - - if ( size < 0 || current < 0 ) - { - /* may help catch/prevent nasty security issues */ - error = FT_Err_Invalid_Argument; - } - else if ( size == 0 ) - { - ft_mem_free( memory, block ); - block = NULL; - } - else if ( current == 0 ) - { - FT_ASSERT( block == NULL ); - - block = ft_mem_alloc( memory, size, &error ); - } - else - { - FT_Pointer block2; - - - block2 = memory->realloc( memory, current, size, block ); - if ( block2 == NULL ) - error = FT_Err_Out_Of_Memory; - else - { - block = block2; - if ( size > current ) - FT_MEM_ZERO( (char*)block + current, size-current ); - } - } + block = ft_mem_qrealloc( memory, item_size, cur_count, new_count, block, &error ); + if ( !error && new_count > cur_count ) + FT_MEM_ZERO( (char*)block + cur_count*item_size, + (new_count-cur_count)*item_size ); *p_error = error; return block; @@ -152,36 +110,43 @@ FT_BASE_DEF( FT_Pointer ) ft_mem_qrealloc( FT_Memory memory, - FT_Long current, - FT_Long size, + FT_Long item_size, + FT_Long cur_count, + FT_Long new_count, void* block, FT_Error *p_error ) { FT_Error error = FT_Err_Ok; - if ( size < 0 || current < 0 ) + if ( cur_count < 0 || new_count < 0 || item_size <= 0 ) { /* may help catch/prevent nasty security issues */ error = FT_Err_Invalid_Argument; } - else if ( size == 0 ) + else if ( new_count == 0 ) { ft_mem_free( memory, block ); block = NULL; } - else if ( current == 0 ) + else if ( new_count > FT_INT_MAX/item_size ) + { + error = FT_Err_Array_Too_Large; + } + else if ( cur_count == 0 ) { FT_ASSERT( block == NULL ); - block = ft_mem_qalloc( memory, size, &error ); + block = ft_mem_alloc( memory, new_count*item_size, &error ); } else { FT_Pointer block2; + FT_Long cur_size = cur_count*item_size; + FT_Long new_size = new_count*item_size; - block2 = memory->realloc( memory, current, size, block ); + block2 = memory->realloc( memory, cur_size, new_size, block ); if ( block2 == NULL ) error = FT_Err_Out_Of_Memory; else @@ -202,194 +167,6 @@ } -#else /* !FT_STRICT_ALIASING */ - - - /* documentation is in ftmemory.h */ - - FT_BASE_DEF( FT_Error ) - ft_mem_alloc( FT_Memory memory, - FT_Long size, - void* *P ) - { - FT_Error error = FT_Err_Ok; - - - FT_ASSERT( P != 0 ); - - if ( size > 0 ) - { - *P = memory->alloc( memory, size ); - if ( !*P ) - { - FT_ERROR(( "ft_mem_alloc:" )); - FT_ERROR(( " Out of memory? (%ld requested)\n", - size )); - - return FT_Err_Out_Of_Memory; - } - FT_MEM_ZERO( *P, size ); - } - else - { - *P = NULL; - if ( size < 0 ) - error = FT_Err_Invalid_Argument; - } - - FT_TRACE7(( "ft_mem_alloc:" )); - FT_TRACE7(( " size = %ld, block = 0x%08p, ref = 0x%08p\n", - size, *P, P )); - - return error; - } - - - /* documentation is in ftmemory.h */ - - FT_BASE_DEF( FT_Error ) - ft_mem_qalloc( FT_Memory memory, - FT_Long size, - void* *P ) - { - FT_Error error = FT_Err_Ok; - - - FT_ASSERT( P != 0 ); - - if ( size > 0 ) - { - *P = memory->alloc( memory, size ); - if ( !*P ) - { - FT_ERROR(( "ft_mem_qalloc:" )); - FT_ERROR(( " Out of memory? (%ld requested)\n", - size )); - - return FT_Err_Out_Of_Memory; - } - } - else - { - *P = NULL; - if ( size < 0 ) - error = FT_Err_Invalid_Argument; - } - - FT_TRACE7(( "ft_mem_qalloc:" )); - FT_TRACE7(( " size = %ld, block = 0x%08p, ref = 0x%08p\n", - size, *P, P )); - - return error; - } - - - /* documentation is in ftmemory.h */ - - FT_BASE_DEF( FT_Error ) - ft_mem_realloc( FT_Memory memory, - FT_Long current, - FT_Long size, - void** P ) - { - void* Q; - - - FT_ASSERT( P != 0 ); - - /* if the original pointer is NULL, call ft_mem_alloc() */ - if ( !*P ) - return ft_mem_alloc( memory, size, P ); - - /* if the new block if zero-sized, clear the current one */ - if ( size == 0 ) - { - ft_mem_free( memory, P ); - return FT_Err_Ok; - } - - if ( size < 0 || current < 0 ) - return FT_Err_Invalid_Argument; - - Q = memory->realloc( memory, current, size, *P ); - if ( !Q ) - goto Fail; - - if ( size > current ) - FT_MEM_ZERO( (char*)Q + current, size - current ); - - *P = Q; - return FT_Err_Ok; - - Fail: - FT_ERROR(( "ft_mem_realloc:" )); - FT_ERROR(( " Failed (current %ld, requested %ld)\n", - current, size )); - return FT_Err_Out_Of_Memory; - } - - - /* documentation is in ftmemory.h */ - - FT_BASE_DEF( FT_Error ) - ft_mem_qrealloc( FT_Memory memory, - FT_Long current, - FT_Long size, - void** P ) - { - void* Q; - - - FT_ASSERT( P != 0 ); - - /* if the original pointer is NULL, call ft_mem_qalloc() */ - if ( !*P ) - return ft_mem_qalloc( memory, size, P ); - - /* if the new block if zero-sized, clear the current one */ - if ( size == 0 ) - { - ft_mem_free( memory, P ); - return FT_Err_Ok; - } - - if ( size < 0 || current < 0 ) - return FT_Err_Invalid_Argument; - - Q = memory->realloc( memory, current, size, *P ); - if ( !Q ) - goto Fail; - - *P = Q; - return FT_Err_Ok; - - Fail: - FT_ERROR(( "ft_mem_qrealloc:" )); - FT_ERROR(( " Failed (current %ld, requested %ld)\n", - current, size )); - return FT_Err_Out_Of_Memory; - } - - - /* documentation is in ftmemory.h */ - - FT_BASE_DEF( void ) - ft_mem_free( FT_Memory memory, - void* *P ) - { - FT_TRACE7(( "ft_mem_free:" )); - FT_TRACE7(( " Freeing block 0x%08p ref 0x%08p\n", P, *P )); - - if ( P && *P ) - { - memory->free( memory, *P ); - *P = NULL; - } - } - -#endif /* !FT_STRICT_ALIASING */ - - /*************************************************************************/ /*************************************************************************/ /*************************************************************************/