阅读iOS Webkit崩溃堆栈跟踪

7
我有一个非常棘手的技术问题,希望能找到一些Webkit专家。我正在为客户开发iOS应用程序,该应用程序的大部分内容是在UIWebView控制器中提供的HTML5内容。
大约一周前,QA团队开始报告应用程序崩溃的情况。过去一周我们每天都会收到约1个崩溃报告。不幸的是,这些崩溃是那种无法确定一致重现步骤的崩溃。奇怪的是,其中一些崩溃报告使用了旧版本的iOS代码库——这些代码曾经成功运行了数月而没有人注意到此崩溃行为。
但所有崩溃情况的共同点是它们都运行在更新后端上,提供最新版本的HTML网络应用页面。因此,似乎我们在服务器端做了一些新的触发iOS代码崩溃的事情。
崩溃日志非常一致。以下是符号化日志:
0   WebCore    0x33147ab0 WebCore::FrameLoader::cancelledError(WebCore::ResourceRequest const&) const + 4
1   WebCore    0x33070fbe WebCore::ResourceLoader::init(WebCore::ResourceRequest const&) + 166
2   WebCore    0x33070e66 WebCore::SubresourceLoader::startLoading() + 14
3   WebCore    0x33070c4e WebCore::ResourceLoadScheduler::servePendingRequests(WebCore::ResourceLoadScheduler::HostInformation*, WebCore::ResourceLoadPriority) + 46
4   WebCore    0x33076508 WebCore::ResourceLoadScheduler::servePendingRequests(WebCore::ResourceLoadPriority) + 36
5   WebCore    0x32fd38c8 WebCore::ThreadTimers::sharedTimerFiredInternal() + 92

大多数关于WebCore崩溃的问题都会建议你在dealloc方法中将webview.delegate设置为nil。但这似乎不是我们的问题。

现在我有一个理论(稍后会讲到),但我没有明确的证据。所以我从webkit.org获取了源代码,并尝试阅读足够的内容来理解WebKit在崩溃时正在做什么。我认为我使用的WebKit源代码版本与iOS设备中的版本不完全相同(我们在5.0.1和5.1.1设备中看到了这个问题),关键方法似乎涉及下载资源(如CSS和图像),但似乎涉及空URL,因此我们最终调用cancelledError方法。

然后FrameLoader做了这件事:

ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const
{
    ResourceError error = m_client->cancelledError(request);
    error.setIsCancellation(true);
    return error;
}

在这个方法中,应用程序崩溃并显示以下信息:

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000008

这让我认为m_client没有指向有效的内容。
现在,我有一个理论关于正在发生的事情,只是基于我的直觉和间接证据。
我们的UIWebView有一个委托来评估正在加载到web视图中的URL。 在某些情况下,我们决定在单独的ViewController中启动新的URL,如下所示:
- (BOOL)webView:(UIWebView *)source shouldStartLoadWithRequest:(NSURLRequest *)request  navigationType:(UIWebViewNavigationType)navigationType 
{
    ...

    if ([self.popupStrategy shouldPopupURL:[request URL] fromCurrent:[source.request URL]]) {

        PopupTransitionViewController *popController = [self createPopupController:request];
        ... push it onto the navigation controller ...

    }
    ...
}

这个弹出策略返回true的关键条件之一是跨域链接。也就是说,如果用户点击链接/图标,并且该链接的目标由第三方站点托管,则应用程序会在不同的ViewController中启动新内容(出于各种原因,包括能够在跨域链接上获得良好的本地过渡效果)。
几周前发生的服务器端变化之一是更新了链接href--现在链接调用我们的主服务器,该服务器发送HTTP重定向将客户端发送到第三方站点。
在这种情况下,我看到我们的popupStrategy被调用了两次。第一次,它评估到我们的主服务器的URL,第二次,它评估第三方URL。在第二种情况下,该策略告诉UIWebView在新的ViewController中加载请求。我的想法是Webkit代码中的某些东西并不总是喜欢那样做,通过一些时间或其他奇怪的事情,这在某些时候导致崩溃。
这个理论让我印象深刻,因为它基于以前不存在于我们服务器代码库中的新的Web加载行为,这很方便地符合症状。我的Webkit代码阅读表明,在引用的一些方法中,当Webkit看到跨源请求时,它似乎正在执行一些特殊处理。但是,这个崩溃无法按需复现,所以我们没有更多的线索。但如果这个理论是正确的,我知道一个合理的解决方法。
我希望有人对Webkit的内部有一些熟悉,并且可以建议:
a)Webkit堆栈跟踪支持这个理论吗?
b)是否有其他见解可以从我得到的堆栈跟踪中推断出来?
1个回答

0

最终我进行了代码更改,这些更改根源于我上面描述的理论。在进行了这些更改之后,我没有看到崩溃再次发生。因此,最初的理论看起来是正确的。


你是怎么解决这个问题的?我们现在也遇到了完全相同的事情。 - Shoerob
我确保在遇到重定向之前,过渡到新控制器已经完成。 - bcholmes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接