From c6e0cdacfac27326ae4221a047650939c1ec96cc Mon Sep 17 00:00:00 2001 From: suzuki toshiya Date: Wed, 5 Jan 2011 17:58:56 +0900 Subject: introduce FT2_ALLOC_{TOTAL,CUR}_MAX_SITE environment to restrict memory allocation locally --- include/freetype/internal/fttrace.h | 1 + src/base/ftdbgmem.c | 90 ++++++++++++++++++++++++++++++++++++- src/cache/ftccache.c | 23 ++++++++++ src/cache/ftccache.h | 13 ++++++ src/cache/ftcmanag.c | 24 ++++++++++ src/cache/ftcsbits.c | 4 ++ 6 files changed, 153 insertions(+), 2 deletions(-) diff --git a/include/freetype/internal/fttrace.h b/include/freetype/internal/fttrace.h index e9b383a58..5d2decc82 100644 --- a/include/freetype/internal/fttrace.h +++ b/include/freetype/internal/fttrace.h @@ -24,6 +24,7 @@ FT_TRACE_DEF( any ) /* base components */ FT_TRACE_DEF( calc ) /* calculations (ftcalc.c) */ FT_TRACE_DEF( memory ) /* memory manager (ftobjs.c) */ +FT_TRACE_DEF( dbgmem ) /* memory debugger (ftdbgmem.c) */ FT_TRACE_DEF( stream ) /* stream manager (ftstream.c) */ FT_TRACE_DEF( io ) /* i/o interface (ftsystem.c) */ FT_TRACE_DEF( list ) /* list management (ftlist.c) */ diff --git a/src/base/ftdbgmem.c b/src/base/ftdbgmem.c index 12fed04bb..16620afa2 100644 --- a/src/base/ftdbgmem.c +++ b/src/base/ftdbgmem.c @@ -16,6 +16,8 @@ /***************************************************************************/ +#include +#include #include #include FT_CONFIG_CONFIG_H #include FT_INTERNAL_DEBUG_H @@ -25,6 +27,10 @@ #include FT_TYPES_H +#undef FT_COMPONENT +#define FT_COMPONENT trace_dbgmem + + #ifdef FT_DEBUG_MEMORY #define KEEPALIVE /* `Keep alive' means that freed blocks aren't released @@ -505,6 +511,47 @@ } + static int + ft_mem_check_site_alloc_environment( FT_MemSource source, + const char* env_var_name ) + { + char *source_basename = basename( (char *)source->file_name ); + char *c, *c0; + + + /* environment is unset */ + c = c0 = getenv( env_var_name ); + if ( !c ) + return -1; + + /* basename not found */ + if ( NULL == ( c = strstr( c, source_basename ) ) ) + return -1; + + /* found position was substring */ + if ( c != c0 && *(c-1) != ',' && *(c-1) != '/' ) + return -1; + + /* invalid syntax without line number */ + c = c + strlen( source_basename ); + if ( ':' != *c ) + return -1; + + /* line number differs */ + if ( atoi( c + 1 ) != source->line_no ) + return -1; + + /* invalid syntax without max memory space */ + if ( NULL == index( c + 1, ':' ) ) + return -1; + c = index( c + 1, ':' ); + if ( !ft_isdigit( c[1] ) ) + return -1; + + return atoi( c + 1 ); + } + + static void ft_mem_table_set( FT_MemTable table, FT_Byte* address, @@ -680,13 +727,52 @@ ft_mem_debug_alloc( FT_Memory memory, FT_Long size ) { - FT_MemTable table = (FT_MemTable)memory->user; - FT_Byte* block; + FT_MemTable table = (FT_MemTable)memory->user; + FT_MemSource source = NULL; + FT_Byte* block; if ( size <= 0 ) ft_mem_debug_panic( "negative block size allocation (%ld)", size ); + { + int mem_limit_site_total = -1; /* negative means unlimited */ + int mem_limit_site_cur = -1; /* negative means unlimited */ + FT_Bool exceeds_limit_site_total = FALSE; + FT_Bool exceeds_limit_site_cur = FALSE; + + + source = ft_mem_table_get_source( table ); + mem_limit_site_total = ft_mem_check_site_alloc_environment( source, "FT2_ALLOC_TOTAL_MAX_SITE" ); + mem_limit_site_cur = ft_mem_check_site_alloc_environment( source, "FT2_ALLOC_CUR_MAX_SITE" ); + if ( mem_limit_site_total >= 0 || mem_limit_site_cur >= 0 ) + FT_TRACE1(("ft_mem_table_set() invoked by %s:%lu, limit:( ")); + if ( mem_limit_site_total >= 0 ) + FT_TRACE1(("%ld =< %ld", source->all_size + size, mem_limit_site_total )); + if ( mem_limit_site_total >= 0 && mem_limit_site_cur >= 0 ) + FT_TRACE1((" && ")); + if ( mem_limit_site_cur >= 0 ) + FT_TRACE1(("%ld =< %ld", source->cur_size + size, mem_limit_site_cur )); + if ( mem_limit_site_total >= 0 || mem_limit_site_cur >= 0 ) + FT_TRACE1((" )\n")); + + if ( mem_limit_site_total >= 0 && mem_limit_site_total < ( source->all_size + size ) ) + exceeds_limit_site_total = TRUE; + if ( mem_limit_site_cur >= 0 && mem_limit_site_cur < ( source->cur_size + size ) ) + exceeds_limit_site_cur = TRUE; + + if ( exceeds_limit_site_total || exceeds_limit_site_cur ) + { + FT_TRACE1(("ft_mem_table_set() returns NULL to %s:%lu, allocation request exceeds %s-limit (%lu > %lu)\n", + basename( (char*)source->file_name ), source->line_no, + ( exceeds_limit_site_total ? "site-total" : "site-current" ), + ( exceeds_limit_site_total ? source->all_size : source->cur_size ) + size, + ( exceeds_limit_site_total ? mem_limit_site_total : mem_limit_site_cur ) + )); + return NULL; + } + } + /* return NULL if the maximum number of allocations was reached */ if ( table->bound_count && table->alloc_count >= table->alloc_count_max ) diff --git a/src/cache/ftccache.c b/src/cache/ftccache.c index ad1c5c307..a72af5809 100644 --- a/src/cache/ftccache.c +++ b/src/cache/ftccache.c @@ -478,6 +478,29 @@ } + FT_LOCAL_DEF( FT_Size ) + ftc_get_list_length( FTC_Cache cache, + FT_PtrDist hash ) + { + FT_Size len = 0; + FTC_Node* bucket; + FTC_Node* pnode; + FT_UFast idx; + + + idx = hash & cache->mask; + if ( idx < cache->p ) + idx = hash & ( cache->mask * 2 + 1 ); + + bucket = cache->buckets + idx; + pnode = bucket; + for ( ; pnode && *pnode; pnode = &((*pnode)->link) ) + len++; + + return len; + } + + #ifndef FTC_INLINE FT_LOCAL_DEF( FT_Error ) diff --git a/src/cache/ftccache.h b/src/cache/ftccache.h index d696621e7..323892a02 100644 --- a/src/cache/ftccache.h +++ b/src/cache/ftccache.h @@ -210,6 +210,10 @@ FT_BEGIN_HEADER FTC_Cache_RemoveFaceID( FTC_Cache cache, FTC_FaceID face_id ); + FT_LOCAL( FT_Size ) + ftc_get_list_length( FTC_Cache cache, + FT_PtrDist hash ); + #ifdef FTC_INLINE @@ -222,6 +226,11 @@ FT_BEGIN_HEADER FT_Bool _list_changed = FALSE; \ \ \ + FT_TRACE7(("FTC_CACHE_LOOKUP_CMP() lookup object for ")); \ + FT_TRACE7(("hash=0x%08x in cache ", _hash )); \ + FT_TRACE7(("mask=0x%08x p=0x%08x ", _cache->mask, _cache->p )); \ + FT_TRACE7(("list length=%d\n", ftc_get_list_length( _cache, _hash ) )); \ + \ error = FTC_Err_Ok; \ node = NULL; \ \ @@ -245,6 +254,8 @@ FT_BEGIN_HEADER \ if ( _list_changed ) \ { \ + FT_TRACE7(("(_bucket,_pnode)=(%p,%p)", _bucket, _pnode)); \ + \ /* Update _bucket by possibly modified linked list */ \ _bucket = _pnode = FTC_NODE__TOP_FOR_HASH( _cache, _hash ); \ \ @@ -259,6 +270,8 @@ FT_BEGIN_HEADER else \ _pnode = &((*_pnode)->link); \ } \ + \ + FT_TRACE7(("-> (%p,%p)\n", _bucket, _pnode)); \ } \ \ /* Reorder the list to move the found node to the `top' */ \ diff --git a/src/cache/ftcmanag.c b/src/cache/ftcmanag.c index 548ebe951..827dd5e4e 100644 --- a/src/cache/ftcmanag.c +++ b/src/cache/ftcmanag.c @@ -622,6 +622,24 @@ } + static int + ft_get_length_nodes_list( FTC_Node node0 ) + { + FTC_Node node = node0; + int len = 0; + + + while ( node ) + { + len ++; + node = node->link; + if ( node == node0 ) + return len; + } + return len; + } + + FT_LOCAL_DEF( FT_UInt ) FTC_Manager_FlushN( FTC_Manager manager, FT_UInt count ) @@ -631,9 +649,14 @@ FT_UInt result; + FT_TRACE1(("%s() tries to free %d nodes from list length=%d\n", __FUNCTION__, count, ft_get_length_nodes_list( manager->nodes_list ) )); + /* try to remove `count' nodes from the list */ if ( first == NULL ) /* empty list! */ + { + FT_TRACE1(("%s() cannot change empty list\n", __FUNCTION__ )); return 0; + } /* go to last node - it's a circular list */ node = FTC_NODE__PREV(first); @@ -654,6 +677,7 @@ node = prev; } + FT_TRACE1(("%s() freed %d nodes, list length=%d\n", __FUNCTION__, result, ft_get_length_nodes_list( manager->nodes_list ) )); return result; } diff --git a/src/cache/ftcsbits.c b/src/cache/ftcsbits.c index d4db99416..097c8d84c 100644 --- a/src/cache/ftcsbits.c +++ b/src/cache/ftcsbits.c @@ -125,6 +125,7 @@ sbit->buffer = 0; error = clazz->family_load_glyph( family, gindex, manager, &face ); + FT_TRACE1(("ftc_snode_load() got error from family_load_glyph() err=0x%02x%s\n", error, error ? " fallback to BadGlyph" : "" )); if ( error ) goto BadGlyph; @@ -200,6 +201,7 @@ *asize = 0; } + FT_TRACE7(("ftc_snode_load() load glyph for gid=%d, err=0x%02x\n", gindex, error)); return error; } @@ -334,6 +336,7 @@ FT_Bool result; + FT_TRACE1(( "ftc_snode_compare() work for gindex=%d\n", gindex )); if (list_changed) *list_changed = FALSE; result = FT_BOOL( gnode->family == gquery->family && @@ -400,6 +403,7 @@ } } + FT_TRACE1(("%s() returns %s\n", __FUNCTION__, result ? "TRUE" : "FALSE")); return result; } -- cgit v1.2.1