ref: 264f307e66f9c2763b2e31b0a4e7513b7866745a
parent: a229540280f53b41c7a82d251b7497b8eb9c91f2
author: David Turner <[email protected]>
date: Tue May 2 02:34:27 EDT 2006
* 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.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2006-05-02 David Turner <[email protected]>
+
+ * 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 <[email protected]>
Fix bug in Mac_Read_POST_Resource() to parse PFB font with MacOS
--- a/include/freetype/config/ftconfig.h
+++ b/include/freetype/config/ftconfig.h
@@ -267,7 +267,7 @@
#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 */
--- 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 */
--- a/include/freetype/internal/ftmemory.h
+++ b/include/freetype/internal/ftmemory.h
@@ -57,9 +57,19 @@
/*************************************************************************/
-#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
* is written to through the `p_error' parameter. See below for
@@ -78,15 +88,17 @@
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,368 +107,40 @@
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_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_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_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 */
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* ft_mem_alloc */
- /* */
- /* <Description> */
- /* Allocates a new block of memory. The returned area is always */
- /* zero-filled; this is a strong convention in many FreeType parts. */
- /* */
- /* <Input> */
- /* memory :: A handle to a given `memory object' which handles */
- /* allocation. */
- /* */
- /* size :: The size in bytes of the block to allocate. */
- /* */
- /* <Output> */
- /* P :: A pointer to the fresh new block. It should be set to */
- /* NULL if `size' is 0, or in case of error. */
- /* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- FT_BASE( FT_Error )
- ft_mem_alloc( FT_Memory memory,
- FT_Long size,
- void* *P );
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* ft_mem_qalloc */
- /* */
- /* <Description> */
- /* Allocates a new block of memory. The returned area is *not* */
- /* zero-filled, making allocation quicker. */
- /* */
- /* <Input> */
- /* memory :: A handle to a given `memory object' which handles */
- /* allocation. */
- /* */
- /* size :: The size in bytes of the block to allocate. */
- /* */
- /* <Output> */
- /* P :: A pointer to the fresh new block. It should be set to */
- /* NULL if `size' is 0, or in case of error. */
- /* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- FT_BASE( FT_Error )
- ft_mem_qalloc( FT_Memory memory,
- FT_Long size,
- void* *p );
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* ft_mem_realloc */
- /* */
- /* <Description> */
- /* Reallocates a block of memory pointed to by `*P' to `Size' bytes */
- /* from the heap, possibly changing `*P'. The returned area is */
- /* zero-filled. */
- /* */
- /* <Input> */
- /* 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. */
- /* */
- /* <InOut> */
- /* P :: A pointer to the fresh new block. It should be set to */
- /* NULL if `size' is 0, or in case of error. */
- /* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- /* <Note> */
- /* 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 );
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* ft_mem_qrealloc */
- /* */
- /* <Description> */
- /* 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. */
- /* */
- /* <Input> */
- /* 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. */
- /* */
- /* <InOut> */
- /* P :: A pointer to the fresh new block. It should be set to */
- /* NULL if `size' is 0, or in case of error. */
- /* */
- /* <Return> */
- /* FreeType error code. 0 means success. */
- /* */
- /* <Note> */
- /* 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 );
-
-
- /*************************************************************************/
- /* */
- /* <Function> */
- /* ft_mem_free */
- /* */
- /* <Description> */
- /* Releases a given block of memory allocated through ft_mem_alloc(). */
- /* */
- /* <Input> */
- /* 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. */
- /* */
- /* <Note> */
- /* 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 )
#define FT_MEM_COPY( dest, source, count ) ft_memcpy( dest, source, count )
@@ -468,6 +152,7 @@
#define FT_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) )
+
#define FT_ARRAY_ZERO( dest, count ) \
FT_MEM_ZERO( dest, (count) * sizeof ( *(dest) ) )
@@ -494,91 +179,51 @@
/* _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_QRENEW_ARRAY(ptr,cur,new) \
+ FT_DEBUG_INNER( (ptr) = ft_mem_qrealloc( memory, sizeof(*(ptr)), (cur), (new), (ptr), &error ) )
-#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_ALLOC(ptr,size) \
+ FT_MEM_SET_ERROR( FT_MEM_ALLOC(ptr,size) )
+#define FT_REALLOC(ptr,cursz,newsz) \
+ FT_MEM_SET_ERROR( FT_MEM_REALLOC(ptr,cursz,newsz) )
- /*************************************************************************/
- /* */
- /* the following macros are obsolete but kept for compatibility reasons */
- /* */
+#define FT_QALLOC(ptr,size) \
+ FT_MEM_SET_ERROR( FT_MEM_QALLOC(ptr,size) )
-#define FT_MEM_ALLOC_ARRAY( _pointer_, _count_, _type_ ) \
- FT_MEM_ALLOC( _pointer_, (_count_) * sizeof ( _type_ ) )
+#define FT_QREALLOC(ptr,cursz,newsz) \
+ FT_MEM_SET_ERROR( FT_MEM_QREALLOC(ptr,cursz,newsz) )
-#define FT_MEM_REALLOC_ARRAY( _pointer_, _old_, _new_, _type_ ) \
- FT_MEM_REALLOC( _pointer_, (_old_) * sizeof ( _type ), \
- (_new_) * sizeof ( _type_ ) )
+#define FT_FREE(ptr) FT_MEM_FREE( ptr )
+#define FT_NEW(ptr) \
+ FT_MEM_SET_ERROR( FT_MEM_NEW(ptr) )
- /*************************************************************************/
- /* */
- /* 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_NEW_ARRAY(ptr,count) \
+ FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY(ptr,count) )
-#define FT_ALLOC( _pointer_, _size_ ) \
- FT_MEM_SET_ERROR( FT_MEM_ALLOC( _pointer_, _size_ ) )
+#define FT_RENEW_ARRAY(ptr,curcnt,newcnt) \
+ FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY(ptr,curcnt,newcnt) )
-#define FT_REALLOC( _pointer_, _current_, _size_ ) \
- FT_MEM_SET_ERROR( FT_MEM_REALLOC( _pointer_, _current_, _size_ ) )
+#define FT_QNEW(ptr) \
+ FT_MEM_SET_ERROR( FT_MEM_QNEW(ptr) )
-#define FT_QALLOC( _pointer_, _size_ ) \
- FT_MEM_SET_ERROR( FT_MEM_QALLOC( _pointer_, _size_ ) )
+#define FT_QNEW_ARRAY(ptr,count) \
+ FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY(ptr,count) )
-#define FT_QREALLOC( _pointer_, _current_, _size_ ) \
- FT_MEM_SET_ERROR( FT_MEM_QREALLOC( _pointer_, _current_, _size_ ) )
+#define FT_QRENEW_ARRAY(ptr,curcnt,newcnt) \
+ FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY(ptr,curcnt,newcnt) )
-
-#define FT_FREE( _pointer_ ) \
- FT_MEM_FREE( _pointer_ )
-
-
-#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
--- a/src/base/ftdbgmem.c
+++ b/src/base/ftdbgmem.c
@@ -36,6 +36,8 @@
#include <stdio.h>
#include <stdlib.h>
+ 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 = "<unknown>";
+ _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 = "<unknown>";
+ _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 = "<unknown>";
+ _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,
--- a/src/base/ftutil.c
+++ b/src/base/ftutil.c
@@ -46,32 +46,17 @@
/*************************************************************************/
-#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 ( !error && size > 0 )
+ FT_MEM_ZERO( block, size );
- 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;
- }
-
*p_error = error;
return block;
}
@@ -105,46 +90,19 @@
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;
+ 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 );
- 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 );
- }
- }
-
*p_error = error;
return block;
}
@@ -152,8 +110,9 @@
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 )
{
@@ -160,28 +119,34 @@
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
@@ -200,194 +165,6 @@
if ( P )
memory->free( memory, (void*)P );
}
-
-
-#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 */
/*************************************************************************/