Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mysterious Crash (NSAttributedString, iOS 7)

In my app I have a homegrown version of UICollectionView (I wrote it before UICollectionView existed, and it seems to be more performant than UICollectionView for my use case). It consists of several tiles in a scrollview.

To aid in scrolling performance, and because each tile consists of around a dozen PNGs on top of each other, each tile is pre-rendered to an NSCache using NSOperations and an NSOperationQueue. Without this optimisation, scrolling performance is terrible.

As well as several PNGs, each tile has (or may have) a couple of pieces of text.

Each NSOperation, to avoid causing problems doing any kind of rendering on a background thread (which of course, is a UIKit no-no), uses CoreGraphics and NSAttributedStrings to render the image.

This brings me to the crash. The crash (below) seems to relate to NSAttributedString rendering. As this NSOperationQueue full of tile render operations is the only place in my app that uses NSAttributedStrings, and gets called a lot, I have to assume it's the culprit. We see the crash occurring reasonably often in our crash reporting, but not often enough that we have a hope of reliably reproducing it in-house (our app has a pretty massive userbase).

Fascinatingly, the crash only occurs on iOS 7. Anyone have any ideas? Here's an example of a crash:

Incident Identifier: 3BE1FF37-4288-40A9-954D-1AD909987D05
CrashReporter Key:   000339CB-9B5B-46EE-B256-4D911B190E7D
Hardware Model:      iPhone5,2
Process:         AppName [733]
Path:            /Users/USER/AppName.app/AppName
Identifier:      com.companyname.appname
Version:         2.0.1
Code Type:       ARM
Parent Process:  launchd [1]

Date/Time:       2013-10-03 23:32:20 +0000
OS Version:      iPhone OS 7.0.2 (11A501)
Report Version:  104

Exception Type:  SIGBUS
Exception Codes: BUS_ADRALN at 0x100078c
Crashed Thread:  0

Thread 0 Crashed:
0   ???                                  0x0100078c 0x0 + 0
1   UIFoundation                         0x36fbf027 -[NSLayoutManager _drawLineForGlyphRange:type:baselineOffset:lineFragmentRect:lineFragmentGlyphRange:containerOrigin:isStrikethrough:] + 3358
2   UIFoundation                         0x36ffdd1f -[NSLayoutManager drawUnderlineForGlyphRange:underlineType:baselineOffset:lineFragmentRect:lineFragmentGlyphRange:containerOrigin:] + 86
3   UIFoundation                         0x36fc024d -[NSLayoutManager _lineGlyphRange:type:lineFragmentRect:lineFragmentGlyphRange:containerOrigin:isStrikethrough:] + 1184
4   UIFoundation                         0x36ffde2f -[NSLayoutManager underlineGlyphRange:underlineType:lineFragmentRect:lineFragmentGlyphRange:containerOrigin:] + 78
5   UIFoundation                         0x36fd43bf -[NSLayoutManager _drawGlyphsForGlyphRange:atPoint:] + 5734
6   UIFoundation                         0x36ffdbf7 -[NSLayoutManager drawGlyphsForGlyphRange:atPoint:] + 38
7   UIFoundation                         0x37013f01 -[NSStringDrawingTextStorage drawTextContainer:withRect:graphicsContext:baselineMode:scrollable:padding:] + 968
8   UIFoundation                         0x3700e5bd __NSStringDrawingEngine + 10293
9   UIFoundation                         0x3701172d -[NSAttributedString(NSExtendedStringDrawing) drawWithRect:options:context:] + 525
10  UIKit                                0x31ed9f5d -[UILabel _drawTextInRect:baselineCalculationOnly:] + 3436
11  UIKit                                0x31f419e7 -[UILabel drawTextInRect:] + 558
12  UIKit                                0x31f417af -[UILabel drawRect:] + 78
13  UIKit                                0x31f41749 -[UIView drawLayer:inContext:] + 372
14  QuartzCore                           0x31b78049 -[CALayer drawInContext:] + 100
15  QuartzCore                           0x31b61813 CABackingStoreUpdate_ + 1859
16  QuartzCore                           0x31c3b735 ___ZN2CA5Layer8display_Ev_block_invoke + 53
17  QuartzCore                           0x31b610c3 x_blame_allocations + 83
18  QuartzCore                           0x31b60d77 CA::Layer::display_() + 1119
19  QuartzCore                           0x31b44969 CA::Layer::display_if_needed(CA::Transaction*) + 209
20  QuartzCore                           0x31b44601 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 25
21  QuartzCore                           0x31b4400d CA::Context::commit_transaction(CA::Transaction*) + 229
22  QuartzCore                           0x31b43e1f CA::Transaction::commit() + 315
23  QuartzCore                           0x31b3db4d CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 57
24  CoreFoundation                       0x2f706f71 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 21
25  CoreFoundation                       0x2f7048ff __CFRunLoopDoObservers + 287
26  CoreFoundation                       0x2f704c4b __CFRunLoopRun + 739
27  CoreFoundation                       0x2f66f541 CFRunLoopRunSpecific + 524
28  CoreFoundation                       0x2f66f323 CFRunLoopRunInMode + 106
29  GraphicsServices                     0x343a62eb GSEventRunModal + 138
30  UIKit                                0x31f261e5 UIApplicationMain + 1136
31  My App                               0x0002cc37 main (main.m:18)
32  libdyld.dylib                        0x39f2fab7 start + 3

Thread 1:
0   libsystem_kernel.dylib               0x39fd3838 kevent64 + 24
1   libdispatch.dylib                    0x39f1c643 _dispatch_mgr_thread + 39

Thread 2:
0   libsystem_kernel.dylib               0x39fd3a84 mach_msg_trap + 20
1   CoreFoundation                       0x2f706561 __CFRunLoopServiceMachPort + 157
2   CoreFoundation                       0x2f704c81 __CFRunLoopRun + 793
3   CoreFoundation                       0x2f66f541 CFRunLoopRunSpecific + 524
4   CoreFoundation                       0x2f66f323 CFRunLoopRunInMode + 106
5   Foundation                           0x3005d827 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 255
6   Foundation                           0x300ae669 -[NSRunLoop(NSRunLoop) run] + 81
7   My App                          0x0003900f -[EndpointOperation start] (EndpointOperation.m:268)
8   Foundation                           0x3010eafd __NSOQSchedule_f + 61
9   libdispatch.dylib                    0x39f1f4bf _dispatch_async_redirect_invoke + 111
10  libdispatch.dylib                    0x39f207e5 _dispatch_root_queue_drain + 225
11  libdispatch.dylib                    0x39f209d1 _dispatch_worker_thread2 + 57
12  libsystem_pthread.dylib              0x3a04adff _pthread_wqthread + 298
13  libsystem_pthread.dylib              0x3a04acc4 start_wqthread + 8

Thread 3:
0   libsystem_kernel.dylib               0x39fd3a84 mach_msg_trap + 20
1   CoreFoundation                       0x2f706561 __CFRunLoopServiceMachPort + 157
2   CoreFoundation                       0x2f704c81 __CFRunLoopRun + 793
3   CoreFoundation                       0x2f66f541 CFRunLoopRunSpecific + 524
4   CoreFoundation                       0x2f66f323 CFRunLoopRunInMode + 106
5   Foundation                           0x300aa651 +[NSURLConnection _resourceLoadLoop:] + 320
6   Foundation                           0x3011fdc7 __NSThread__main__ + 1063
7   libsystem_pthread.dylib              0x3a04cc5d _pthread_body + 141
8   libsystem_pthread.dylib              0x3a04cbcf _pthread_start + 102
9   libsystem_pthread.dylib              0x3a04acd0 thread_start + 8

Thread 4:
0   libsystem_kernel.dylib               0x39fd3a84 mach_msg_trap + 20
1   CoreFoundation                       0x2f706561 __CFRunLoopServiceMachPort + 157
2   CoreFoundation                       0x2f704c81 __CFRunLoopRun + 793
3   CoreFoundation                       0x2f66f541 CFRunLoopRunSpecific + 524
4   CoreFoundation                       0x2f66f323 CFRunLoopRunInMode + 106
5   Foundation                           0x3005d827 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 255
6   My App                          0x000a1287 +[XMPPStream xmppThreadMain] (XMPPStream.m:4463)
7   Foundation                           0x3011fdc7 __NSThread__main__ + 1063
8   libsystem_pthread.dylib              0x3a04cc5d _pthread_body + 141
9   libsystem_pthread.dylib              0x3a04cbcf _pthread_start + 102
10  libsystem_pthread.dylib              0x3a04acd0 thread_start + 8

Thread 5:
0   libsystem_kernel.dylib               0x39fe6440 __select + 20
1   libsystem_pthread.dylib              0x3a04cc5d _pthread_body + 141
2   libsystem_pthread.dylib              0x3a04cbcf _pthread_start + 102
3   libsystem_pthread.dylib              0x3a04acd0 thread_start + 8

Thread 6:
0   libsystem_kernel.dylib               0x39fd3a84 mach_msg_trap + 20
1   CoreFoundation                       0x2f706561 __CFRunLoopServiceMachPort + 157
2   CoreFoundation                       0x2f704c81 __CFRunLoopRun + 793
3   CoreFoundation                       0x2f66f541 CFRunLoopRunSpecific + 524
4   CoreFoundation                       0x2f66f323 CFRunLoopRunInMode + 106
5   WebCore                              0x375d27dd RunWebThread(void*) + 421
6   libsystem_pthread.dylib              0x3a04cc5d _pthread_body + 141
7   libsystem_pthread.dylib              0x3a04cbcf _pthread_start + 102
8   libsystem_pthread.dylib              0x3a04acd0 thread_start + 8

Thread 7:
0   libsystem_kernel.dylib               0x39fd3a84 mach_msg_trap + 20
1   CoreFoundation                       0x2f706561 __CFRunLoopServiceMachPort + 157
2   CoreFoundation                       0x2f704c81 __CFRunLoopRun + 793
3   CoreFoundation                       0x2f66f541 CFRunLoopRunSpecific + 524
4   CoreFoundation                       0x2f66f323 CFRunLoopRunInMode + 106
5   libAVFAudio.dylib                    0x2e64d5b3 GenericRunLoopThread::Entry(void*) + 131
6   libAVFAudio.dylib                    0x2e641bf7 CAPThread::Entry(CAPThread*) + 179
7   libsystem_pthread.dylib              0x3a04cc5d _pthread_body + 141
8   libsystem_pthread.dylib              0x3a04cbcf _pthread_start + 102
9   libsystem_pthread.dylib              0x3a04acd0 thread_start + 8

Thread 8:
0   libsystem_kernel.dylib               0x39fe5f38 __psynch_cvwait + 24
1   libsystem_pthread.dylib              0x3a04d041 pthread_cond_wait + 40
2   JavaScriptCore                       0x3069340d JSC::BlockAllocator::blockFreeingThreadMain() + 209
3   JavaScriptCore                       0x30690a73 WTF::wtfThreadEntryPoint(void*) + 15
4   libsystem_pthread.dylib              0x3a04cc5d _pthread_body + 141
5   libsystem_pthread.dylib              0x3a04cbcf _pthread_start + 102
6   libsystem_pthread.dylib              0x3a04acd0 thread_start + 8

Thread 9:
0   libsystem_kernel.dylib               0x39fe5f38 __psynch_cvwait + 24
1   libsystem_pthread.dylib              0x3a04d041 pthread_cond_wait + 40
2   JavaScriptCore                       0x30831af7 JSC::GCThread::waitForNextPhase() + 79
3   JavaScriptCore                       0x30831b51 JSC::GCThread::gcThreadMain() + 53
4   JavaScriptCore                       0x30690a73 WTF::wtfThreadEntryPoint(void*) + 15
5   libsystem_pthread.dylib              0x3a04cc5d _pthread_body + 141
6   libsystem_pthread.dylib              0x3a04cbcf _pthread_start + 102
7   libsystem_pthread.dylib              0x3a04acd0 thread_start + 8

Thread 10:
0   libsystem_kernel.dylib               0x39fd3a84 mach_msg_trap + 20
1   CoreFoundation                       0x2f706561 __CFRunLoopServiceMachPort + 157
2   CoreFoundation                       0x2f704c81 __CFRunLoopRun + 793
3   CoreFoundation                       0x2f66f541 CFRunLoopRunSpecific + 524
4   CoreFoundation                       0x2f66f323 CFRunLoopRunInMode + 106
5   Foundation                           0x3005d827 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 255
6   Foundation                           0x300ae669 -[NSRunLoop(NSRunLoop) run] + 81
7   My App                          0x000b1635 +[GCDAsyncSocket cfstreamThread] (GCDAsyncSocket.m:6714)
8   Foundation                           0x3011fdc7 __NSThread__main__ + 1063
9   libsystem_pthread.dylib              0x3a04cc5d _pthread_body + 141
10  libsystem_pthread.dylib              0x3a04cbcf _pthread_start + 102
11  libsystem_pthread.dylib              0x3a04acd0 thread_start + 8

Thread 11:
0   libsystem_kernel.dylib               0x39fd3a84 mach_msg_trap + 20
1   CoreFoundation                       0x2f706561 __CFRunLoopServiceMachPort + 157
2   CoreFoundation                       0x2f704c81 __CFRunLoopRun + 793
3   CoreFoundation                       0x2f66f541 CFRunLoopRunSpecific + 524
4   CoreFoundation                       0x2f6b31ab CFRunLoopRun + 98
5   CoreMotion                           0x2fd27399 CLSF_thorntonUpdate_6x6 + 57225
6   libsystem_pthread.dylib              0x3a04cc5d _pthread_body + 141
7   libsystem_pthread.dylib              0x3a04cbcf _pthread_start + 102
8   libsystem_pthread.dylib              0x3a04acd0 thread_start + 8

Thread 12:
0   libsystem_kernel.dylib               0x39fd3ad4 semaphore_wait_trap + 8
1   MediaToolbox                         0x30b60d0f fpa_AsyncMovieControlThread + 1755
2   CoreMedia                            0x2fc9b23f figThreadMain + 195
3   libsystem_pthread.dylib              0x3a04cc5d _pthread_body + 141
4   libsystem_pthread.dylib              0x3a04cbcf _pthread_start + 102
5   libsystem_pthread.dylib              0x3a04acd0 thread_start + 8

Thread 13:
0   libsystem_kernel.dylib               0x39fe6c7c __workq_kernreturn + 8
1   libsystem_pthread.dylib              0x3a04acc4 start_wqthread + 8

Thread 14:
0   libsystem_kernel.dylib               0x39fe6c7c __workq_kernreturn + 8
1   libsystem_pthread.dylib              0x3a04acc4 start_wqthread + 8

Thread 15:
0   libsystem_kernel.dylib               0x39fe6c7c __workq_kernreturn + 8
1   libsystem_pthread.dylib              0x3a04acc4 start_wqthread + 8

Thread 16:
0   libsystem_kernel.dylib               0x39fe6c7c __workq_kernreturn + 8
1   libsystem_pthread.dylib              0x3a04acc4 start_wqthread + 8

Thread 0 crashed with ARM Thread State:
    pc: 0x0100078c     r7: 0x27ddb5e8     sp: 0x27ddb5b8     r0: 0x16d20b30 
    r1: 0x27ddb5b8     r2: 0x0100078c     r3: 0x00000000     r4: 0x169a6d78 
    r5: 0x16b33250     r6: 0x2fe140a5     r8: 0x27ddb5b8     r9: 0x164ea8b8 
   r10: 0x157ea030    r11: 0x00000004     ip: 0x3a265964     lr: 0x2fe1402d 
  cpsr: 0x40000010 

Here's the code:

NSMutableDictionary *attributes = [@{NSFontAttributeName: [[self class] unreadChatLabelFont]
                                    , NSForegroundColorAttributeName: [UIColor whiteColor]} mutableCopy];

if ([self unreadChatLabelHasDropShadow]) {

    NSShadow *shadow = [[NSShadow alloc] init];
    shadow.shadowOffset = CGSizeMake(0, -1);
    shadow.shadowColor = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: .5];
    attributes[NSShadowAttributeName] = shadow;

}



NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString: unreadChats
                                                                       attributes: attributes];

[attributedString drawAtPoint: labelPosition];

And in a different place in the same class:

CGContextRef context = UIGraphicsGetCurrentContext();

CGContextSetShadowWithColor(context, CGSizeMake(0,1), 1.5, [UIColor blackColor].CGColor);

NSDictionary *attributes = @{NSFontAttributeName: [[self class] displayNameFont], NSForegroundColorAttributeName: [UIColor whiteColor]};

NSAttributedString *displayName = [[NSAttributedString alloc] initWithString: dictionary[kDisplayNameKey]
                                                                  attributes: attributes];

[displayName drawAtPoint: [[self class] displayNamePosition]];

// Remove shadow from draw settings
CGContextSetShadowWithColor(context, CGSizeMake(0,1), 1.5, NULL);
like image 931
Nick Locking Avatar asked Oct 17 '13 00:10

Nick Locking


2 Answers

Ensure that you are not adding a label, changing text in the label or drawing text on a thread other than the main thread. Whilst the documentation does say the following:

NSTextStorage, NSLayoutManager, and NSTextContainer can be accessed from subthreads as long as the app guarantees the access from a single thread.

I have found in the past that they are not entirely thread safe and some glyph related operations must occur on the main thread and will produce an exception or crash with an EXC_BAD_ACCESS if they are not. Whilst this is not exactly like your crash report, this is a possible cause of the crash.

like image 166
Joshua Avatar answered Nov 15 '22 09:11

Joshua


To rule out cross thread UIKit drawing as an issue, dispatch your call to -drawAtPoint: onto the main queue.

NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:unreadChats attributes:attributes];

dispatch_async(dispatch_get_main_queue(), ^{
  [attributedString drawAtPoint: labelPosition];
});
like image 23
RyanR Avatar answered Nov 15 '22 09:11

RyanR