Crasher due to unsafe block implementation in -[NSTextView checkTextInRange:types:options:]?
Crasher due to unsafe block implementation in -[NSTextView checkTextInRange:types:options:]?
- Subject: Crasher due to unsafe block implementation in -[NSTextView checkTextInRange:types:options:]?
- From: Thomas Bunch <email@hidden>
- Date: Tue, 02 Aug 2011 17:36:41 -0700
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 (email@hidden)
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:
This email sent to email@hidden