* 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.
This commit is contained in:
David Turner 2006-05-02 06:34:27 +00:00
parent a229540280
commit 264f307e66
6 changed files with 159 additions and 909 deletions

View File

@ -1,3 +1,30 @@
2006-05-02 David Turner <david@freetype.org>
* 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 <mpsuzuki@hiroshima-u.ac.jp> 2006-04-30 suzuki toshiya <mpsuzuki@hiroshima-u.ac.jp>
Fix bug in Mac_Read_POST_Resource() to parse PFB font with MacOS Fix bug in Mac_Read_POST_Resource() to parse PFB font with MacOS

View File

@ -267,7 +267,7 @@ FT_BEGIN_HEADER
#ifdef __cplusplus #ifdef __cplusplus
#define FT_BASE_DEF( x ) extern "C" x #define FT_BASE_DEF( x ) extern "C" x
#else #else
#define FT_BASE_DEF( x ) extern x #define FT_BASE_DEF( x ) x
#endif #endif
#endif /* !FT_BASE_DEF */ #endif /* !FT_BASE_DEF */

View File

@ -52,6 +52,8 @@
"broken table" ) "broken table" )
FT_ERRORDEF_( Invalid_Offset, 0x09, \ FT_ERRORDEF_( Invalid_Offset, 0x09, \
"broken offset within table" ) "broken offset within table" )
FT_ERRORDEF_( Array_Too_Large, 0x0A, \
"array allocation size too large" )
/* glyph/character errors */ /* glyph/character errors */

View File

@ -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 * The allocation functions return a pointer, and the error code
@ -78,15 +88,17 @@ FT_BEGIN_HEADER
FT_BASE( FT_Pointer ) FT_BASE( FT_Pointer )
ft_mem_realloc( FT_Memory memory, ft_mem_realloc( FT_Memory memory,
FT_Long current, FT_Long item_size,
FT_Long size, FT_Long cur_count,
FT_Long new_count,
void* block, void* block,
FT_Error *p_error ); FT_Error *p_error );
FT_BASE( FT_Pointer ) FT_BASE( FT_Pointer )
ft_mem_qrealloc( FT_Memory memory, ft_mem_qrealloc( FT_Memory memory,
FT_Long current, FT_Long item_size,
FT_Long size, FT_Long cur_count,
FT_Long new_count,
void* block, void* block,
FT_Error *p_error ); FT_Error *p_error );
@ -95,367 +107,39 @@ FT_BEGIN_HEADER
const void* P ); 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 ) #define FT_MEM_NEW(ptr) \
ft_mem_alloc_debug( FT_Memory memory, FT_MEM_ALLOC( ptr, sizeof(*(ptr)) )
FT_Long size,
FT_Error *p_error,
const char* file_name,
FT_Long line_no );
FT_BASE( FT_Pointer ) #define FT_MEM_REALLOC( ptr, cur, new ) \
ft_mem_qalloc_debug( FT_Memory memory, FT_DEBUG_INNER( (ptr) = ft_mem_realloc( memory, 1, (cur), (new), (ptr), &error ) )
FT_Long size,
FT_Error *p_error,
const char* file_name,
FT_Long line_no );
FT_BASE( FT_Pointer ) #define FT_MEM_QALLOC(ptr,size) \
ft_mem_realloc_debug( FT_Memory memory, FT_DEBUG_INNER( (ptr) = ft_mem_qalloc( memory, (size), &error ) )
FT_Long current,
FT_Long size,
void* P,
FT_Error *p_error,
const char* file_name,
FT_Long line_no );
FT_BASE( FT_Pointer ) #define FT_MEM_QNEW(ptr) \
ft_mem_qrealloc_debug( FT_Memory memory, FT_MEM_QALLOC( ptr, sizeof(*(ptr)) )
FT_Long current,
FT_Long size,
void* P,
FT_Error *p_error,
const char* file_name,
FT_Long line_no );
FT_BASE( void ) #define FT_MEM_QREALLOC( ptr, cur, new ) \
ft_mem_free_debug( FT_Memory memory, FT_DEBUG_INNER( (ptr) = ft_mem_qrealloc( memory, 1, (cur), (new), (ptr), &error ) )
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_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 ) #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_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_ZERO( p ) FT_MEM_ZERO( p, sizeof ( *(p) ) )
#define FT_ARRAY_ZERO( dest, count ) \ #define FT_ARRAY_ZERO( dest, count ) \
FT_MEM_ZERO( dest, (count) * sizeof ( *(dest) ) ) FT_MEM_ZERO( dest, (count) * sizeof ( *(dest) ) )
@ -494,92 +179,52 @@ FT_BEGIN_HEADER
/* _typed_ in order to automatically compute array element sizes. */ /* _typed_ in order to automatically compute array element sizes. */
/* */ /* */
#define FT_MEM_NEW( _pointer_ ) \ #define FT_MEM_NEW_ARRAY(ptr,count) \
FT_MEM_ALLOC( _pointer_, sizeof ( *(_pointer_) ) ) FT_DEBUG_INNER( (ptr) = ft_mem_realloc( memory, sizeof(*(ptr)), 0, (count), NULL, &error ) )
#define FT_MEM_NEW_ARRAY( _pointer_, _count_ ) \ #define FT_MEM_RENEW_ARRAY(ptr,cur,new) \
FT_MEM_ALLOC( _pointer_, (_count_) * sizeof ( *(_pointer_) ) ) FT_DEBUG_INNER( (ptr) = ft_mem_realloc( memory, sizeof(*(ptr)), (cur), (new), (ptr), &error ) )
#define FT_MEM_RENEW_ARRAY( _pointer_, _old_, _new_ ) \ #define FT_MEM_QNEW_ARRAY(ptr,count) \
FT_MEM_REALLOC( _pointer_, (_old_) * sizeof ( *(_pointer_) ), \ FT_DEBUG_INNER( (ptr) = ft_mem_qrealloc( memory, sizeof(*(ptr)), 0, (count), NULL, &error ) )
(_new_) * sizeof ( *(_pointer_) ) )
#define FT_MEM_QNEW( _pointer_ ) \ #define FT_MEM_QRENEW_ARRAY(ptr,cur,new) \
FT_MEM_QALLOC( _pointer_, sizeof ( *(_pointer_) ) ) 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) )
/* the following macros are obsolete but kept for compatibility reasons */
/* */
#define FT_MEM_ALLOC_ARRAY( _pointer_, _count_, _type_ ) \ #define FT_REALLOC(ptr,cursz,newsz) \
FT_MEM_ALLOC( _pointer_, (_count_) * sizeof ( _type_ ) ) FT_MEM_SET_ERROR( FT_MEM_REALLOC(ptr,cursz,newsz) )
#define FT_MEM_REALLOC_ARRAY( _pointer_, _old_, _new_, _type_ ) \ #define FT_QALLOC(ptr,size) \
FT_MEM_REALLOC( _pointer_, (_old_) * sizeof ( _type ), \ FT_MEM_SET_ERROR( FT_MEM_QALLOC(ptr,size) )
(_new_) * sizeof ( _type_ ) )
#define FT_QREALLOC(ptr,cursz,newsz) \
FT_MEM_SET_ERROR( FT_MEM_QREALLOC(ptr,cursz,newsz) )
/*************************************************************************/ #define FT_FREE(ptr) FT_MEM_FREE( 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_ALLOC( _pointer_, _size_ ) \ #define FT_NEW(ptr) \
FT_MEM_SET_ERROR( FT_MEM_ALLOC( _pointer_, _size_ ) ) FT_MEM_SET_ERROR( FT_MEM_NEW(ptr) )
#define FT_REALLOC( _pointer_, _current_, _size_ ) \ #define FT_NEW_ARRAY(ptr,count) \
FT_MEM_SET_ERROR( FT_MEM_REALLOC( _pointer_, _current_, _size_ ) ) FT_MEM_SET_ERROR( FT_MEM_NEW_ARRAY(ptr,count) )
#define FT_QALLOC( _pointer_, _size_ ) \ #define FT_RENEW_ARRAY(ptr,curcnt,newcnt) \
FT_MEM_SET_ERROR( FT_MEM_QALLOC( _pointer_, _size_ ) ) FT_MEM_SET_ERROR( FT_MEM_RENEW_ARRAY(ptr,curcnt,newcnt) )
#define FT_QREALLOC( _pointer_, _current_, _size_ ) \ #define FT_QNEW(ptr) \
FT_MEM_SET_ERROR( FT_MEM_QREALLOC( _pointer_, _current_, _size_ ) ) 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_ ) \ #define FT_QRENEW_ARRAY(ptr,curcnt,newcnt) \
FT_MEM_FREE( _pointer_ ) 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 #ifdef FT_CONFIG_OPTION_OLD_INTERNALS

View File

@ -36,6 +36,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
FT_BASE_DEF( const char* ) _ft_debug_file = 0;
FT_BASE_DEF( long ) _ft_debug_lineno = 0;
extern void extern void
FT_DumpMemory( FT_Memory memory ); FT_DumpMemory( FT_Memory memory );
@ -48,7 +50,10 @@
#define FT_MEM_VAL( addr ) ((FT_ULong)(FT_Pointer)( addr )) #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_ typedef struct FT_MemSourceRec_
{ {
const char* file_name; const char* file_name;
@ -76,7 +81,12 @@
*/ */
#define FT_MEM_SOURCE_BUCKETS 128 #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_ typedef struct FT_MemNodeRec_
{ {
FT_Byte* address; FT_Byte* address;
@ -94,6 +104,9 @@
} FT_MemNodeRec; } FT_MemNodeRec;
/* the global structure, containing compound statistics and all hash
* tables
*/
typedef struct FT_MemTableRec_ typedef struct FT_MemTableRec_
{ {
FT_ULong size; FT_ULong size;
@ -113,9 +126,6 @@
FT_MemSource sources[FT_MEM_SOURCE_BUCKETS]; FT_MemSource sources[FT_MEM_SOURCE_BUCKETS];
const char* file_name;
FT_Long line_no;
FT_Bool keep_alive; FT_Bool keep_alive;
FT_Memory memory; FT_Memory memory;
@ -447,8 +457,8 @@
FT_MemSource node, *pnode; FT_MemSource node, *pnode;
hash = (FT_UInt32)(void*)table->file_name + hash = (FT_UInt32)(void*)_ft_debug_file +
(FT_UInt32)( 5 * table->line_no ); (FT_UInt32)( 5 * _ft_debug_lineno );
pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS]; pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS];
for ( ;; ) for ( ;; )
@ -457,8 +467,8 @@
if ( node == NULL ) if ( node == NULL )
break; break;
if ( node->file_name == table->file_name && if ( node->file_name == _ft_debug_file &&
node->line_no == table->line_no ) node->line_no == _ft_debug_lineno )
goto Exit; goto Exit;
pnode = &node->link; pnode = &node->link;
@ -469,8 +479,8 @@
ft_mem_debug_panic( ft_mem_debug_panic(
"not enough memory to perform memory debugging\n" ); "not enough memory to perform memory debugging\n" );
node->file_name = table->file_name; node->file_name = _ft_debug_file;
node->line_no = table->line_no; node->line_no = _ft_debug_lineno;
node->cur_blocks = 0; node->cur_blocks = 0;
node->max_blocks = 0; node->max_blocks = 0;
@ -527,7 +537,7 @@
"org=%s:%d new=%s:%d\n", "org=%s:%d new=%s:%d\n",
node->address, node->size, node->address, node->size,
FT_FILENAME( node->source->file_name ), node->source->line_no, 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" "freeing memory block at %p more than once at (%s:%ld)\n"
"block allocated at (%s:%ld) and released at (%s:%ld)", "block allocated at (%s:%ld) and released at (%s:%ld)",
address, 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->source->file_name ), node->source->line_no,
FT_FILENAME( node->free_file_name ), node->free_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 */ /* we simply invert the node's size to indicate that the node */
/* was freed. */ /* was freed. */
node->size = -node->size; node->size = -node->size;
node->free_file_name = table->file_name; node->free_file_name = _ft_debug_file;
node->free_line_no = table->line_no; node->free_line_no = _ft_debug_lineno;
} }
else else
{ {
@ -657,7 +667,7 @@
ft_mem_debug_panic( ft_mem_debug_panic(
"trying to free unknown block at %p in (%s:%ld)\n", "trying to free unknown block at %p in (%s:%ld)\n",
address, 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 */ /* return NULL if this allocation would overflow the maximum heap size */
if ( table->bound_total && 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; return NULL;
block = (FT_Byte *)ft_mem_table_alloc( table, size ); block = (FT_Byte *)ft_mem_table_alloc( table, size );
@ -691,8 +701,8 @@
table->alloc_count++; table->alloc_count++;
} }
table->file_name = NULL; _ft_debug_file = "<unknown>";
table->line_no = 0; _ft_debug_lineno = 0;
return (FT_Pointer)block; return (FT_Pointer)block;
} }
@ -707,8 +717,8 @@
if ( block == NULL ) if ( block == NULL )
ft_mem_debug_panic( "trying to free NULL in (%s:%ld)", ft_mem_debug_panic( "trying to free NULL in (%s:%ld)",
FT_FILENAME( table->file_name ), FT_FILENAME( _ft_debug_file ),
table->line_no ); _ft_debug_lineno );
ft_mem_table_remove( table, (FT_Byte*)block, 0 ); ft_mem_table_remove( table, (FT_Byte*)block, 0 );
@ -717,8 +727,8 @@
table->alloc_count--; table->alloc_count--;
table->file_name = NULL; _ft_debug_file = "<unknown>";
table->line_no = 0; _ft_debug_lineno = 0;
} }
@ -733,8 +743,8 @@
FT_Pointer new_block; FT_Pointer new_block;
FT_Long delta; FT_Long delta;
const char* file_name = FT_FILENAME( table->file_name ); const char* file_name = FT_FILENAME( _ft_debug_file );
FT_Long line_no = table->line_no; FT_Long line_no = _ft_debug_lineno;
/* unlikely, but possible */ /* unlikely, but possible */
@ -796,8 +806,8 @@
ft_mem_table_remove( table, (FT_Byte*)block, delta ); ft_mem_table_remove( table, (FT_Byte*)block, delta );
table->file_name = NULL; _ft_debug_file = "<unknown>";
table->line_no = 0; _ft_debug_lineno = 0;
if ( !table->keep_alive ) if ( !table->keep_alive )
ft_mem_table_free( table, block ); 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 static int
ft_mem_source_compare( const void* p1, ft_mem_source_compare( const void* p1,

View File

@ -46,31 +46,16 @@
/*************************************************************************/ /*************************************************************************/
#ifdef FT_STRICT_ALIASING
FT_BASE_DEF( FT_Pointer ) FT_BASE_DEF( FT_Pointer )
ft_mem_alloc( FT_Memory memory, ft_mem_alloc( FT_Memory memory,
FT_Long size, FT_Long size,
FT_Error *p_error ) FT_Error *p_error )
{ {
FT_Error error = FT_Err_Ok; FT_Error error;
FT_Pointer block = NULL; FT_Pointer block = ft_mem_qalloc( memory, size, &error );
if ( !error && size > 0 )
if ( size > 0 ) FT_MEM_ZERO( block, size );
{
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; *p_error = error;
return block; return block;
@ -105,45 +90,18 @@
FT_BASE_DEF( FT_Pointer ) FT_BASE_DEF( FT_Pointer )
ft_mem_realloc( FT_Memory memory, ft_mem_realloc( FT_Memory memory,
FT_Long current, FT_Long item_size,
FT_Long size, FT_Long cur_count,
FT_Long new_count,
void* block, void* block,
FT_Error *p_error ) FT_Error *p_error )
{ {
FT_Error error = FT_Err_Ok; FT_Error error = FT_Err_Ok;
block = ft_mem_qrealloc( memory, item_size, cur_count, new_count, block, &error );
if ( size < 0 || current < 0 ) if ( !error && new_count > cur_count )
{ FT_MEM_ZERO( (char*)block + cur_count*item_size,
/* may help catch/prevent nasty security issues */ (new_count-cur_count)*item_size );
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; *p_error = error;
return block; return block;
@ -152,36 +110,43 @@
FT_BASE_DEF( FT_Pointer ) FT_BASE_DEF( FT_Pointer )
ft_mem_qrealloc( FT_Memory memory, ft_mem_qrealloc( FT_Memory memory,
FT_Long current, FT_Long item_size,
FT_Long size, FT_Long cur_count,
FT_Long new_count,
void* block, void* block,
FT_Error *p_error ) FT_Error *p_error )
{ {
FT_Error error = FT_Err_Ok; 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 */ /* may help catch/prevent nasty security issues */
error = FT_Err_Invalid_Argument; error = FT_Err_Invalid_Argument;
} }
else if ( size == 0 ) else if ( new_count == 0 )
{ {
ft_mem_free( memory, block ); ft_mem_free( memory, block );
block = NULL; 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 ); FT_ASSERT( block == NULL );
block = ft_mem_qalloc( memory, size, &error ); block = ft_mem_alloc( memory, new_count*item_size, &error );
} }
else else
{ {
FT_Pointer block2; 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 ) if ( block2 == NULL )
error = FT_Err_Out_Of_Memory; error = FT_Err_Out_Of_Memory;
else 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 */
/*************************************************************************/ /*************************************************************************/
/*************************************************************************/ /*************************************************************************/
/*************************************************************************/ /*************************************************************************/