UIStringDrawing methods are no longer thread safe in iOS 6

Originator:adam
Number:rdar://12367081 Date Originated:25-Sep-2012 02:38 PM
Status:Open Resolved:
Product:iPhone SDK Product Version:6.0
Classification: Reproducible:Always
 
Summary:

Using any UIStringDrawing methods on two threads simultaneously causes a crash. My understanding was that all UIStringDrawing methods were thread safe from iOS 4.0.

Steps to Reproduce:

This code (that does nothing of any use) demonstrates the problem:

	dispatch_queue_t queue = dispatch_queue_create("com.queue", NULL);
	
	for (int i = 0; i < 10000; i++) {
		
		dispatch_async(queue, ^{
			
			NSString *string = @"My string";
			CGSize size = [string sizeWithFont:[UIFont boldSystemFontOfSize:13]];
		});
	}
	
	for (int i = 0; i < 10000; i++) {
		
		NSString *string = @"My string";
		CGSize size = [string sizeWithFont:[UIFont boldSystemFontOfSize:13]];
	}
	
	dispatch_release(queue);

The app crashes after a few iterations of the loops with the following backtrace:

* thread #1: tid = 0x2403, 0x00ad40c8, stop reason = EXC_BAD_ACCESS (code=2, address=0xad40c8)
    frame #0: 0x00ad40c8
    frame #1: 0x36bc4252 WebCore`WebCore::Font::Font(WebCore::FontPlatformData const&, WTF::PassRefPtr<WebCore::FontSelector>) + 90
    frame #2: 0x36bc41f2 WebCore`WebCore::Font::Font(WebCore::FontPlatformData const&, WTF::PassRefPtr<WebCore::FontSelector>) + 10
    frame #3: 0x38f0368e WebKit`rendererForFont(__GSFont*) + 246
    frame #4: 0x38f03230 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:forWidth:ellipsis:letterSpacing:resultRange:] + 200
    frame #5: 0x38f03162 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:forWidth:ellipsis:letterSpacing:] + 66
    frame #6: 0x38f04532 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:] + 58
    frame #7: 0x361dc5d2 UIKit`-[NSString(UIStringDrawing) sizeWithFont:] + 46
    frame #8: 0x00060ca8 atlas`-[TAViewController drawingTest] + 216 at TAViewController.m:157
    frame #9: 0x38da1e66 Foundation`__NSFireDelayedPerform + 450
    frame #10: 0x3aa47856 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 14
    frame #11: 0x3aa47502 CoreFoundation`__CFRunLoopDoTimer + 274
    frame #12: 0x3aa46176 CoreFoundation`__CFRunLoopRun + 1230
    frame #13: 0x3a9b923c CoreFoundation`CFRunLoopRunSpecific + 356
    frame #14: 0x3a9b90c8 CoreFoundation`CFRunLoopRunInMode + 104
    frame #15: 0x3a8a433a GraphicsServices`GSEventRunModal + 74
    frame #16: 0x3622c288 UIKit`UIApplicationMain + 1120
    frame #17: 0x0005f08c atlas`main + 96 at main.m:16

  thread #3: tid = 0x2803, 0x3b441568 libsystem_kernel.dylib`__getdirentries64 + 8
    frame #0: 0x3b441568 libsystem_kernel.dylib`__getdirentries64 + 8
    frame #1: 0x37f98670 libsystem_c.dylib`_readdir_unlocked + 72
    frame #2: 0x37f98610 libsystem_c.dylib`readdir + 40
    frame #3: 0x3a9d2e58 CoreFoundation`_CFBundleCopySortedDirectoryContentsAtPath + 492
    frame #4: 0x3a9dee1e CoreFoundation`_CFBundleURLLooksLikeBundleVersion + 38
    frame #5: 0x3a9de572 CoreFoundation`_CFBundleCreate + 142
    frame #6: 0x3a9f2bbe CoreFoundation`_CFBundleEnsureBundleExistsForImagePath + 66
    frame #7: 0x3a9f2a9c CoreFoundation`CFBundleGetBundleWithIdentifier + 96
    frame #8: 0x36c61708 WebCore`WebCore::localizedString(char const*) + 36
    frame #9: 0x38f2222e WebKit`WebLocalizedStringInternal + 38
    frame #10: 0x339f0792 libdispatch.dylib`_dispatch_call_block_and_release + 10
    frame #11: 0x339f4656 libdispatch.dylib`_dispatch_root_queue_drain + 278
    frame #12: 0x339f47d8 libdispatch.dylib`_dispatch_worker_thread2 + 92
    frame #13: 0x37f957f0 libsystem_c.dylib`_pthread_wqthread + 360
    frame #14: 0x37f95684 libsystem_c.dylib`start_wqthread + 8

  thread #4: tid = 0x2903, 0x3b442d98 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #0: 0x3b442d98 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #1: 0x37f95ada libsystem_c.dylib`_pthread_workq_return + 18
    frame #2: 0x37f957f6 libsystem_c.dylib`_pthread_wqthread + 366
    frame #3: 0x37f95684 libsystem_c.dylib`start_wqthread + 8

  thread #5: tid = 0x2a03, 0x00ad40c8, stop reason = EXC_BAD_ACCESS (code=2, address=0xad40c8)
    frame #0: 0x00ad40c8
    frame #1: 0x36bc4252 WebCore`WebCore::Font::Font(WebCore::FontPlatformData const&, WTF::PassRefPtr<WebCore::FontSelector>) + 90
    frame #2: 0x36bc41f2 WebCore`WebCore::Font::Font(WebCore::FontPlatformData const&, WTF::PassRefPtr<WebCore::FontSelector>) + 10
    frame #3: 0x38f0368e WebKit`rendererForFont(__GSFont*) + 246
    frame #4: 0x38f03230 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:forWidth:ellipsis:letterSpacing:resultRange:] + 200
    frame #5: 0x38f03162 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:forWidth:ellipsis:letterSpacing:] + 66
    frame #6: 0x38f04532 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:] + 58
    frame #7: 0x361dc5d2 UIKit`-[NSString(UIStringDrawing) sizeWithFont:] + 46
    frame #8: 0x00060d5c atlas`__31-[TAViewController drawingTest]_block_invoke_0 + 116 at TAViewController.m:150
    frame #9: 0x339f0792 libdispatch.dylib`_dispatch_call_block_and_release + 10
    frame #10: 0x339f3b3a libdispatch.dylib`_dispatch_queue_drain + 142
    frame #11: 0x339f167c libdispatch.dylib`_dispatch_queue_invoke + 44
    frame #12: 0x339f4612 libdispatch.dylib`_dispatch_root_queue_drain + 210
    frame #13: 0x339f47d8 libdispatch.dylib`_dispatch_worker_thread2 + 92
    frame #14: 0x37f957f0 libsystem_c.dylib`_pthread_wqthread + 360
    frame #15: 0x37f95684 libsystem_c.dylib`start_wqthread + 8

  thread #6: tid = 0x2b03, 0x3b442d98 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #0: 0x3b442d98 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #1: 0x37f95ada libsystem_c.dylib`_pthread_workq_return + 18
    frame #2: 0x37f957f6 libsystem_c.dylib`_pthread_wqthread + 366
    frame #3: 0x37f95684 libsystem_c.dylib`start_wqthread + 8

  thread #10: tid = 0x2c03, 0x3b442d98 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #0: 0x3b442d98 libsystem_kernel.dylib`__workq_kernreturn + 8
    frame #1: 0x37f95ada libsystem_c.dylib`_pthread_workq_return + 18
    frame #2: 0x37f957f6 libsystem_c.dylib`_pthread_wqthread + 366
    frame #3: 0x37f95684 libsystem_c.dylib`start_wqthread + 8

  thread #7: tid = 0x2d03, 0x3b4426a4 libsystem_kernel.dylib`__semwait_signal + 24
    frame #0: 0x3b4426a4 libsystem_kernel.dylib`__semwait_signal + 24
    frame #1: 0x37fa51c2 libsystem_c.dylib`nanosleep + 142
    frame #2: 0x37fa5130 libsystem_c.dylib`usleep + 52
    frame #3: 0x005530b6 GPUToolsCore`smt_poll_thread_entry(void*) + 126
    frame #4: 0x37fa00e0 libsystem_c.dylib`_pthread_start + 308
    frame #5: 0x37f9ffa8 libsystem_c.dylib`thread_start + 8

  thread #8: tid = 0x2e03, 0x3b4325d0 libsystem_kernel.dylib`kevent64 + 24
    frame #0: 0x3b4325d0 libsystem_kernel.dylib`kevent64 + 24
    frame #1: 0x339f5d26 libdispatch.dylib`_dispatch_mgr_invoke + 810
    frame #2: 0x339f1378 libdispatch.dylib`_dispatch_mgr_thread + 36

  thread #9: tid = 0x2f03, 0x3b431e30 libsystem_kernel.dylib`mach_msg_trap + 20
    frame #0: 0x3b431e30 libsystem_kernel.dylib`mach_msg_trap + 20
    frame #1: 0x3b431fd4 libsystem_kernel.dylib`mach_msg + 52
    frame #2: 0x3aa472ba CoreFoundation`__CFRunLoopServiceMachPort + 130
    frame #3: 0x3aa46030 CoreFoundation`__CFRunLoopRun + 904
    frame #4: 0x3a9b923c CoreFoundation`CFRunLoopRunSpecific + 356
    frame #5: 0x3a9b90c8 CoreFoundation`CFRunLoopRunInMode + 104
    frame #6: 0x36bcca84 WebCore`RunWebThread(void*) + 444
    frame #7: 0x37fa00e0 libsystem_c.dylib`_pthread_start + 308
    frame #8: 0x37f9ffa8 libsystem_c.dylib`thread_start + 8

  thread #11: tid = 0x3003, 0x3b431e30 libsystem_kernel.dylib`mach_msg_trap + 20
    frame #0: 0x3b431e30 libsystem_kernel.dylib`mach_msg_trap + 20
    frame #1: 0x3b431fd4 libsystem_kernel.dylib`mach_msg + 52
    frame #2: 0x3aa472ba CoreFoundation`__CFRunLoopServiceMachPort + 130
    frame #3: 0x3aa46030 CoreFoundation`__CFRunLoopRun + 904
    frame #4: 0x3a9b923c CoreFoundation`CFRunLoopRunSpecific + 356
    frame #5: 0x3a9b90c8 CoreFoundation`CFRunLoopRunInMode + 104
    frame #6: 0x38cfddd2 Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 254
    frame #7: 0x001c4350 atlas`+[FlurryHTTPEater sendMethod:to:body:headerFields:timeoutInterval:useWebView:] + 684 at FlurryHTTPEater.m:66
    frame #8: 0x001ce2a6 atlas`+[FlurrySession sendSessionsToServerWithTimeout:useWebView:requestAppCircleAds:requestVideoAds:requestAppSpotAds:requestReengageAds:sendCurrentSession:] + 1054 at FlurrySession.m:1058
    frame #9: 0x001cde24 atlas`+[FlurrySession sendSessionsToServerForAppCircle] + 308 at FlurrySession.m:1019
    frame #10: 0x38daaa40 Foundation`__NSThread__main__ + 972
    frame #11: 0x37fa00e0 libsystem_c.dylib`_pthread_start + 308
    frame #12: 0x37f9ffa8 libsystem_c.dylib`thread_start + 8

  thread #12: tid = 0x3103, 0x3b431e30 libsystem_kernel.dylib`mach_msg_trap + 20
    frame #0: 0x3b431e30 libsystem_kernel.dylib`mach_msg_trap + 20
    frame #1: 0x3b431fd4 libsystem_kernel.dylib`mach_msg + 52
    frame #2: 0x3aa472ba CoreFoundation`__CFRunLoopServiceMachPort + 130
    frame #3: 0x3aa46030 CoreFoundation`__CFRunLoopRun + 904
    frame #4: 0x3a9b923c CoreFoundation`CFRunLoopRunSpecific + 356
    frame #5: 0x3a9b90c8 CoreFoundation`CFRunLoopRunInMode + 104
    frame #6: 0x38d2709c Foundation`+[NSURLConnection(Loader) _resourceLoadLoop:] + 308
    frame #7: 0x38daaa40 Foundation`__NSThread__main__ + 972
    frame #8: 0x37fa00e0 libsystem_c.dylib`_pthread_start + 308
    frame #9: 0x37f9ffa8 libsystem_c.dylib`thread_start + 8

  thread #13: tid = 0x3303, 0x3b442594 libsystem_kernel.dylib`select$DARWIN_EXTSN + 20
    frame #0: 0x3b442594 libsystem_kernel.dylib`select$DARWIN_EXTSN + 20
    frame #1: 0x3aa4b478 CoreFoundation`__CFSocketManager + 680
    frame #2: 0x37fa00e0 libsystem_c.dylib`_pthread_start + 308
    frame #3: 0x37f9ffa8 libsystem_c.dylib`thread_start + 8

Expected Results:

My understanding was that UIStringDrawing methods were thread safe from iOS 4. I expect that these loops should complete with no errors.

Actual Results:

The app crashes after a few iterations of the loops with EXC_BAD_ACCESS.

Regression:

• The crash occurs when running on an iPhone running iOS 6 (tested on iPhone 5).
• The crash does NOT occur when running on an iPhone running iOS 5 (tested on iPhone 4).
• The crash does NOT occur when running in the simulator (tested with iOS 6).
• The crash does NOT occur if only the foreground or only the background loop is run. Both foreground and background loops are required to cause a crash.

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!