Re: Exception not being caught in try statement


Mark Allan
 

Hi all,

Thanks to everyone for their suggestions. I spent far too much time working around this bug, but have finally got to the bottom of the original issue.

It turns out this is a known issue with some other apps as well, and (thanks to https://trac.cyberduck.io/ticket/11231#comment:25 ) can be fixed by removing an obscure preference key from the User Defaults system.

I was able to reproduce the issue by setting the __NSDisableSharingTextTabInstance key to YES using the "defaults write" command.

I've solved it by removing that key in my -applicationDidFinishLaunching method:
[[NSUserDefaults standardUserDefaults] removeObjectForKey: @"__NSDisableSharingTextTabInstance"];

Looks like someone has already submitted a bug report to Apple for it (https://openradar.appspot.com/FB8930278 ) so I'm just posting this here in case it helps anyone else in the future.

Best regards,
Mark 

On 29 Mar 2021, at 7:01 pm, Martin Wierschin via Cocoa-dev <cocoa-dev@...> wrote:

Breaking the RTFD loading process down into subtasks is a good idea. It might be worth trying to sidestep the issue using NSAttributedString. You can try loading the data yourself as Mike suggested and then use initWithRTFD or initWithRTFDFileWrapper. Once you have the text in an attributed string you can swap its content into your NSTextView/NSTextStorage using -replaceCharactersInRange:withAttributedString:

However, I suspect the problem will remain. The exception is coming from Apple's internal NSRTFReader class, which we can be reasonably certain is utilized by all RTF/RTFD loading code paths. To really fix this you're probably going to be stuck with ugly code that either:

1. Preprocess the RTFD to remove the data that Apple's code can't handle, eg: strip tab stops as someone else suggested.
2. Use method swizzling to patch Apple's buggy methods at runtime, eg: replace -[NSRTFReader defaultParagraphStyle] to avert the conditions that lead to the exception, before it gets thrown in the first place.

One other potential debugging aid: NSExceptionHandler. You can register your own handler, perhaps in a way that prevents AppKit from killing your app outright when an exception occurs (this used to be possible but I don't know the current behavior). But as Mike said, this isn't a real solution for shipping software. Generally speaking once an app has thrown an exception its state can't be relied upon. So you should only use this for testing to gather additional debug information.

~Martin Wierschin

On Mar 26, 2021, at 11:22 AM, Mike Abdullah via Cocoa-dev <cocoa-dev@...> wrote:

This does seem quite surprising. However, here’s the thing: this code is very strange approach to take.

Number 1: Cocoa doesn’t support exceptions as an error-handling mechanism except where explicitly stated and supported. You’re trying to use them, which is asking for trouble. The system doesn’t guarantee proper handling of memory if an exception does throw.

Number 2: Your error handling approach is back-to-front. You’re trying an operation, seeing if it fails, then attempting to guess from the current state (which might have changed in the meantime) why it might have failed.

Instead, use the proper error APIs and approach:

1. Load the data from disk, e.g. +[NSData dataWithContentsOfURL:options:error:]

If that fails you can introspect the error to your heart’s content to find out what went wrong

2. Load the data into your text view. I’m not sure if there’s an API to do that in a single step or not, dunno.

I also note that your code explicitly is trying to read an RTFD which if memory serves can be a document *bundle* format, so perhaps at step 1 you’d have to go with a file wrapper. But the path you specify is .rtf so I’m guessing you really do have a basic file and can load it as data.

Mike.

On 26 Mar 2021, at 11:11, Mark Allan via Cocoa-dev <cocoa-dev@...> wrote:

Hi folks,

Some users are reporting a crash that I can't reproduce, and in an attempt to gain additional diagnostics from a user, I wrapped the affected line in a try/catch block.  For two users it resolve the crash, but for a third, it's still crashing at the same point!

The crash occurs when a user attempts to open the "About" window from my app's main menu item. I'm not using the standard about panel as there's a few additional items I need to display, one of which is an NSTextView which I populate with the contents of an RTF file from within the app bundle.

I've symbolicated the crash log to find it's happening when populating that TextView. The line in question now reads as follows:

@try {
[self.aboutBox.creditsTextView readRTFDFromFile:[[NSBundle mainBundle] pathForResource:@"Credits" ofType:@"rtf"]];
} @catch (NSException *exception) {
NSLog(@"Error loading the contents of the text file for the About Box. %@", exception);
//Check we have a file at the expected path
if([[NSFileManager defaultManager] fileExistsAtPath:[[NSBundle mainBundle] pathForResource:@"Credits" ofType:@"rtf"]]){
NSLog(@"Yes. Found the RTF credits file");
// check the attributes in case somehow there's no permission to read the file
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[[NSBundle mainBundle] pathForResource:@"Credits" ofType:@"rtf"] error:nil];
NSLog(@"RTF file has following attributes %@", fileAttributes);
}
else {
NSLog(@"Nope, file not found");
}
}

This is the crash log from the newest build (with the try/catch around that line):

Performing @selector(showAboutBox:) from sender NSMenuItem 0x600000634540
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
terminating with uncaught exception of type NSException
abort() called

Application Specific Backtrace 1:
0   CoreFoundation                      0x00007fff206ea6af __exceptionPreprocess + 242
1   libobjc.A.dylib                     0x00007fff204223c9 objc_exception_throw + 48
2   CoreFoundation                      0x00007fff2079ea9a -[__NSCFString characterAtIndex:].cold.1 + 0
3   CoreFoundation                      0x00007fff2079c953 -[__NSArrayM insertObject:atIndex:].cold.2 + 0
4   CoreFoundation                      0x00007fff20610421 -[__NSArrayM insertObject:atIndex:] + 1135
5   UIFoundation                        0x00007fff23c223ab __defaultTabStops_block_invoke + 161
6   libdispatch.dylib                   0x00007fff203cd7c7 _dispatch_client_callout + 8
7   libdispatch.dylib                   0x00007fff203ce96b _dispatch_once_callout + 20
8   UIFoundation                        0x00007fff23c229d7 -[NSMutableParagraphStyle setTabStops:] + 199
9   UIFoundation                        0x00007fff23c3c697 -[NSRTFReader defaultParagraphStyle] + 75
10  UIFoundation                        0x00007fff23c3c5be -[NSRTFReader _mutableParagraphStyle] + 112
11  UIFoundation                        0x00007fff23c36113 controlClass + 1757
12  UIFoundation                        0x00007fff23c356b4 -[NSRTFReader attributedString] + 76
13  UIFoundation                        0x00007fff23c311a6 _NSReadAttributedStringFromURLOrData + 3213
14  UIFoundation                        0x00007fff23d46985 -[NSAttributedString(NSAttributedStringUIFoundationAdditions) initWithURL:options:documentAttributes:error:] + 228
15  AppKit                              0x00007fff23677d9a -[NSTextView readRTFDFromFile:] + 126
16  MyAppHere                             0x0000000105fa18a7 MyAppHere+ 227495
17  AppKit                              0x00007fff230af7fd -[NSApplication(NSResponder) sendAction:to:from:] + 283
18  AppKit                              0x00007fff231b2611 -[NSMenuItem _corePerformAction] + 413


Any ideas what's going on? Other than the file not being found, why else might the object at line 3 in the backtrace be nil...and more interestingly, why is the exception not being caught?

Thanks
Mark

Join cocoa@apple-dev.groups.io to automatically receive all group messages.