无法重现的 webcore 崩溃

Posted

技术标签:

【中文标题】无法重现的 webcore 崩溃【英文标题】:Unreproducible webcore crashes 【发布时间】:2013-11-20 11:36:59 【问题描述】:

我的 iPad 应用程序在 App Store 上架了大约三个月,我收到了一些我无法弄清楚的奇怪崩溃报告。这些并不是那么频繁,自发布以来大约有 15-20 个实例,但仍然频繁到足以让我真正烦恼。崩溃略有不同(请参阅下面的堆栈跟踪),但由于它们与 WebCore 有关,我猜它们与应用程序中 UIWebView 的使用有关,并且可能有一个共同原因,尽管我是不是 100% 积极的。该应用程序的部署目标是 ios 6.0,但崩溃出现在 iPad 2、iPad 3 和 iPad Mini 上,仅在 iOS 7 上。

我在应用程序中只有一个地方使用 webview,用于显示来自各种来源的新闻文章网页。我有一个视图控制器,它有一个UIWebView 作为它的视图。这个视图控制器的一个实例存在于整个应用程序中,每次选择一篇新文章时,现有的 web 视图都会使用新选择的文章的 url 重新加载。

基于围绕 WebCore 问题的讨论提出的解决方案之一建议在控制器的 dealloc 方法中将 webviews delegate 属性设置为 nil。不幸的是,我认为它不适用于我的情况,因为视图控制器在应用程序的生命周期内不会被释放。 另一个问题可能是不正确的网页在 CSS 中有错误的图像引用(loadPendingImages 崩溃)。不过我还没有找到这样的页面。 另外,我仔细检查并确保在主线程上进行了与 webview 相关的操作。

崩溃是

Exception Type: EXC_BAD_ACCESS 
Code: KERN_INVALID_ADDRESS

具有以下堆栈跟踪(完整的here)

0 WebCore WebCore::StyleResolver::applyMatchedProperties(WebCore::StyleResolver::MatchResult const&, WebCore::Element const*) + 815
1 WebCore WebCore::StyleResolver::applyMatchedProperties(WebCore::StyleResolver::MatchResult const&, WebCore::Element const*) + 788
2 WebCore WebCore::StyleResolver::styleForElement(WebCore::Element*, WebCore::RenderStyle*, WebCore::StyleSharingBehavior, WebCore::RuleMatchingBehavior, WebCore::RenderRegion*) + 948
3 WebCore WebCore::Document::styleForElementIgnoringPendingStylesheets(WebCore::Element*) + 96
4 WebCore WebCore::Element::computedStyle(WebCore::PseudoId) + 142
5 WebCore WebCore::ComputedStyleExtractor::propertyValue(WebCore::CSSPropertyID, WebCore::EUpdateLayout) const + 458

0 WebCore WebCore::StyleResolver::loadPendingImages() + 1153
1 WebCore WebCore::ResourceRequestBase::~ResourceRequestBase() + 104
2 WebCore WebCore::StyleResolver::applyMatchedProperties(WebCore::StyleResolver::MatchResult const&, WebCore::Element const*) + 782
3 WebCore WebCore::StyleResolver::styleForElement(WebCore::Element*, WebCore::RenderStyle*, WebCore::StyleSharingBehavior, WebCore::RuleMatchingBehavior, WebCore::RenderRegion*) + 948
4 WebCore WebCore::Document::styleForElementIgnoringPendingStylesheets(WebCore::Element*) + 96
5 WebCore WebCore::Element::computedStyle(WebCore::PseudoId) + 142

0 WebCore WebCore::StyleResolver::adjustRenderStyle(WebCore::RenderStyle*, WebCore::RenderStyle*, WebCore::Element*) + 19
1 WebCore WebCore::StyleResolver::styleForElement(WebCore::Element*, WebCore::RenderStyle*, WebCore::StyleSharingBehavior, WebCore::RuleMatchingBehavior, WebCore::RenderRegion*) + 964
2 WebCore WebCore::Document::styleForElementIgnoringPendingStylesheets(WebCore::Element*) + 96
3 WebCore WebCore::Element::computedStyle(WebCore::PseudoId) + 142
4 WebCore WebCore::ComputedStyleExtractor::propertyValue(WebCore::CSSPropertyID, WebCore::EUpdateLayout) const + 458
5 WebCore WebCore::CSSComputedStyleDeclaration::getPropertyValue(WebCore::CSSPropertyID) const + 42

0 WebCore WebCore::TimerBase::heapDeleteMin() + 37
1 WebCore WebCore::ThreadTimers::sharedTimerFiredInternal() + 94
2 WebCore WebCore::ThreadTimers::sharedTimerFiredInternal() + 94
3 WebCore WebCore::timerFired(__CFRunLoopTimer*, void*) + 24
4 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 14
5 CoreFoundation __CFRunLoopDoTimer + 782

有没有人遇到过类似的崩溃?如果是这样: 1. 有没有办法复制它们? 2. 如何在不复制它们的情况下调试它们? 3. 哪些修复解决了这些问题?

谢谢!

【问题讨论】:

iOS 7 在图形渲染方面存在几个主要问题。您试图追查的问题很可能是操作系统级别(或 SDK 级别)的问题。冒昧地猜测一下,有一些 CSS 转换或动画会导致崩溃。找出原因的唯一希望是找到导致它的页面,即使这样,您也可能无能为力。 是的,不幸的是我还没有自己复制它,因为我正在从各种 (30+) 新闻来源加载新闻文章,所以我觉得我做不到很快。如果没有其他人对这里可能发生的事情有更好的了解,我们将不得不等待 iOS 7.1,看看他们是否解决了这些问题。 我已经在cordova ios7中复制了这个错误,在递归循环中使用window.requestAnimationFrame来对精灵表情进行步进动画。似乎当应用从长时间的睡眠中醒来并尝试再次动画时会发生这种情况。 不幸的是,7.1 并没有解决这些问题。至少在 beta2 中没有。 【参考方案1】:

我在使用的应用程序中遇到了完全相同的问题,奇怪的是它只发生在运行 iOS 7 的旧设备上。我怀疑这与他们无法跟上有关。

我有一个UITableView,其中一行将打开一个UIViewController,上面有一个UIWebView,用于自定义广告。我发现,在较旧的设备上,对象和内存的释放频率比我在其他平台上看到的要频繁得多。通过进出屏幕 2 或 3 次,我可以很容易地在 iPhone 4 上模拟崩溃。作为 iPhone 5,我花了 15 分钟做同样的事情,而且无可挑剔。

我知道您可能会觉得您的控制器没有被释放,但听起来好像是或者某些引用正在被删除,我还看到我的委托引用在这个应用程序中也消失了几次。

我的建议和对我有用的是停止 webview 的执行,并尽可能将所有内容设置为 nil

在我的应用程序的一个实例中,我选择在 viewWillDisappear 回调中执行此操作,因为在我的情况下,它已从用户那里消失并稍后重新创建,所以我将所有内容都这样删除:

[webView stopLoading];

self.webView.delegate = nil;
self.webView = nil;

【讨论】:

感谢您的提示,西蒙。我得试试这个。不幸的是,由于我无法复制该问题,因此我无法知道这是否有效,至少在我发布应用更新之前是这样。 @BotondSzékely 希望它对您有所帮助,一种快速的方法是按照我的做法向您的所有朋友发送消息,并要求借用旧设备几天。我发现 iPhone 4 对 iOS 7 的处理非常糟糕 请注意,如果您只是按原样使用上面的代码,请注意。如果您有用户可以从具有 web 视图的屏幕访问的屏幕,您可能会引入错误。例如,假设您有一个导航栏按钮,可以推动导航控制器上的另一个屏幕。它将调用viewWillDisappear 并清除self.webView.delegateself.webView。然后,当您返回 webview 屏幕时,您仍会看到 webview,但任何引用 self.webView 的代码都不会执行任何操作。【参考方案2】:

查看您的 javascript-to-Objective-C 代码,如果您正在执行/调用 javascript 代码,请确保该脚本不会调用对 Objective-C 的新调用。

这是正确的用法:

Javascript >> Objective-C

Objective-C >> Javascript

这是崩溃的原因:

Objective-C >> Javascript >> Objective-C(根据某些竞争条件,这里可能会崩溃)

解决方案特定于您的项目代码。但最简单的方法是将所有 Javascript 包装在 setTimeout() 中以安排在 Javascript 线程中执行。这是一个简单的例子,你的 Objective-C 代码需要执行这个脚本:

storeUserPhoneNumber("011 123 4567");

如果storeUserPhoneNumber 函数在其主体中回调(直接或间接)Objective-C 代码,则会发生崩溃。要解决这个问题,只需像这样在 setTimeout 中包装代码:

setTimeout(function() 
    storeUserPhoneNumber("011 123 4567");
, 0);

这样做的目的是从字符串中解析 Javascript 代码,并将其置于函数中,该函数计划稍后在解析 JS 代码后的下一个事件循环滴答释放控制权返回给 Objective-C 时执行。

请记住,您需要对所有 Objective-C >> Javascript 调用进行此修复;)

【讨论】:

如果你是对的,你的答案很有趣。您是否有任何文档/参考资料/示例项目支持您的声明?为什么“Objective-C >> Javascript >> Objective-C”会导致崩溃?那么从 Objective-C 执行的 javascript 没有在 javascript 线程上执行呢?这似乎很奇怪,这不会被记录在案。 @deadbeef 如果您想花一些时间自己确认,可以通过简单的测试项目轻松重现。我认为这是 IOS 实现中的一个错误,而不是需要记录的功能。

以上是关于无法重现的 webcore 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

WebCore bmalloc :: IsoAllocator在iOS 11.3中崩溃

WebCore WebCore::GraphicsContext3D::reshape(int, int)

WebKit三件套:WebKit之WebCore篇

[WebKit] JavaScriptCore解析--基础篇 JSC与WebCore

WebCore:Worker:将 Safari 调试器连接到 Xcode 8.3 项目时的 EXC_BAD_ACCESS

Report WebCore crash to the ErrorReportUtils at:Fri Jul 24 09:59:08 格林尼治标准时间+0800 2015