try to cope better with apps which leak autorelease pools.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@33099 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2011-05-24 10:52:25 +00:00
parent afc2ef7de8
commit e32626abe7
2 changed files with 66 additions and 10 deletions

View file

@ -1,7 +1,16 @@
2011-05-24 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSAutoreleasePool.m:
Try to better cope with bad code which leaks autorelease pools.
1. check number of pools in thread when creating a new one, and
raise an exception if too many are created.
2. when deallocating a pool, avoid recursively deallocating child
pools so that a large number of pools won't cause stack overflow.
2011-05-23 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSBundle.m:
Fixe to resolve links and standardize path to current executable.
Fix to resolve links and standardize path to current executable.
2011-05-22 Richard Frith-Macdonald <rfm@gnu.org>

View file

@ -156,6 +156,11 @@ static NSAutoreleasePool *pool = nil;
return;
}
+ (void) setPoolNumberThreshhold: (unsigned)c
{
return;
}
@end
#else
@ -166,9 +171,13 @@ static NSAutoreleasePool *pool = nil;
static BOOL autorelease_enabled = YES;
/* When the _released_count of a pool gets over this value, we raise
an exception. This can be adjusted with -setPoolCountThreshhold */
an exception. This can be adjusted with +setPoolCountThreshhold */
static unsigned pool_count_warning_threshhold = UINT_MAX;
/* When the number of pools in a thread gets over this value, we raise
an exception. This can be adjusted with +setPoolNumberThreshhold */
static unsigned pool_number_warning_threshhold = 10000;
/* The size of the first _released array. */
#define BEGINNING_POOL_SIZE 32
@ -305,10 +314,25 @@ pop_pool_from_cache (struct autorelease_thread_vars *tv)
*/
{
struct autorelease_thread_vars *tv = ARP_THREAD_VARS;
unsigned level = 0;
_parent = tv->current_pool;
if (_parent)
_parent->_child = self;
{
NSAutoreleasePool *pool = _parent;
while (nil != pool)
{
level++;
pool = pool->_parent;
}
_parent->_child = self;
}
tv->current_pool = self;
if (level > pool_number_warning_threshhold)
{
[NSException raise: NSGenericException
format: @"Too many (%u) autorelease pools ... leaking them?", level];
}
}
return self;
@ -504,14 +528,32 @@ pop_pool_from_cache (struct autorelease_thread_vars *tv)
{
volatile struct autorelease_array_list *released;
/* If there are NSAutoreleasePool below us in the stack of
NSAutoreleasePools, then deallocate them also. The (only) way we
could get in this situation (in correctly written programs, that
don't release NSAutoreleasePools in weird ways), is if an
exception threw us up the stack. */
while (_child != nil)
/* If there are NSAutoreleasePool below us in the list of
* NSAutoreleasePools, then deallocate them also.
* The (only) way we could get in this situation (in correctly
* written programs, that don't release NSAutoreleasePools in
* weird ways), is if an exception threw us up the stack.
* However, if a program has leaked pools we may be deallocating
* a pool with LOTS of children. To avoid stack overflow we
* therefore deallocate children starting with the oldest first.
*/
if (nil != _child)
{
[_child dealloc];
NSAutoreleasePool *pool = _child;
/* Find other end of linked list ... oldest child.
*/
while (nil != pool->_child)
{
pool = pool->_child;
}
/* Deallocate the children in the list.
*/
while (pool != self)
{
pool = pool->_parent;
[pool->_child dealloc];
}
}
/* Take the object out of the released list just before releasing it,
@ -634,5 +676,10 @@ pop_pool_from_cache (struct autorelease_thread_vars *tv)
pool_count_warning_threshhold = c;
}
+ (void) setPoolNumberThreshhold: (unsigned)c
{
pool_number_warning_threshhold = c;
}
@end
#endif