NSarray crashes with different exceptions from the same place

It seems that that all the crashes are coming from the same place BUT the error is slightly different. Attaching the code that responsible for the crash:

static NSString * const kDelimiter = @"#$@";
+ (PNDArray *)getObjectsFromData:(NSData *)data {
    NSString *dataStr = [[NSString alloc] initWithData:data encoding:encoding];
    dataStr = [dataStr stringByReplacingOccurrencesOfString:@"\\u0000" withString:@""];
    NSArray *components = [dataStr componentsSeparatedByString:kDelimiter];
    NSMutableArray *result = [NSMutableArray array];
    
    for (NSString *jsonStr in components) {
        if (jsonStr != nil && jsonStr.length != 0 && ![jsonStr hasPrefix:kBatchUUID]) {
            [result addObject:jsonStr];
        }
    }
    
    return [PNDArray arrayWithArray:result];
}

I can't make out anything from the crash reports, but this line smells:

NSMutableArray *result = [NSMutableArray array];

Isn't it supposed to be something like this?

NSMutableArray *result = [[NSMutableArray alloc] init];

I looked at your last crash report. It has this:

Exception Type:  EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x0000000193717ae0

EXC_BREAKPOINT usually means that the app trapped, that is, it detected a failure and deliberately crashed. Looking at the backtrace I see this:

Thread 13 name:
Thread 13 Crashed:
0   CoreFoundation          … -[__NSArrayM insertObject:atIndex:].cold.2 + 16 (NSArrayM.m:254)
1   CoreFoundation          … -[__NSArrayM insertObject:atIndex:] + 988 (NSArrayM_Common.h:254)
2   Foundation              … -[NSString componentsSeparatedByString:] + 160 (NSString.m:599)
3   Pendo                   … +[PNDDiskBufferHelper getObjectsFromData:] + 144
4   Pendo                   … -[PNDDiskBuffer prepareObjectsForProcessing] + 72
5   Pendo                   … __44-[PNDAnalyticsMessageManager sendAnalytics:]_block_invoke_2 + 36
6   libdispatch.dylib       … _dispatch_client_callout + 20 (object.m:560)
7   libdispatch.dylib       … _dispatch_continuation_pop + 504 (inline_internal.h:2632)
8   libdispatch.dylib       … _dispatch_source_invoke + 1588 (source.c:596)
9   libdispatch.dylib       … _dispatch_lane_serial_drain + 376 (inline_internal.h:0)
10  libdispatch.dylib       … _dispatch_lane_invoke + 384 (queue.c:3940)
11  libdispatch.dylib       … _dispatch_workloop_worker_thread + 652 (queue.c:6846)
12  libsystem_pthread.dylib … _pthread_wqthread + 288 (pthread.c:2618)
13  libsystem_pthread.dylib … start_wqthread + 8 (:-1)

Note how the crash is within -componentsSeparatedByString:. Looking at your code, there are only two parameters to that:

  • kDelimiter, which is a constant (-:

  • dataStr, which is created from the data

You’re not checking the result from -initWithData:encoding:, so dataStr could be nil. However, if it were nil you wouldn’t see this crash because messaging nil is a no-op in Objective-C.

Thus, it’s unlikely that this is caused by the parameters you’re passing to -componentsSeparatedByString:, which suggests that there’s some sort of memory management problem triggering it. For advice on how to investigate those, see Standard Memory Debugging Tools.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@DTS Engineer Just to clarify:

  1. This code is part of our SDK and the SDK is running in hosting app.
  2. We already have tried all possible Instruments and didn't see any clue to the problem, please suggest if you have any specific configuration u want us to try
  3. The crash happens only for that customer
  4. We have submitted a TSI (in addition to current TSI) a year a go and nothing really came out of it

Currently we need a solution. I know that's kinda a crash that hard to see (that's why we applied for your help). We attached several crashes with different exception type to provide better picture. With that to say, is there some proper way to recover from those kind of crashes. like try/catch for signals?

@DTS Engineer Any additional info u can provide

This code is part of our SDK and the SDK is running in hosting app.

The crash happens only for that customer

So, lemme see if I have this straight:

  • You build an SDK.

  • That SDK is used by a number of other third-party apps.

  • Only one of those apps see this problem.

Is that right?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hi,

Thanks for your help.

  1. Yes

  2. Yes

  3. Currently one client reported about the issue (I tend to believe there might be more clients with the same issue)

wanted to point out that I managed to reproduce the following crash on the client app: Thread 182: EXC_RESOURCE (RESOURCE_TYPE_MEMORY: high watermark memory limit exceeded) (limit=1450 MB) . That happens when the data is to big , it should not happen and we will fix it BUT no guarantee it will solve their issue

The EXC_RESOURCE crash is almost certainly a different thing. Indeed, it may not be a crash at all (-:

Coming back to your main issue, when you wrote:

We already have tried all possible Instruments and didn't see any clue to the problem

were you running these tests again the client’s app? Or your own app that exercises your SDK?

Also, not all the standard memory debugging tools are Instruments based. Some of them, like ASan, require recompiling your code. This can be tricky with in your situation. Unless you have the source code for the client’s app, you’d have to ask them to run the tests for you.

This is actually a good idea anyway, because it’s absolutely possible that this isn’t a bug in your code but a problem in the client’s app that just happens to trigger the crash here.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@DTS Engineer So initially we tried in our sample apps but that it didnt yield any result.

So I took client compiled app, compiled the SDK with Sanitizers and injected it to the client app. (I have linked the ASAN libs to prevent crashes when the app cant find those libs SDK refers to) . I tried mainly the Address Sanitizer tool (it seems like the most appropriate)

@DTS Engineer

Why the stack trace of componentsSeparatedByString: is different between crashes? (different OS?)

@DTS Engineer

What do you think if we rewrite apple componentsSeparatedByString with our own implementation something like that: https://gist.github.com/MikePendo/ef4eb4cfd03adfbf07dd040a1d538089 Maybe it will point out to exact place of the crash?

Why the stack trace of -componentsSeparatedByString: is different between crashes?

Because things are failing in different ways. Let’s look at the backtraces of your five crashes in order.


Thread 13 name:
Thread 13 Crashed:
0   libobjc.A.dylib … cache_t::insert(objc_selector*, void (*)(), objc_object*) + 244 (objc-cache.mm:901)
1   libobjc.A.dylib … lookUpImpOrForward + 664 (objc-runtime-new.mm:7435)
2   libobjc.A.dylib … _objc_msgSend_uncached + 68 (:-1)
3   CoreFoundation  … __exceptionPreprocess + 124 (NSException.m:241)
4   libobjc.A.dylib … objc_exception_throw + 60 (objc-exception.mm:356)
5   CoreFoundation  … -[__NSArrayM insertObject:atIndex:] + 1292 (NSArrayM.m:164)
6   Foundation      … -[NSString componentsSeparatedByString:] + 160 (NSString.m:623)
7   Pendo           … +[PNDDiskBufferHelper getObjectsFromData:] + 144

In this crash NSArray has detected a problem and is trying to throw a language exception. That’s got halfway through the process before crashing in the Objective-C runtime due to a memory corruption issue.


Thread 13 name:
Thread 13 Crashed:
0   CoreFoundation  … -[__NSArrayM insertObject:atIndex:].cold.1 + 16 (NSArrayM.m:168)
1   CoreFoundation  … -[__NSArrayM insertObject:atIndex:] + 1680 (NSArrayM.m:168)
2   Foundation      … -[NSString componentsSeparatedByString:] + 160 (NSString.m:623)
3   Pendo           … +[PNDDiskBufferHelper getObjectsFromData:] + 144

In this crash NSArray has detected a problem and trapped. It’s hard to say exactly what’s causing this due to inlining but, if I had to guess, it’s because the index is out of bounds.


Last Exception Backtrace:
0   CoreFoundation  … __exceptionPreprocess + 164 (NSException.m:202)
1   libobjc.A.dylib … objc_exception_throw + 60 (objc-exception.mm:356)
2   CoreFoundation  … _CFThrowFormattedException + 108 (CFObject.m:2235)
3   CoreFoundation  … -[__NSArrayM insertObject:atIndex:].cold.1 + 52 (NSArrayM.m:164)
4   CoreFoundation  … -[__NSArrayM insertObject:atIndex:] + 908 (NSArrayM.m:164)
5   Foundation      … -[NSString componentsSeparatedByString:] + 160 (NSString.m:599)

In this crash NSArray has successfully managed to throw the exception. I’m fairly confident that the exception is complaining that the object being inserted is nil.


Thread 15 name:
Thread 15 Crashed:
0   libobjc.A.dylib … cache_t::insert(objc_selector*, void (*)(), objc_object*) + 244 (objc-cache.mm:934)
1   libobjc.A.dylib … lookUpImpOrForward + 664 (objc-runtime-new.mm:7503)
2   libobjc.A.dylib … _objc_msgSend_uncached + 68 (:-1)
3   CoreFoundation  … -[__NSArrayM insertObject:atIndex:] + 1288 (NSArrayM.m:164)
4   Foundation      … -[NSString componentsSeparatedByString:] + 160 (NSString.m:622)
5   Pendo           … +[PNDDiskBufferHelper getObjectsFromData:] + 144

This is very similar to crash 1, albeit with a slightly different backtrace probably due to a different object being corrupted.


Thread 13 name:
Thread 13 Crashed:
0   CoreFoundation  … -[__NSArrayM insertObject:atIndex:].cold.2 + 16 (NSArrayM.m:254)
1   CoreFoundation  … -[__NSArrayM insertObject:atIndex:] + 988 (NSArrayM_Common.h:254)
2   Foundation      … -[NSString componentsSeparatedByString:] + 160 (NSString.m:599)
3   Pendo           … +[PNDDiskBufferHelper getObjectsFromData:] + 144

The backtrace here is a bit weird because of inlining, but I believe that the crash is because some core code within NSArray was unable to allocate memory for the array. That is, malloc failed. Either your process has run out of address space, or the heap is corrupted. Given the other crashes, I suspect it’s the latter.


What do you think if we rewrite apple -componentsSeparatedByString: with our own implementation

I think you’ll start getting similar crash reports from your own code. Unless you think that -componentsSeparatedByString: itself is corrupting memory — which seems unlikely because it’s pretty darned battle hardened — the root cause of this problem is some other memory corruption issue, and changing out this implementation won’t affect that.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@DTS Engineer

ok so In the case of index out of bounds OR nil insertion. Try/Catch should prevent the crash, right?.

So maybe we should (at least reduce number of crashes). What do you think about that approach?

Try/Catch should prevent the crash, right?.

Probably not. It’ll just shuffle the crash to somewhere else. For -componentsSeparatedByString: to crash like this, something is badly corrupted. You might be able to mask this problem with a trycatch, but another problem will inevitably crop up elsewhere.

Also, in general, it’s not safe to try to recover from language exceptions in Objective-C. I go into this in more detail in What is an exception?.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@DTS Engineer

I had a long call with that client and it seems that most of those crashes were caused by out of memory issue (indicated by instabug).

Is it possible to see that information from apple crash logs?

(how much memory were used by the app, how much disk is used etc )

Is it possible to see that information from apple crash logs?

No.

Out of memory is a pretty unusual error, even on iOS. You only get it you run out of address space, and in most cases you’ll run out of physical memory (either on the device as a whole, or in the budget allocated to your app) before you run out address space.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

NSarray crashes with different exceptions from the same place
 
 
Q