為什麼特殊阿拉伯字元串能造成iOS系統和OS X下應用崩潰?解決方案是什麼?15年重現bug。

更新:15年5月14日,微信朋友出現字元串: ? ? ? ?。一旦查看該字元串,微信,手q,陌陌,來往等多個IOS應用崩潰。
——分割線——

  • Fenng 的微博 | 新浪微博
  • 某特殊阿拉伯字元可造成蘋果 iOS 6 操作系統應用閃退(烏雲)
  • 此特殊阿拉伯字元串的搜索結果 - Google

Warning:前兩個鏈接所指向頁面的評論區和第三個鏈接的頁面都含有此字元串,iOS 6 和 OSX 10.8 用戶請勿打開,若需查看請更換運行 Windows/Linux/Android 等其他操作系統的設備,或者使用 Firefox 瀏覽器


先說結論吧:
@Bill Cheng、@麥子龍 和 @李鐵柱 的答案都是片面的。
導致這個 bug 的元兇,在 iOS 6 上是 WebCore,在 OS X 10.8 上是 CoreText。

========

以下是反駁 @Bill Cheng 的觀點:
這是那個越獄補丁的源碼:https://github.com/FilippoBiga/GlyphPatch/blob/master/Tweak.mm
很明顯是給 WebCore 打的補丁。

代碼的注釋里提到了 WebCore 的 characterRangeCodePath() 函數會在處理 U+0600 ~ U+109F 的字元(其中 U+0600 ~ U+06FF、U+0750 ~ U+077F 是阿拉伯字母)時當成複雜類型,而它調用的 ComplexTextController::adjustGlyphsAndAdvances() 方法在處理這種類型的文字時卻出錯了。
以下代碼來自 WebKit 源碼(https://github.com/WebKit/webkit/blob/6d656cf12b0b12cfb5555dd50d5d908d6d2793ff/Source/WebCore/platform/graphics/mac/FontComplexTextMac.cpp#L59):

float Font::getGlyphsAndAdvancesForComplexText(const TextRun run, int from, int to, GlyphBuffer glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
{
float initialAdvance;

ComplexTextController controller(this, run, false, 0, forTextEmphasis);
controller.advance(from);
float beforeWidth = controller.runWidthSoFar();
controller.advance(to, glyphBuffer);

if (glyphBuffer.isEmpty())
return 0;

float afterWidth = controller.runWidthSoFar();

if (run.rtl()) {
initialAdvance = controller.totalWidth() + controller.finalRoundingWidth() - afterWidth;
glyphBuffer.reverse(0, glyphBuffer.size());
} else
initialAdvance = beforeWidth;

return initialAdvance;
}

它構造了一個 ComplexTextController 類型的對象,這個對象在初始化時崩潰了。
這個類是 WebCore 框架的,根據 @麥子龍 和匿名用戶的回答(http://www.zhihu.com/question/21568134/answer/18652888),這裡並沒有更深的調用棧(也不排除調用了內聯函數),基本可以認定是 WebCore 的 bug。我並不同意 @麥子龍 說異常棧可能不完整的問題,因為彙編代碼都顯示出來了,在哪崩潰是很顯而易見的。
補丁給出的解決辦法是將類型設為自動,也就不會調用上述方法了。但這種解決辦法也許會引來其他的 bug(主要是顯示方面,對不用阿拉伯語的人應該沒影響);只是我對阿拉伯語不了解,也就不妄做判斷了。

更直接的依據是 @祝博韜 的回答:iOS 6 的 CoreText 是能正常顯示這段文字的。

========

但上述結論也並不代表 CoreText 就沒問題,我今天在測試時發現某些字元組合甚至可以讓 OS X 10.8 的 Terminal 崩潰,而它是不太可能使用 WebCore 的。
此外,這個 bug 並不是在 iOS 7 和 OS X 10.9 上就不存在了,在某些情況下仍能造成 crash。例如用那串文字做文件名,那麼 Finder 在顯示這個文件時就會崩潰。這也讓我覺得 CoreText 很可疑。

以 Mac Safari 的崩潰異常棧為例,它是在 CoreText 里崩潰的;雖然也用到了 WebCore,但崩潰的位置和 iOS 下不一樣:

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libvDSP.dylib 0x00007fff8efdbadb 0x7fff8efbf000 + 117467
1 com.apple.CoreText 0x00007fff8e6c1d5c TRun::TRun(TRun const, CFRange, TRun::SubrangingStyle) + 850
2 com.apple.CoreText 0x00007fff8e6c19ee CTGlyphRun::CloneRange(CTRun const*, CFRange, TRun::SubrangingStyle) + 142
3 com.apple.CoreText 0x00007fff8e6d0764 TLine::SetLevelRange(CFRange, unsigned char, bool) + 162
4 com.apple.CoreText 0x00007fff8e6d1e2c TLine::SetTrailingWhitespaceLevel(unsigned char) + 70
5 com.apple.CoreText 0x00007fff8e6d1d58 TRunReorder::ReorderRuns(TBidiLevelsProvider const, TLine) + 122
6 com.apple.CoreText 0x00007fff8e6d1bfe TTypesetter::FinishLineFill(TLine, double, double) const + 142
7 com.apple.CoreText 0x00007fff8e6c1775 CTTypesetterCreateLine + 131
8 com.apple.WebCore 0x00007fff8f7f1f1a WebCore::ComplexTextController::collectComplexTextRunsForCharactersCoreText(unsigned short const*, unsigned int, unsigned int, WebCore::SimpleFontData const*) + 1562
9 com.apple.WebCore 0x00007fff8f7f176a WebCore::ComplexTextController::collectComplexTextRuns() + 522

這是 Mac QQ 崩潰的異常棧,受傷的也是 CoreText:

Exception Type: EXC_CRASH (SIGSEGV)
Exception Codes: 0x0000000000000000, 0x0000000000000000

Application Specific Information:
Performing @selector(paste:) from sender NSMenuItem 0x6b85170

Thread 0:: Dispatch queue: com.apple.main-thread
0 com.apple.CoreText 0x9568e48f TStorageRange::SetStorageSubRange(CFRange) + 307
1 com.apple.CoreText 0x9568cdf7 TRun::TRun(TRun const, CFRange, TRun::SubrangingStyle) + 853
2 com.apple.CoreText 0x9568ca8e CTGlyphRun::CloneRange(CTRun const*, CFRange, TRun::SubrangingStyle) + 166
3 com.apple.CoreText 0x95699947 TLine::SetLevelRange(CFRange, unsigned char, bool) + 157
4 com.apple.CoreText 0x9569b000 TLine::SetTrailingWhitespaceLevel(unsigned char) + 86
5 com.apple.CoreText 0x9569aee7 TRunReorder::ReorderRuns(TBidiLevelsProvider const, TLine) + 107
6 com.apple.CoreText 0x9569ad8c TTypesetter::FinishLineFill(TLine, double, double) const + 122
7 com.apple.CoreText 0x9568c870 TTypesetter::FillLine(TLine, CFRange, double, double) const + 90
8 com.apple.CoreText 0x9568c7ff CTTypesetterCreateLine + 185
9 com.apple.AppKit 0x98085a9a -[NSATSLineFragment layoutForStartingGlyphAtIndex:characterIndex:minPosition:maxPosition:lineFragmentRect:] + 802
10 com.apple.AppKit 0x9808452c -[NSATSTypesetter _layoutLineFragmentStartingWithGlyphAtIndex:characterIndex:atPoint:renderingContext:] + 2254
11 com.apple.AppKit 0x980a91cb -[NSATSTypesetter layoutParagraphAtPoint:] + 147
12 com.apple.AppKit 0x98645f21 -[NSTypesetter _layoutGlyphsInLayoutManager:startingAtGlyphIndex:maxNumberOfLineFragments:maxCharacterIndex:nextGlyphIndex:nextCharacterIndex:] + 3403
13 com.apple.AppKit 0x980a813a -[NSTypesetter layoutCharactersInRange:forLayoutManager:maximumNumberOfLineFragments:] + 215
14 com.apple.AppKit 0x980a8011 -[NSATSTypesetter layoutCharactersInRange:forLayoutManager:maximumNumberOfLineFragments:] + 1185
15 com.apple.AppKit 0x980a69c5 -[NSLayoutManager(NSPrivate) _fillLayoutHoleForCharacterRange:desiredNumberOfLines:isSoft:] + 738
16 com.apple.AppKit 0x980d9f1e _NSFastFillAllLayoutHolesForGlyphRange + 227
17 com.apple.AppKit 0x980a4f95 -[NSLayoutManager textContainerForGlyphAtIndex:effectiveRange:] + 198
18 com.apple.AppKit 0x97ee4a80 -[NSTextView(NSPrivate) _ensureLayoutCompleteToEndOfCharacterRange:] + 125
19 com.apple.AppKit 0x97ee442b -[NSTextView(NSSharing) didChangeText] + 159
20 com.apple.AppKit 0x97ee1f71 -[NSTextView insertText:replacementRange:] + 2261
21 com.tencent.qq 0x003ed850 -[TXTypingTextView insertText:replacementRange:] + 163
22 com.apple.AppKit 0x985b57f0 -[NSTextView insertText:] + 319
23 com.tencent.qq 0x003cfd6c -[TXBaseTextView AddAttributedString:] + 69
24 com.tencent.qq 0x003d2a0c -[TXBaseTextView ReadFromPasteborad:] + 392
25 com.tencent.qq 0x003ee97f -[TXTypingTextView paste:] + 98
26 libobjc.A.dylib 0x96dbc5d3 -[NSObject performSelector:withObject:] + 70
27 com.apple.AppKit 0x98110ad2 -[NSApplication sendAction:to:from:] + 436
28 com.apple.AppKit 0x9824d2fc -[NSMenuItem _corePerformAction] + 529
29 com.apple.AppKit 0x9824cf8b -[NSCarbonMenuImpl performActionWithHighlightingForItemAtIndex:] + 163
30 com.apple.AppKit 0x9824c614 -[NSMenu _performActionWithHighlightingForItemAtIndex:sendAccessibilityNotification:] + 79
31 com.apple.AppKit 0x9824c5c0 -[NSMenu _performActionWithHighlightingForItemAtIndex:] + 48
32 com.apple.AppKit 0x9824bac5 -[NSMenu performKeyEquivalent:] + 306
33 com.tencent.qq 0x0053233e -[TXMenu performKeyEquivalent:] + 503
34 com.apple.AppKit 0x9824ae7c -[NSApplication _handleKeyEquivalent:] + 915
35 com.apple.AppKit 0x98100de1 -[NSApplication sendEvent:] + 5512
36 com.apple.AppKit 0x9801a62c -[NSApplication run] + 951
37 com.apple.AppKit 0x97fbd5f6 NSApplicationMain + 1053
38 com.tencent.qq 0x000028b5 start + 53

這就說明在 OS X 10.8 上,CoreText 才是真兇。

因此 iOS 和 OS X 上各有不同的 bug,而不能想當然地認為兇手只有一個。


不完全同意 @Bill Cheng 的答案,iOS 6 上即使是 UILabel 也是用 WebCore 渲染的。

我傾向於 CoreText 和 WebCore 各自都有問題。這個 bug 應該歸結為蘋果從 WebCore 到 CoreText 都存在設計缺陷,對從右往左的編輯方向支持的不好,設計上沒有考慮這種字元序列,而不能單純說 WebCore 或者 CoreText 的某個地方有個小 bug。

我們看一下它們 crash 在什麼地方。從 iOS 和 OSX 的 crash 上看它們 crash 在不同的地方。

iOS crash 在 WebCore 的 ComplexTextController::adjustGlyphsAndAdvances(),OSX 則 crash 在 CoreText 的 TRun::TRun(TRun const, CFRange, TRun::SubrangingStyle) 或者 TRun::TruncateUnorderedEnd(CFRange, bool, TCharStream const) 等地方。

因為不知道 binary 對應的源碼版本,不確定 iOS adjustGlyphsAndAdvances crash 在源碼的哪一行上。OSX 雖然 crash 在 CoreText 上,也不能排除是 WebCore 調用 CoreText 的 CTTypesetterCreateLine 函數時傳的 typesetter 參數有問題。

10.9 上部分控制項同樣有這個問題,當把一個文件的文件名設為這段字元的時候 Finder 崩潰(如果你把這個文件放在桌面上……)。

那麼,為什麼說這個問題不是單獨由 CoreText 引起的呢?

首先,OSX 10.8 使用 Firefox 是不會 crash 的。

其次,OSX 10.8 上只修改 WebCore,可以繞過這個 bug(注釋掉這個 if 的前一半):

// if (!m_mayUseNaturalWritingDirection || m_run.directionalOverride()) {
// static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel };
// const short ltrForcedEmbeddingLevelValue = 0;
// const short rtlForcedEmbeddingLevelValue = 1;
// static const void* ltrOptionValues[] = { CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, ltrForcedEmbeddingLevelValue) };
// static const void* rtlOptionValues[] = { CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, rtlForcedEmbeddingLevelValue) };
// static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, WTF_ARRAY_LENGTH(optionKeys), kCFCopyStringDictionaryKeyCallBacks, kCFTypeDictionaryValueCallBacks);
// static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, WTF_ARRAY_LENGTH(optionKeys), kCFCopyStringDictionaryKeyCallBacks, kCFTypeDictionaryValueCallBacks);
//
//#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED &>= 1070
// ProviderInfo info = { cp, length, stringAttributes.get() };
// RetainPtr& typesetter = adoptCF(wkCreateCTTypesetterWithUniCharProviderAndOptions(provideStringAndAttributes, 0, info, m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions));
//#else
// RetainPtr& string = adoptCF(CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, cp, length, kCFAllocatorNull));
// RetainPtr& attributedString = adoptCF(CFAttributedStringCreate(kCFAllocatorDefault, string.get(), stringAttributes.get()));
// RetainPtr& typesetter = adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions));
//#endif
//
// line = adoptCF(CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0)));
// } else {
ProviderInfo info = { cp, length, stringAttributes.get() };

line = adoptCF(wkCreateCTLineWithUniCharProvider(provideStringAndAttributes, 0, info));
// }

修改後這段字元串可以正常顯示:

另外,

另外,在 iOS 6 上直接用 CoreText 渲染這段文字,是沒有問題的(有圖有真相)


10.8 上 Safari crash 在 WebCore 調用 CoreText 里:

10.9 上 Finder 崩潰的部分異常棧:

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libvDSP.dylib 0x00007fff8df210b3 0x7fff8deb4000 + 446643
1 com.apple.CoreText 0x00007fff853b7ce7 TRun::TruncateUnorderedEnd(CFRange, bool, TCharStream const) + 1207
2 com.apple.CoreText 0x00007fff853b77ed TTruncator::AppendTruncatedRun(TLine, CTRun const*, CFRange, bool) + 109
3 com.apple.CoreText 0x00007fff853b7261 TTruncator::TruncateEndChars(long, double, TLine, bool*) + 425
4 com.apple.CoreText 0x00007fff853c7b92 TTruncator::MiddleTruncate(double, __CTRun const* (__CTLine const*, CFRange*, __CFDictionary const*) block_pointer) + 342
5 com.apple.CoreText 0x00007fff853b6939 CTLineCreateTruncatedLineWithTokenHandler + 236
6 com.apple.CoreText 0x00007fff853b6847 CTLineCreateTruncatedLineWithTokenCallback + 81
7 com.apple.AppKit 0x00007fff83be9ff4 -[NSATSLineFragment layoutForStartingGlyphAtIndex:characterIndex:minPosition:maxPosition:lineFragmentRect:] + 2372
8 com.apple.AppKit 0x00007fff83be825a -[NSATSTypesetter _layoutLineFragmentStartingWithGlyphAtIndex:characterIndex:atPoint:renderingContext:] + 2777
9 com.apple.AppKit 0x00007fff83ebdddf -[NSSingleLineTypesetter

iOS 6 的 crash 只 crash 在 WebCore 里:

4 libsystem_platform.dylib 0x992ebdeb _sigtramp + 43
5 ??? 0xffffffff 0x0 + 4294967295
6 WebCore 0x04936db7 _ZN7WebCore21ComplexTextControllerC2EPKNS_4FontERKNS_7TextRunEbPN3WTF7HashSetIPKNS_14SimpleFontDataENS7_7PtrHashISB_EENS7_10HashTraitsISB_EEEEb + 855
7 WebCore 0x04936a5a _ZN7WebCore21ComplexTextControllerC1EPKNS_4FontERKNS_7TextRunEbPN3WTF7HashSetIPKNS_14SimpleFontDataENS7_7PtrHashISB_EENS7_10HashTraitsISB_EEEEb + 58
8 WebCore 0x04b71216 _ZNK7WebCore4Font34getGlyphsAndAdvancesForComplexTextERKNS_7TextRunEiiRNS_11GlyphBufferENS0_20ForTextEmphasisOrNotE + 70
9 WebCore 0x04b713fd _ZNK7WebCore4Font15drawComplexTextEPNS_15GraphicsContextERKNS_7TextRunERKNS_10FloatPointEii + 173
10 WebCore 0x04b69058 _ZNK7WebCore4Font8drawTextEPNS_15GraphicsContextERKNS_7TextRunERKNS_10FloatPointEii + 296
11 WebCore 0x04bd9c68 _ZN7WebCore15GraphicsContext12drawBidiTextERKNS_4FontERKNS_7TextRunERKNS_10FloatPointEPNS_10BidiStatusEi + 968
12 WebKit 0x0470d786 _ZL11drawAtPointPKtiRKN7WebCore10FloatPointERKNS1_4FontEPNS1_15GraphicsContextEbPNS1_10BidiStatusEi + 326

總結起來,CoreText 和 WebCore 都有問題。


轉自果殼:
看上去是IOS6的complex text layout render engine的問題。在計算機中,阿拉伯文,天城文,越南文這類文字被稱為complex text,主要的特徵就是字元會因為所在的位置,或者附加符號而產生形變。比如阿拉伯文的同一個字母,會因為所處的位置有4種不同的形態。越南的國語字(Ch? Qu?c Ng?)雖然是以拉丁字母為基礎,但是複雜的音調系統會造成字元變形,所以也屬於complex text.

對於人來說,complex text就是一個死記硬背的過程。而對於計算機來說,就變成一個麻煩事兒。因為保存在存儲器上的文本,無法直接逐字元呈現給用戶看。舉例比如梵文中佛陀(buddha)一詞,存儲的時候會逐字存儲為
? ? ? ? ?五個字元,但是如果直接這麼畫出來,誰都看不懂。 所以這就需要一個complex text layout render engine,它的作用就是把存儲的complex text組合後畫出來,變成可以正常閱讀的形式。 比如Windows下的uniscribe,就是這麼個東西。

這個render engine依賴於兩個東西來工作。第一是逐語言的規則。也就是說,藏文一套規則,阿拉伯文一套規則,印地語一套規則,梵文一套規則..... 所以包含了多少種語言的規則,就可以按規則對字元組合,畫出來多少種語言的文字來。第二是字體文件內部的合字規則(ligature),OpenType和AAT字體支持ligature。

同樣的,Unicode標準提供了一系列用於進行組合的字元,其中一部分就是為了支持complex text的。比如上面看到的? ? 就是天城體中的母音附記。

那麼繞回來,為什麼IOS6可能出問題。看上去就是它的complex text layout render engine的規則出問題了。上邊的字串中包含了3個Unicode組合字元。U+0310, U+0334, U+0337. 而不幸的是,這三個字元都不用於阿拉伯語。U+0310叫新月點,一般用於轉寫天城文,孟加拉文等時標記在拉丁字元上的。U+0334是用於國際音標中標記鼻化母音的那個小波浪線,學法語的同學肯定很熟悉。 U+0337是短刪除線。 這幾個字元都不是用在阿拉伯語中的。

所以當IOS6的engine(原諒我,懶得敲那麼長了)在處理這一串字元的時候,會根據字元的範圍,判定為阿拉伯字元,再根據字元出現的概率選擇一種規則(這步可能沒有,但是因為很多語言使用阿拉伯字元,比如烏爾都語,所以這步其實有必要),假定為選擇了阿拉伯語規則。那麼規則里發現找不到這三個組合字元,傷不起啊有木有! 然後,掛了.......

從程序猿角度來說,沒有default fall through處理嘛,bug!

原文鏈接:
這段會讓iOS 6崩潰的字元是什麼意思?


對於那個說是core text導致crash的答案,我存在一些疑惑,理由如下:

  1. 最底下是我自己用mobile safari查看這個阿拉伯字元串拿到的crash log,可以清楚的看到crash的線程就是WebCore,stack trace裡面也沒有core text framework的調用。
  2. 從這個文章看,webkit在osx和iOS有使用core text做文字渲染http://www.paulirish.com/2013/webkit-for-developers/ 如果有問題,只可能是這一步有問題
  3. 說coretext導致崩潰的那個答案的引文2中的gist和我這個crash log幾乎一致,但是和答案中貼的crash log不一致。而該答案中引用的crash log從引文1中看應該是在使用iTerms2的時候的crash log,而非瀏覽器本身,而且從上層調用中看到的PTYTextView我google了一下好像是iTerms2的私有類,所以是否iTerms中看到core text在stack trace上僅僅是個例,會不會是iTerms2中的PTYTextView自身有bug?
  4. 說coretext導致崩潰的那個答案中引文1的那個論壇,樓下很多都回復使用iTerms無法重現該crash,讓我更加懷疑是不是個案。
  5. 我並不是說一定就不是core text的問題,只是認為那個答案的論證方法存在漏洞,而且夾帶大量私貨,對於技術問題的討論這樣是不恰當的,尤其是在有非技術人員會瀏覽的論壇。

Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x81819462
Crashed Thread: 2

Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0:
0 libsystem_kernel.dylib 0x3a309e30 mach_msg_trap + 20
1 libsystem_kernel.dylib 0x3a309fd0 mach_msg + 48
2 CoreFoundation 0x321002b6 __CFRunLoopServiceMachPort + 126
3 CoreFoundation 0x320fefd6 __CFRunLoopRun + 814
4 CoreFoundation 0x32072238 CFRunLoopRunSpecific + 352
5 CoreFoundation 0x320720c4 CFRunLoopRunInMode + 100
6 GraphicsServices 0x35c51336 GSEventRunModal + 70
7 UIKit 0x33f8e2b4 UIApplicationMain + 1116
8 MobileSafari 0x000e736e 0xda000 + 54126
9 libdyld.dylib 0x3a253b1c start + 0

Thread 1 name: Dispatch queue: com.apple.libdispatch-manager
Thread 1:
0 libsystem_kernel.dylib 0x3a30a5d0 kevent64 + 24
1 libdispatch.dylib 0x3a245d22 _dispatch_mgr_invoke + 806
2 libdispatch.dylib 0x3a241374 _dispatch_mgr_thread + 32

Thread 2 name: WebThread
Thread 2 Crashed:
0 WebCore 0x382f295a WebCore::ComplexTextController::adjustGlyphsAndAdvances() + 522
1 WebCore 0x382ef94e WebCore::ComplexTextController::ComplexTextController(WebCore::Font const*, WebCore::TextRun const, bool, WTF::HashSet&, WTF::HashTraits& &>*, bool) + 318
2 WebCore 0x382ef806 WebCore::ComplexTextController::ComplexTextController(WebCore::Font const*, WebCore::TextRun const, bool, WTF::HashSet&, WTF::HashTraits& &>*, bool) + 18
3 WebCore 0x382f3990 WebCore::Font::getGlyphsAndAdvancesForComplexText(WebCore::TextRun const, int, int, WebCore::GlyphBuffer, WebCore::Font::ForTextEmphasisOrNot) const + 56
4 WebCore 0x382f3862 WebCore::Font::drawComplexText(WebCore::GraphicsContext*, WebCore::TextRun const, WebCore::FloatPoint const, int, int) const + 150
5 WebCore 0x38075684 WebCore::Font::drawText(WebCore::GraphicsContext*, WebCore::TextRun const, WebCore::FloatPoint const, int, int) const + 200
6 WebCore 0x381d8e04 WebCore::paintTextWithShadows(WebCore::GraphicsContext*, WebCore::Font const, WebCore::TextRun const, WTF::AtomicString const, int, int, int, int, WebCore::FloatPoint const, WebCore::FloatRect const, WebCore::ShadowData const*, bool, bool) + 300
7 WebCore 0x381d7b2a WebCore::InlineTextBox::paint(WebCore::PaintInfo, WebCore::IntPoint const, int, int) + 2250
8 WebCore 0x381d34a0 WebCore::InlineFlowBox::paint(WebCore::PaintInfo, WebCore::IntPoint const, int, int) + 780
9 WebCore 0x381d311a WebCore::RootInlineBox::paint(WebCore::PaintInfo, WebCore::IntPoint const, int, int) + 26
10 WebCore 0x3810cb8e WebCore::RenderLineBoxList::paint(WebCore::RenderBoxModelObject*, WebCore::PaintInfo, WebCore::IntPoint const) const + 274
11 WebCore 0x3810955c WebCore::RenderBlock::paintObject(WebCore::PaintInfo, WebCore::IntPoint const) + 232
12 WebCore 0x3810a8b8 WebCore::RenderBlock::paint(WebCore::PaintInfo, WebCore::IntPoint const) + 168
13 WebCore 0x38109a38 WebCore::RenderBlock::paintChildren(WebCore::PaintInfo, WebCore::IntPoint const) + 360
14 WebCore 0x38109568 WebCore::RenderBlock::paintObject(WebCore::PaintInfo, WebCore::IntPoint const) + 244
15 WebCore 0x3810a8b8 WebCore::RenderBlock::paint(WebCore::PaintInfo, WebCore::IntPoint const) + 168
16 WebCore 0x38108338 WebCore::RenderLayer::paintLayerContents(WebCore::RenderLayer*, WebCore::GraphicsContext*, WebCore::IntRect const, unsigned int, WebCore::RenderObject*, WebCore::RenderRegion*, WTF::HashMap&, WTF::HashTraits&, WTF::HashTraits& &>*, unsigned int) + 1760
17 WebCore 0x38107c3a WebCore::RenderLayer::paintLayer(WebCore::RenderLayer*, WebCore::GraphicsContext*, WebCore::IntRect const, unsigned int, WebCore::RenderObject*, WebCore::RenderRegion*, WTF::HashMap&, WTF::HashTraits&, WTF::HashTraits& &>*, unsigned int) + 1082
18 WebCore 0x381084ba WebCore::RenderLayer::paintLayerContents(WebCore::RenderLayer*, WebCore::GraphicsContext*, WebCore::IntRect const, unsigned int, WebCore::RenderObject*, WebCore::RenderRegion*, WTF::HashMap&, WTF::HashTraits&, WTF::HashTraits& &>*, unsigned int) + 2146
19 WebCore 0x38107c3a WebCore::RenderLayer::paintLayer(WebCore::RenderLayer*, WebCore::GraphicsContext*, WebCore::IntRect const, unsigned int, WebCore::RenderObject*, WebCore::RenderRegion*, WTF::HashMap&, WTF::HashTraits&, WTF::HashTraits& &>*, unsigned int) + 1082
20 WebCore 0x381077b0 WebCore::RenderLayer::paint(WebCore::GraphicsContext*, WebCore::IntRect const, unsigned int, WebCore::RenderObject*, WebCore::RenderRegion*, unsigned int) + 52
21 WebCore 0x38107448 WebCore::FrameView::paintContents(WebCore::GraphicsContext*, WebCore::IntRect const) + 520
22 WebKit 0x389ab6aa -[WebFrame(WebInternal) _drawRect:contentsOnly:] + 354
23 WebKit 0x389ab4d0 -[WebHTMLView drawSingleRect:] + 132
24 WebKit 0x389ab3fe -[WebHTMLView drawRect:] + 30
25 WebCore 0x38106f4e -[WAKView _drawRect:context:lockFocus:] + 274
26 WebCore 0x38107086 -[WAKView _drawRect:context:lockFocus:] + 586
27 WebCore 0x38107086 -[WAKView _drawRect:context:lockFocus:] + 586
28 WebCore 0x38107086 -[WAKView _drawRect:context:lockFocus:] + 586
29 WebCore 0x38107086 -[WAKView _drawRect:context:lockFocus:] + 586
30 WebCore 0x38106e2e -[WAKView displayRect:] + 94
31 WebCore 0x38106dc6 -[WAKWindow displayRect:] + 50
32 WebCore 0x38106ad0 WebCore::TileCache::drawLayer(TileLayer*, CGContext*) + 900
33 QuartzCore 0x33cf39f8 CABackingStoreUpdate_ + 2088
34 QuartzCore 0x33cf3032 CA::Layer::display_() + 970
35 QuartzCore 0x33cea0b2 CA::Layer::display_if_needed(CA::Transaction*) + 198
36 QuartzCore 0x33ce9fdc CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 20
37 QuartzCore 0x33ce99be CA::Context::commit_transaction(CA::Transaction*) + 234
38 QuartzCore 0x33ce97d0 CA::Transaction::commit() + 312
39 QuartzCore 0x33ce9634 CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 56
40 CoreFoundation 0x3210093e __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 18
41 CoreFoundation 0x320fec34 __CFRunLoopDoObservers + 272
42 CoreFoundation 0x3207225e CFRunLoopRunSpecific + 390
43 CoreFoundation 0x320720c4 CFRunLoopRunInMode + 100
44 WebCore 0x3807a390 RunWebThread(void*) + 440
45 libsystem_c.dylib 0x3a2730de _pthread_start + 306
46 libsystem_c.dylib 0x3a272fa4 thread_start + 4

Thread 3 name: com.apple.NSURLConnectionLoader
Thread 3:
0 libsystem_kernel.dylib 0x3a309e30 mach_msg_trap + 20
1 libsystem_kernel.dylib 0x3a309fd0 mach_msg + 48
2 CoreFoundation 0x321002b6 __CFRunLoopServiceMachPort + 126
3 CoreFoundation 0x320ff02c __CFRunLoopRun + 900
4 CoreFoundation 0x32072238 CFRunLoopRunSpecific + 352
5 CoreFoundation 0x320720c4 CFRunLoopRunInMode + 100
6 Foundation 0x329bf888 +[NSURLConnection(Loader) _resourceLoadLoop:] + 304
7 Foundation 0x32a4322c __NSThread__main__ + 968
8 libsystem_c.dylib 0x3a2730de _pthread_start + 306
9 libsystem_c.dylib 0x3a272fa4 thread_start + 4

Thread 4 name: Safari::SafeBrowsingManager
Thread 4:
0 libsystem_kernel.dylib 0x3a309e30 mach_msg_trap + 20
1 libsystem_kernel.dylib 0x3a309fd0 mach_msg + 48
2 CoreFoundation 0x321002b6 __CFRunLoopServiceMachPort + 126
3 CoreFoundation 0x320ff02c __CFRunLoopRun + 900
4 CoreFoundation 0x32072238 CFRunLoopRunSpecific + 352
5 CoreFoundation 0x320720c4 CFRunLoopRunInMode + 100
6 MobileSafari 0x000f1086 0xda000 + 94342
7 JavaScriptCore 0x3616d030 WTF::wtfThreadEntryPoint(void*) + 12
8 libsystem_c.dylib 0x3a2730de _pthread_start + 306
9 libsystem_c.dylib 0x3a272fa4 thread_start + 4

Thread 5 name: WebCore: CFNetwork Loader
Thread 5:
0 libsystem_kernel.dylib 0x3a309e30 mach_msg_trap + 20
1 libsystem_kernel.dylib 0x3a309fd0 mach_msg + 48
2 CoreFoundation 0x321002b6 __CFRunLoopServiceMachPort + 126
3 CoreFoundation 0x320ff02c __CFRunLoopRun + 900
4 CoreFoundation 0x32072238 CFRunLoopRunSpecific + 352
5 CoreFoundation 0x320720c4 CFRunLoopRunInMode + 100
6 WebCore 0x38114ccc WebCore::runLoaderThread(void*) + 140
7 JavaScriptCore 0x3616d030 WTF::wtfThreadEntryPoint(void*) + 12
8 libsystem_c.dylib 0x3a2730de _pthread_start + 306
9 libsystem_c.dylib 0x3a272fa4 thread_start + 4

Thread 6 name: com.apple.CFSocket.private
Thread 6:
0 libsystem_kernel.dylib 0x3a31a594 __select + 20
1 CoreFoundation 0x32104474 __CFSocketManager + 676
2 libsystem_c.dylib 0x3a2730de _pthread_start + 306
3 libsystem_c.dylib 0x3a272fa4 thread_start + 4

Thread 7 name: JavaScriptCore::BlockFree
Thread 7:
0 libsystem_kernel.dylib 0x3a31a08c __psynch_cvwait + 24
1 libsystem_c.dylib 0x3a26bafc _pthread_cond_wait + 644
2 libsystem_c.dylib 0x3a26b870 pthread_cond_timedwait + 40
3 JavaScriptCore 0x36047df6 WTF::ThreadCondition::timedWait(WTF::Mutex, double) + 102
4 JavaScriptCore 0x3615a532 JSC::BlockAllocator::blockFreeingThreadMain() + 78
5 JavaScriptCore 0x3616d030 WTF::wtfThreadEntryPoint(void*) + 12
6 libsystem_c.dylib 0x3a2730de _pthread_start + 306
7 libsystem_c.dylib 0x3a272fa4 thread_start + 4

Thread 8 name: JavaScriptCore::Marking
Thread 8:
0 libsystem_kernel.dylib 0x3a31a08c __psynch_cvwait + 24
1 libsystem_c.dylib 0x3a26bafc _pthread_cond_wait + 644
2 libsystem_c.dylib 0x3a275cf8 pthread_cond_wait + 36
3 JavaScriptCore 0x360ed6dc JSC::SlotVisitor::drainFromShared(JSC::SlotVisitor::SharedDrainMode) + 140
4 JavaScriptCore 0x360ed620 JSC::MarkStackThreadSharedData::markingThreadMain() + 140
5 JavaScriptCore 0x3616d030 WTF::wtfThreadEntryPoint(void*) + 12
6 libsystem_c.dylib 0x3a2730de _pthread_start + 306
7 libsystem_c.dylib 0x3a272fa4 thread_start + 4

Thread 9 name: WebCore: LocalStorage
Thread 9:
0 libsystem_kernel.dylib 0x3a31a08c __psynch_cvwait + 24
1 libsystem_c.dylib 0x3a26bafc _pthread_cond_wait + 644
2 libsystem_c.dylib 0x3a275cf8 pthread_cond_wait + 36
3 JavaScriptCore 0x36047dc8 WTF::ThreadCondition::timedWait(WTF::Mutex, double) + 56
4 WebCore 0x3828ee7c WTF::PassOwnPtr& WTF::MessageQueue&::waitForMessageFilteredWithTimeout&(WTF::MessageQueueWaitResult, bool ()(WebCore::StorageTask*), double) + 52
5 WebCore 0x3828ee30 WebCore::StorageThread::threadEntryPoint() + 120
6 JavaScriptCore 0x3616d030 WTF::wtfThreadEntryPoint(void*) + 12
7 libsystem_c.dylib 0x3a2730de _pthread_start + 306
8 libsystem_c.dylib 0x3a272fa4 thread_start + 4

Thread 10 name: WebCore: LocalStorage
Thread 10:
0 libsystem_kernel.dylib 0x3a31a08c __psynch_cvwait + 24
1 libsystem_c.dylib 0x3a26bafc _pthread_cond_wait + 644
2 libsystem_c.dylib 0x3a275cf8 pthread_cond_wait + 36
3 JavaScriptCore 0x36047dc8 WTF::ThreadCondition::timedWait(WTF::Mutex, double) + 56
4 WebCore 0x3828ee7c WTF::PassOwnPtr& WTF::MessageQueue&::waitForMessageFilteredWithTimeout&(WTF::MessageQueueWaitResult, bool ()(WebCore::StorageTask*), double) + 52
5 WebCore 0x3828ee30 WebCore::StorageThread::threadEntryPoint() + 120
6 JavaScriptCore 0x3616d030 WTF::wtfThreadEntryPoint(void*) + 12
7 libsystem_c.dylib 0x3a2730de _pthread_start + 306
8 libsystem_c.dylib 0x3a272fa4 thread_start + 4

Thread 11:
0 libsystem_kernel.dylib 0x3a31ad98 __workq_kernreturn + 8
1 libsystem_c.dylib 0x3a268ad6 _pthread_workq_return + 14
2 libsystem_c.dylib 0x3a2687f2 _pthread_wqthread + 362
3 libsystem_c.dylib 0x3a268680 start_wqthread + 4

Thread 12:
0 libsystem_kernel.dylib 0x3a31a08c __psynch_cvwait + 24
1 libsystem_c.dylib 0x3a26bafc _pthread_cond_wait + 644
2 libsystem_c.dylib 0x3a275cf8 pthread_cond_wait + 36
3 MobileSafari 0x00169d44 0xda000 + 589124
4 Foundation 0x32a4322c __NSThread__main__ + 968
5 libsystem_c.dylib 0x3a2730de _pthread_start + 306
6 libsystem_c.dylib 0x3a272fa4 thread_start + 4

Thread 13:
0 libsystem_kernel.dylib 0x3a31ad98 __workq_kernreturn + 8
1 libsystem_c.dylib 0x3a268ad6 _pthread_workq_return + 14
2 libsystem_c.dylib 0x3a2687f2 _pthread_wqthread + 362
3 libsystem_c.dylib 0x3a268680 start_wqthread + 4

Thread 14:
0 libsystem_kernel.dylib 0x3a31ad98 __workq_kernreturn + 8
1 libsystem_c.dylib 0x3a268ad6 _pthread_workq_return + 14
2 libsystem_c.dylib 0x3a2687f2 _pthread_wqthread + 362
3 libsystem_c.dylib 0x3a268680 start_wqthread + 4

Thread 15:
0 libsystem_kernel.dylib 0x3a31ad98 __workq_kernreturn + 8
1 libsystem_c.dylib 0x3a268ad6 _pthread_workq_return + 14
2 libsystem_c.dylib 0x3a2687f2 _pthread_wqthread + 362
3 libsystem_c.dylib 0x3a268680 start_wqthread + 4

Thread 2 crashed with ARM Thread State (32-bit):
r0: 0x0000001e r1: 0x3a47dffc r2: 0x0cf1d46a r3: 0x24b2a7c4
r4: 0xffffffff r5: 0x0000001f r6: 0x00000001 r7: 0x017b4340
r8: 0x00000020 r9: 0x00000000 r10: 0x00000000 r11: 0x0ce49500
ip: 0x00000003 sp: 0x017b4210 lr: 0x382f2ba3 pc: 0x382f295a
cpsr: 0x00000030


========更新===========
@祝博韜 大神親自在Mac上編譯了WebKit,然後發現了問題的觸發點,就是WebCore裡面的對於自然語言排版的判斷存在問題,相關代碼我引用一下:

// if (!m_mayUseNaturalWritingDirection || m_run.directionalOverride()) {
// static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel };
// const short ltrForcedEmbeddingLevelValue = 0;
// const short rtlForcedEmbeddingLevelValue = 1;
// static const void* ltrOptionValues[] = { CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, ltrForcedEmbeddingLevelValue) };
// static const void* rtlOptionValues[] = { CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, rtlForcedEmbeddingLevelValue) };
// static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, WTF_ARRAY_LENGTH(optionKeys), kCFCopyStringDictionaryKeyCallBacks, kCFTypeDictionaryValueCallBacks);
// static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, WTF_ARRAY_LENGTH(optionKeys), kCFCopyStringDictionaryKeyCallBacks, kCFTypeDictionaryValueCallBacks);
//
//#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED &>= 1070
// ProviderInfo info = { cp, length, stringAttributes.get() };
// RetainPtr& typesetter = adoptCF(wkCreateCTTypesetterWithUniCharProviderAndOptions(provideStringAndAttributes, 0, info, m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions));
//#else
// RetainPtr& string = adoptCF(CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, cp, length, kCFAllocatorNull));
// RetainPtr& attributedString = adoptCF(CFAttributedStringCreate(kCFAllocatorDefault, string.get(), stringAttributes.get()));
// RetainPtr& typesetter = adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions));
//#endif
//
// line = adoptCF(CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0)));
// } else {
ProviderInfo info = { cp, length, stringAttributes.get() };

line = adoptCF(wkCreateCTLineWithUniCharProvider(provideStringAndAttributes, 0, info));
// }

注釋掉的代碼應該就是問題所在
報錯的位置就在

line = adoptCF(CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0)));

這一行
對於這個終極解答,我個人認為這個表明,WebCore處理自然語言的時候存在問題,CoreText也存在問題
不過就WebCore是在處理完了之後丟給CoreText的時候出的問題,我覺得CoreText應該要負主要責任。
至於CoreText,這貨只要蘋果不開源,我們永遠不知道他到底是怎麼『殺人』的……

=========頂部註明==========
感覺有些亂了,和@孫竟 還有@祝博韜 兩位知乎iOS大神交流也不太通暢,似乎是因為周六他們都在泡妹子的原因……(窮苦Loser蹲家裡)
這個註明主要是為了指出一個區別,那就是Mac OSX上面我說的CoreText,和iOS上我說的CoreText,指的都是系統對於文字的繪製和排版底層庫,而不是傳說中iOS上的CoreText.framework。
我個人認為,iOS和Mac OSX上,CoreText和WebKit都是具有絕對的排版功能的,但是在層級上,CoreText應該是作為WebKit的底層存在的,如果說CoreText有問題,那麼WebKit和其中的WebCore也會出現問題。
然後iOS上面的CoreText.framework和Mac OSX上面的實現應該是完全不一樣的。
iOS上面CoreText.framework可能為了更加方便的使用和復用庫,將AttributeString部分交給了UIWebDocumentView,也就是Webkit中的WebCore去處理。而Mac OSX上,整個處理過程可能是完全依賴於底層CoreText庫的。
說白了,就是iOS上面的CoreText.framework只是我們看到的一個蘋果玩的Trick,他並沒有連接到底層的CoreText實現,只是一個建立在WebKit上面的封裝。
然後,由於WebKit和CoreText都具有排版能力,在完全交給WebCore來排版的時候不會出問題『@祝博韜 的回答』,但是一旦涉及到了底層CoreText來進行排版,那就會出錯。
==========註明完畢===========

首先,我個人覺得,這個問題的真正原因在於:[1]

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libvDSP.dylib 0x00007fff9080ead6 0x7fff907f2000 + 117462
1 com.apple.CoreText 0x00007fff8892cd5c TRun::TRun(TRun const, CFRange, TRun::SubrangingStyle) + 850
2 com.apple.CoreText 0x00007fff8892c9ee CTGlyphRun::CloneRange(CTRun const*, CFRange, TRun::SubrangingStyle) + 142
3 com.apple.CoreText 0x00007fff8893b764 TLine::SetLevelRange(CFRange, unsigned char, bool) + 162
?
8 com.googlecode.iterm2 0x000000010003ce63 -[PTYTextView(Private) drawRun:ctx:initialPoint:] + 99
9 com.googlecode.iterm2 0x000000010003d498 -[PTYTextView(Private) _drawRuns:runs:] + 344
?
41 com.googlecode.iterm2 0x0000000100001bd4 start + 52

CoreText!
CoreText是用來幹什麼的呢?基本上你在iOS和Mac OSX上面看到的所有字元,都是通過CoreText來進行渲染的。所以CoreText的這個Bug,會導致所有顯示字元的地方都會因為這串字元而崩潰。

當然,由於iOS的特殊性,這個崩潰看上去更像是由WebCore導致的[2]

Thread 2 name: WebThread
Thread 2 Crashed:
0 WebCore 0x382fe95a WebCore::ComplexTextController::adjustGlyphsAndAdvances() + 522
1 WebCore 0x382fb94e WebCore::ComplexTextController::ComplexTextController(WebCore::Font const*, WebCore::TextRun const, bool, WTF::HashSet&, WTF::HashTraits& &>*, bool) + 318
2 WebCore 0x382fb806 WebCore::ComplexTextController::ComplexTextController(WebCore::Font const*, WebCore::TextRun const, bool, WTF::HashSet&, WTF::HashTraits& &>*, bool) + 18
3 WebCore 0x382ff990 WebCore::Font::getGlyphsAndAdvancesForComplexText(WebCore::TextRun const, int, int, WebCore::GlyphBuffer, WebCore::Font::ForTextEmphasisOrNot) const + 56
4 WebCore 0x382ff862 WebCore::Font::drawComplexText(WebCore::GraphicsContext*, WebCore::TextRun const, WebCore::FloatPoint const, int, int) const + 150
5 WebCore 0x3808

(WTF這個……Apple的開發人員啊……)
這裡由於我粘貼複製的原因,Gist和引用的可能有些不同,這裡提供一個另外的Gist,來自於我自己測試的結果[5](178行報錯)。至於引用部分,來自[1]中的討論串,Gist部分來自討論串下面的鏈接。為了引用的完整性,我就不另作處理了,詳細問題大家可以去[1]中找到作者鏈接詢問作者。

這裡會有同學問道為什麼iOS的特性會導致看上去像是WebCore的錯誤,這裡我貼上一張圖片[3]:

這張圖片的進程顯示出iOS在處理Text的一個Trick,那就是富文本內容實際上會被NSHTMLWriter處理。當然非富文本作為富文本的子集自然也是通過這條路的(可能),HTML相關嘛,當然會被WebCore拿走咯,結果就是在WebCore的時候死掉了……當然這個只是推測,詳細的估計還是得把整個Bug發生流程拆了才知道。

這張圖片的進程顯示出iOS在處理Text的一個Trick,那就是富文本內容實際上會被NSHTMLWriter處理。當然非富文本作為富文本的子集自然也是通過這條路的(可能),HTML相關嘛,當然會被WebCore拿走咯,結果就是在WebCore的時候死掉了……當然這個只是推測,詳細的估計還是得把整個Bug發生流程拆了才知道。

今天有很多同學都在質疑iOS 上 CoreText是否是決定性元兇,各種代碼和Error Log都展現出WebCore的嫌疑(名偵探柯南既視感……),看到這麼多同學的質疑,說實在我有點吃不消……亞歷山大……
但是剛才我看到一個Chromium在Mac OSX上面的Error Log [6],從這個Error Log上,我們可以發現這貨:

1 Google Chrome Framew0.894.0.0 0x012f8451 WebCore::ComplexTextController::adjustGlyphsAndAdvances + 0x7 (ComplexTextController.cpp:479)

adjustGlyphsAndAdvance這貨看上去是不是很熟悉,和iOS上面WebCore報錯的那玩意一模一樣吧
根據@孫竟大神提供的Mac OSX上Safari的Error Log:

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libvDSP.dylib 0x00007fff8efdbadb 0x7fff8efbf000 + 117467
1 com.apple.CoreText 0x00007fff8e6c1d5c TRun::TRun(TRun const, CFRange, TRun::SubrangingStyle) + 850
2 com.apple.CoreText 0x00007fff8e6c19ee CTGlyphRun::CloneRange(CTRun const*, CFRange, TRun::SubrangingStyle) + 142
3 com.apple.CoreText 0x00007fff8e6d0764 TLine::SetLevelRange(CFRange, unsigned char, bool) + 162
4 com.apple.CoreText 0x00007fff8e6d1e2c TLine::SetTrailingWhitespaceLevel(unsigned char) + 70
5 com.apple.CoreText 0x00007fff8e6d1d58 TRunReorder::ReorderRuns(TBidiLevelsProvider const, TLine) + 122
6 com.apple.CoreText 0x00007fff8e6d1bfe TTypesetter::FinishLineFill(TLine, double, double) const + 142
7 com.apple.CoreText 0x00007fff8e6c1775 CTTypesetterCreateLine + 131
8 com.apple.WebCore 0x00007fff8f7f1f1a WebCore::ComplexTextController::collectComplexTextRunsForCharactersCoreText(unsigned short const*, unsigned int, unsigned int, WebCore::SimpleFontData const*) + 1562
9 com.apple.WebCore 0x00007fff8f7f176a WebCore::ComplexTextController::collectComplexTextRuns() + 522

WebCore報錯的根本還是在於CoreText
一樣的WebCore Function,我覺得蘋果然兩個WebKit實現機制一致實在是可能性太高了
但是限於沙盒機制(待驗證),CoreText的報錯被隱藏了,就像Chromium的報錯一樣,你看不到CoreText,但實際上CoreText就站在那裡,拿著帶血的小匕首。
當然,鑒於iOS和Mac OSX的處理機制存在一定差異,最終解釋還要看蘋果內部有沒有人願意站出來說明一下了。

再補充一個新的證據,根據@周琪 和我本人的實驗,在UILabel長度不足以顯示完整整個字元串的時候,這個Bug是不會被觸發的,根據WebKit相關代碼[7],我個人認為WebKit的排版不會負責對於顯示空間的判斷,所以CoreText在繪製部分出錯的可能性更高。

就和所有文字排版導致的問題一樣,這次出現的這串字元也有一個很有趣的效應,詳細大家可以去看看我這個項目:so898/TestCoreTextWebCoreCrash 路 GitHub
這小玩意挺好玩的,而且我相信這個項目對於幫助大家理解這次Bug和UILabel處理文字排版的機制也是很有幫助的。

[註明:以上所有分析都存在一個絕對假設:Bug只存在一處。如果Bug存在WebCore和CoreText等多處,或者說Bug來自於蘋果開發人員對於整個欄位理解錯誤,那麼上面的所有分析幾乎都不成立。]

那麼關於發生Bug的根本原因呢?
通過上面的所有Log,我們至少可以得出一個結論,那就是萬惡的Range檢測失敗了。
在蘋果的系統中,一般來說對於文字內容的檢測都是分成一個個Range來細化處理的,這次的字元串很有可能是一個需要被聯合到一起處理的內容,但是由於種種原因,對於處理區域的檢測判定失敗了(或者重疊了),所以產生了不可避免的錯誤。如果大家有幸在Mac OSX 10.8上面看到這串字元而且沒有使得閃退的話,應該會發現在某些時候這段字元自動換行了,也許就是這個被強加的換行處理和換行字元的連續處理兩個渲染重疊產生了問題。
如果說要詳細研究的話,就得去研究這串阿拉伯文的語義和相關語法了……

之後呢?
由於WP和Android用戶,還有廣大人民群眾對於iOS和Mac OSX用戶深深的惡意,還有諸如@Fenng 等大V無心的傳播,導致從早上到下午,無數的iOS和Mac OSX用戶中槍。
上午我在公司的時候,QQ開著,基本上每個QQ群都在刷,瀏覽了一下各種科技網站,滿目這串字元,微信朋友圈一陣哀嚎,還有無數轉發微博在那裡求證、攻擊……
最後的結果就是,無數的人簡訊打不開了,微信打不開了,QQ打不開了……
好在大部分電腦小白都給Macbook Pro裝了Windows,不然殺傷人數會增加更多。
至於iOS用戶,那真是只能自求多福。
當然除了自求多福之外,還有些事情是可以做的。

  1. 升級iOS7。iOS7正在進行最後一個Beta,現在升級並不需要去淘寶或者找其他開發者要開發者許可權,直接在威鋒或者其他網站上下一個就好了,然後按照教程升級即可。(說得巧,今天下午威鋒剛好論壇升級,直接導致某些淘寶賣家賺了不少黑心錢)
  2. 越獄用戶可以安裝@麥子龍 提到的那個補丁
  3. 對於微信,可以在接收到這個字元之後,通過Windows上的諸如iTools等軟體的微信查看功能來刪除對應聊天記錄;簡訊可以通過某些蘋果助手內置的簡訊編輯功能來刪除對應字元(需要關閉iCloud之後才可操作)
  4. Mac用戶可以修改系統字體,字體修改之後似乎可以繞過這個Bug[4]

當然,之後也許你應該把給你發這段字元的人給拉黑,或者直接起訴他或者蘋果公司(如果有重大利益損失並且你可以證明的話)


再之後呢?
在之後我們似乎應該想想,為什麼會發生下午這個狀況。
略帶惡意的玩笑?無心的調侃?亦或者宣洩不滿的攻擊?還是說是蘋果為了讓iOS 6用戶儘快升級留下的黑手?
想像空間太大了。
雖然我的設備都升級到了iOS 7 Beta,Macbook Pro也做了響應的保護性處理(關閉所有推送,轉發所有收到的信息到Windows電腦或者iOS 7設備),但是想著我母上大人手中的iPhone可能因此而沒法看簡訊,沒法看微信,說真的我恨憤怒。我不在她身邊,也沒有辦法遠程解決這個不太好解決的問題,如果她中招,那麼接下來,她可能得被迫放棄iPhone和裡面的所有資料。想到她可能的焦慮,我很無力,很憤怒。
我懶得再去猜測那麼還在瘋狂轉發那段純攻擊性的阿拉伯字元的人的想法了。
人的惡意,真的是無法揣測的。

[1]DoS exploit crashes iOS/OSX devices using WebKit
[2]https://gist.github.com/steakknife/6374524
[3]UITextView Caught With Trousers Down
[4]http://translate.google.com/translate?hl=ensl=rutl=enu=http%3A%2F%2Fhabrahabr.ru%2Fpost%2F191654%2F
[5]https://gist.github.com/so898/6396011
[6]Issue 98711 -
chromium -

chrome_mac crash: WebCore::FontPlatformData::roundsGlyphAdvances
[7]webkit/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp at master 路 WebKit/webkit 路 GitHub


今天發現了一條有關 iOS6 的bug, 只要在 iOS6的手機上出現某特定字元串,就會引起閃退,比如微信朋友圈,只要有人在朋友圈中發了那條指定字元串,他的朋友一打開朋友圈就會閃退,還有手機 QQ,簡訊,備忘錄等,都會出現這種情況,據有人分析可能是因為 iOS6的字型檔有漏洞,導致只要顯是該字元串就會出現閃退(未證實,不確定)

我就很好奇的開始了實驗,首先通過MBP裡面的備忘錄,存了這條字元串,我的備忘錄是通過 iCloud 同步的,然後從手機上打開備忘錄,發現直接閃退...然後我準備通過網頁版微信給自己發這條字元串,發現剛複製到對話框,網頁直接崩潰...接著我在電腦上的 QQ 群裡面發了這條字元串,通過手機 QQ 去看,手機 QQ 直接被廢.我同事的手機升級了 iOS7,我讓他給我發微信,他發給我之後我的微信也被廢了,直接無法打開.然後他給我發簡訊,這條字元串通過推送出現在手機屏幕上的時候我的手機直接重啟了,之後簡訊就無法打開,經過以上手賤的實驗,發現這個漏洞實在是殺傷力巨大....總的原則就是只要你的手機顯示了這條字元串,就會崩潰.

我說一下初步的解決方案,如果在朋友圈中有人發送了這條消息,那麼可以等到你朋友圈中的其他人發的消息把該字元串給刷掉,也就是說只要你朋友圈中一個屏幕內沒有這條字元串,就不會崩潰,但是當你往下翻,翻出了這條字元串,照舊會閃退,只有當發布該字元串的人刪除了這條消息,才會沒事.而如果對方是通過微信或者 手機 QQ 單獨發送給你這條字元串,你需要刪除微信或者 QQ,重新安裝,目的是刪除存在本地的聊天記錄,只要手機不顯示該字元串,就不會閃退.至於簡訊,讓發送者給你再發一條簡訊,然後讓另一個人也給你發一條簡訊,這樣就能打開簡訊了,然後你把包含該字元串那個對話給刪除就可以了

最徹底的解決方案就是升級 iOS7...但是需要開發者帳號,所以不具備普遍意義,我覺得如此嚴重的 bug,蘋果應該會很快發布升級補丁,所以各位也不用驚慌,這個這個補丁從技術上推測應該是很簡單解決的(樓主的手機已經徹底被自己玩壞掉了...現在正在升級 iOS7)


我覺得,可能是系統不夠清真的緣故。大家知道的,美國佬都是異教徒,異教徒的東西,對阿拉伯人民來說,簡直是大罪孽。


題外話,這不是iOS的問題,甚至這個不是Apple的問題,在任何平台任何app中都有可能因為這段阿拉伯字元導致崩潰,不相信的可以做個實踐。

打開word2013
複製這段阿拉伯字元進去(純文本)
加大這段阿拉伯字元的字號

word一樣會崩潰。

// 2013-09-01 16:48修改
在PC上才發現知乎可以傳圖,那麼來一張,證實一下在windows下,個別App也存在這個問題。


不過圖片上來,居然被壓縮成jpg了。 gif走這裡: http://ww1.sinaimg.cn/bmiddle/69c1953bgw1e873bfv1xog20bd0axam8.gif


3、如果是微信朋友圈崩潰,你可以從微信「我」-「我的相冊」進去,點擊「今天」那裡的相機,發張照片即可恢復。

不可恢復的說~誰還有辦法?


在看MahApps的源代碼
發現了這個BIDI OS注釋
http://www.ibm.com/developerworks/cn/opensource/os-cn-bidi/


解決方法是升級IOS7


問題原因樓上有人分析了,我說一下解決方案。針對簡訊,微信,如果只是朋友惡作劇,讓你朋友發一條新的簡訊過來就可以,微信的話多發十幾條新的微信把代碼刷出屏幕範圍,然後 記得清除記錄 ,否則不小心划過去又看到了。其他應用直接刪除重新安裝,空間這一類的,先用其他系統手機電腦把這個發代碼說說的人拉黑,然後手機上重裝app。


ipad弄這個導致qq崩潰了,重新下載程序也沒用,後來換了個小號登陸了一下沒事,退出再登陸平常用的主號後就好了.不過奇怪的是,我開始就是在電腦上用小號發的這竄字元導致主號崩潰,可是登陸小號調出的聊天記錄查看這竄字元卻不崩潰,不知道為什麼.


自己發了個微信朋友圈 然後無法刪除 有什麼方法解決?


非程序猿的IOS使用者弱弱的說一句…IOS8暫時沒中招,已經有人發過這種東西了但是沒問題


我歪個樓

大家不要沒事只複製最後一句發朋友圈,不僅你自己開不了朋友圈,你的前好友們也開不了。

別問我為什麼是前好友...


這都幾年了?????至少13年之前
卧槽。。。果然是墳


奔潰可能原因:
解析有問題

臨時解決方案:
1、找一個朋友發一條普通的簡訊
2、如果是ipad/mac用戶,卸載,重新安裝,先用小號登陸,然後註銷,最後再用大號登陸即可。
3、如果是微信朋友圈崩潰,你可以從微信「我」-「我的相冊」進去,點擊「今天」那裡的相機,發張照片即可恢復。

解決方案1、3來自:烏雲-漏洞報告平台的微博 新浪微博


推薦閱讀:

iOS 8 設備隨機 MAC 地址躲避 Wi-Fi 熱點的記錄追蹤,技術上是怎麼實現,有何影響?
如何評價 Swift 語言?
為什麼 Windows 上的第三方軟體對高清屏支持這麼差?

TAG:macOS | iOS 應用 | 計算機語言 | iOS 6 | iOS 8 |