Hello, fellow cocoa devs.

I'm running down the most common crasher we're seeing in OmniPlan-2.0 under 
Lion and running onto some grief with NSSpellChecker/NSTextView.  We have a 
fairly complex outline view that is backed by many text storages and the field 
editor is asked to do a lot. When editing a row, we create a text storage for 
that row's contents, then insert a field editor into the view hierarchy and 
call -replaceTextStorage: on its layout manager with our freshly-minted text 
storage.

If I enable “Correct Spelling Automatically”, create a new task and title it 
"Hello htere" [sic], spell checking is performed asynchronously on the main 
thread and the NSSpellChecker shows a correctionIndicator

#0  0x00007fff8c295a5b in -[NSSpellChecker 
showCorrectionIndicatorOfType:primaryString:alternativeStrings:forStringInRect:view:completionHandler:]
 ()
#1  0x00007fff8bf12cef in -[NSTextView 
handleTextCheckingResults:forRange:types:options:orthography:wordCount:] ()
#2  0x00007fff8bf11565 in -[NSTextView 
_handleTextCheckingResults:sequenceNumber:forRange:types:options:orthography:wordCount:applyNow:]
 ()
#3  0x00007fff8bf113e6 in __-[NSTextView 
checkTextInRange:types:options:]_block_invoke_2 ()
#4  0x00007fff896a6ecc in __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ ()
#5  0x00007fff8965efa2 in __CFRunLoopDoBlocks ()
#6  0x00007fff89686f07 in __CFRunLoopRun ()
…

If I hit return, the default correction is selected and I infer that the 
completionHandler is enqueued on the main queue. However, our custom 
implementation of -insertNewline: will also end editing on the current row, 
create a new item with another text storage behind it, and tell the field 
editor's layout manager to replaceTextStorage: with that new row's text 
storage. After we return to the run loop, an NSPortMessage happens to be 
received by another object, and that object calls [NSApp 
nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] 
inMode:NSEventTrackingRunLoopMode dequeue:NO], which will again fire the run 
loop. This causes the the main queue to fire its pending blocks, and thus the 
NSTextView's text checking handler's completionHandler is run and raises an 
exception: 

#13 0x00007fff896f1ab4 in +[NSException raise:format:] ()
#14 0x00007fff896af87e in -[__NSCFString characterAtIndex:] ()
#15 0x00007fff8bf17e76 in -[NSAttributedString(NSAttributedStringKitAdditions) 
doubleClickAtIndex:inRange:] ()
#16 0x00007fff8bf17de7 in -[NSAttributedString(NSAttributedStringKitAdditions) 
doubleClickAtIndex:] ()
#17 0x00007fff8bf17da4 in -[NSTextView _doubleClickAtIndex:limitedRangeOK:] ()
#18 0x00007fff8c304d61 in __-[NSTextView 
handleTextCheckingResults:forRange:types:options:orthography:wordCount:]_block_invoke_2
 ()
#19 0x00007fff8dbdf90a in _dispatch_call_block_and_release ()
#20 0x00007fff8dbe177a in _dispatch_main_queue_callback_4CF ()
#21 0x00007fff89686ddc in __CFRunLoopRun ()
#22 0x00007fff896863e6 in CFRunLoopRunSpecific ()
#23 0x00007fff90e5c697 in RunCurrentEventLoopInMode ()
#24 0x00007fff90e63db9 in ReceiveNextEventCommon ()
#25 0x00007fff90e63c46 in BlockUntilNextEventMatchingListInMode ()
#26 0x00007fff8bd2baf5 in _DPSNextEvent ()
#27 0x00007fff8bd2b3fc in -[NSApplication 
nextEventMatchingMask:untilDate:inMode:dequeue:] ()
…

Here, this problem occurs because the field editor's new NSTextStorage is 
shorter now (having a default task title of something like “Task 2”). The 
completion handler appears to be hanging on to the range of the 
NSTextCheckingResult it's handling, (NSRange){6, 5}. The exception we get is:

---------------------------
Mask: 0x00000001
Name: NSRangeException
Reason: -[__NSCFString characterAtIndex:]: Range or index out of bounds
Info:

Because we regard an unhandled exception in a place like this as a potential 
data corruptor, we immediately crash on purpose and hope the user will send in 
a crash report with a backtrace to the scene of the crime.

It just looks to me like it's unsafe to change the text storage backing the 
field editor unless you can be sure that there are no text checking completion 
blocks hanging around on the main dispatch queue. I don't believe there's any 
API or trick to get the spell checker to wrap up its text checking now, 
synchronously. Subclassing [NSTextView 
handleTextCheckingResults:forRange:types:options:orthography:wordCount:] in our 
field editor would be pretty onerous; it's a very complicated method.

Your thoughts would be very welcome.  I'm happy to provide more information of 
course, but I've got over half a million lines of .m files here and I'm trying 
to narrow the scope of the problem suitably. Kyle is currently across the hall 
striving to reproduce this problem in a smaller, Radar-compatible sample 
project.

Thanks!

-Tom_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to