Serious crash from setNeedsDisplayInRect:
Serious crash from setNeedsDisplayInRect:
- Subject: Serious crash from setNeedsDisplayInRect:
- From: Benjohn <email@hidden>
- Date: Wed, 9 Feb 2005 11:27:26 +0000
Dear list,
Our application is crashing. I've built a small test case to recreate
our application's behaviour, and this appears to crash in the same way.
In summary, there seems to be a serious bug with
setNeedsDisplayInRect:.
The test project is very simple, it's an NSView subclass that launches
one worker threads to draw in to itself. I have placed the view's
implementation at the bottom of this mail, along with GDB's stacks for
the main thread and worker thread, and log output from the program
running. I'd be delighted to mail an archive of the project to anyone
who would like a look (I'll be putting it on to Apple's bug tracker in
a few minutes).
A few points:
* I've put logging in to the view's dealloc call. This seems to get
called for no reason I can see when the view is still visible.
Presumably this is "not a good thing", and leads to the BAD ACCESS that
happens. Why the view would be deallocated, I don't know. I can only
presume that it's being caused by the framework.
* If "performSelectorOnMainThread:withObject:waitUntilDone:" is called
with "waitUntilDone: YES", then the crash does not happen.
* The real application seems to crash sooner on G5 dual processor
machines than on G4 dual processor machines. We've not seen the crash
on single processor machines, but haven't tried hard to replicate it on
such systems.
* Sometimes the test project and real app will be stable for a while
(tens of minutes under various provocations). Sometimes they fall over
almost immediately.
Unless there's something stupid I'm doing (which would be great), is
there something wrong with Apple's framework? We think that we may be
able to replace our "performSelectorOnMainThread:..." call with one
that uses "waitUntilDone: YES". I would welcome other workaround
suggestions.
The other obvious workaround is to simply call "setNeedsDisplayInRect:"
from the worker thread, and this does not crash the test project (so
far...). However, we originally used this approach, but found that some
rects were being ignored. We found that calling "displayRect:" directly
from workers did not loose rects, but did cause crashes. In our current
code, the workers ask the main thread to call "displayRect:", but as
found here, this causes intermittent crashes.
Thanks for any help,
Cheers,
Benjohn
Console Log [Note the view deallocation near bottom that shouldn't
happen].
[Session started at 2005-02-09 11:05:57 +0000.]
GNU gdb 5.3-20030128 (Apple version gdb-330.1) (Fri Jul 16 21:42:28
GMT 2004)
Loading program into debugger…
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and
you are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details.
This GDB was configured as "powerpc-apple-darwin".
tty /dev/ttyp1
Program loaded.
run
[Switching to process 3229 local thread 0xd03]
Running…
2005-02-09 11:06:08.916 ThreadedPaintTest[3229] View has been
deallocated.
Program received signal: "EXC_BAD_ACCESS".
(gdb)
Thread 1 (main thread)
#0 0x908311f4 in objc_msgSend
#1 0x9019f18c in CFArrayApplyFunction
#2 0x92dc57ac in -[NSView _propagateDirtyRectsToOpaqueAncestors]
#3 0x9019f18c in CFArrayApplyFunction
#4 0x92dc57ac in -[NSView _propagateDirtyRectsToOpaqueAncestors]
#5 0x92dee21c in -[NSView displayIfNeeded]
#6 0x92dfef4c in -[NSWindow displayIfNeeded]
#7 0x92ddf5ac in -[NSImage
compositeToPoint:fromRect:operation:fraction:]
#8 0x90191ca0 in __CFRunLoopDoObservers
#9 0x9019153c in __CFRunLoopRun
#10 0x90195e8c in CFRunLoopRunSpecific
#11 0x927d5f60 in GetWindowList
#12 0x927dc6c8 in GetMainEventQueue
#13 0x927fe6a0 in BlockUntilNextEventMatchingListInMode
#14 0x92dd2e44 in _DPSNextEvent
#15 0x92de98c8 in -[NSApplication
nextEventMatchingMask:untilDate:inMode:dequeue:]
#16 0x92dfdc30 in -[NSApplication run]
#17 0x92eba2b8 in NSApplicationMain
#18 0x000e0f74 in main at main.m:13
Thread 2 (worker thread)
#0 0x90012568 in syscall_thread_switch
#1 0x90a029c8 in +[NSThread sleepUntilDate:]
#2 0x002ee64c in -[FLThreadedRepaintView forcePaintLoop] at
FLThreadedRepaintView.mm:43
#3 0x90a39b74 in forkThreadForFunction
#4 0x900246e8 in _pthread_body
// FLThreadedRepaintView.mm
#import "FLThreadedRepaintView.h"
@implementation FLThreadedRepaintView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self setBounds: NSMakeRect(0.0f, 0.0f, 1.0f, 1.0f)];
// Start a worker thread on me.
[NSThread detachNewThreadSelector: @selector(forcePaintLoop)
toTarget: self withObject: nil];
}
return self;
}
- (void) dealloc
{
NSLog(@"View has been deallocated.");
[super dealloc];
}
#pragma mark -
- (void) forcePaintLoop
{
while( true )
{
NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init];
[self forcePaints];
[NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow:
NormalisedRandom() * 0.1f]];
[autoreleasePool release];
}
}
- (void) forcePaints
{
for( int i=0; i<6; i++ )
{
[self performSelectorOnMainThread:
@selector(forceDisplayOfRandomRect) withObject: nil waitUntilDone: NO];
}
}
- (void) forceDisplayOfRandomRect
{
[self setNeedsDisplayInRect: RandomRect()];
}
#pragma mark -
- (void)drawRect:(NSRect)rect
{
// Drawing code here.
[RandomColour() set];
[NSBezierPath fillRect: rect];
}
@end
NSRect RandomRect()
{
const float x = 0.2f + 0.6f * NormalisedRandom();
const float y = 0.2f + 0.6f * NormalisedRandom();
return NSMakeRect( x-0.1f, y-0.1f, 0.1f, 0.1f );
}
NSColor *RandomColour()
{
return [NSColor colorWithCalibratedRed: NormalisedRandom() green:
NormalisedRandom() blue: NormalisedRandom() alpha: 1.0f];
}
float NormalisedRandom()
{
return float(rand() % 1000) / float(1000.0);
}
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden