You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cobalt 23网络抓取模块崩溃问题及解决方案合理性咨询

Cobalt 23.lts.3.310436 Net Fetcher模块崩溃问题排查与解决方案验证

问题背景

我们在Cobalt 23.lts.3.310436版本的net fetcher模块中多次遭遇崩溃。通过添加日志排查,定位到url_fetcher_core.cc文件,确认是线程安全问题:对象在仍被使用时被删除。

日志显示,地址2574072352的对象在SetLoadTimingInfo调用前后被删除,触发崩溃;而2574091304的对象使用后删除无异常。

经分析,Stop等方法在同一线程执行,GetLoadTimingInfo在另一线程执行,导致并发冲突。

我提出解决方案:通过PostTask将GetLoadTimingInfo调度到delegate线程执行,避免并发,确保delegate_指针检查与使用一致,同时微调代码。具体修改见下文代码。

请问该解决方案是否合理?另外,此问题可能与部分请求文件(如图片)在服务器上不可用有关,但尚未验证该关联。

日志详情

╭[NetworkModule/21:0306/170243.371985:INFO:url_request.cc(1171)] Call Run
│[NetworkModule/21:0306/170243.372074:INFO:url_fetcher_core.cc(1134)] URLFetcherCore::GetLoadTimingInfo() delegate_=2574091304, this=2573807496, &timing_info=2574194072
│[NetworkModule/21:0306/170243.372140:INFO:url_fetcher_core.cc(1138)] Call ReportLoadTimingInfo, d=2574091304, delegate_=2574091304
│[NetworkModule/21:0306/170243.372233:INFO:net_fetcher.cc(305)] Call SetLoadTimingInfo, h=2574143520, this=2574091296, &timing_info=2574194072
│[NetworkModule/21:0306/170243.372308:INFO:fetcher.h(68)] SetLoadTimingInfo() this=2574143520, load_timing_info_callback_=2574143524
│[NetworkModule/21:0306/170243.372399:INFO:fetcher.h(70)]                     load_timing_info_callback_.is_null()=0
 [MainWebModule/68:0306/170243.372732:INFO:url_fetcher_core.cc(181)] URLFetcherCore::Stop(), delegate_=2574121288, will now set it to NULL.
╰[NetworkModule/21:0306/170243.705613:INFO:fetcher.h(72)]                     Call load_timing_info_callback_.Run, &timing_info=2574194072
 [MainWebModule/68:0306/170243.706208:INFO:url_fetcher_core.cc(181)] URLFetcherCore::Stop(), delegate_=2573905472, will now set it to NULL.
╭[NetworkModule/21:0306/170243.706464:INFO:url_request.cc(1171)] Call Run
 [MainWebModule/68:0306/170243.706509:INFO:url_fetcher_core.cc(181)] URLFetcherCore::Stop(), delegate_=2574091304, will now set it to NULL.
│[NetworkModule/21:0306/170243.706545:INFO:url_fetcher_core.cc(1134)] URLFetcherCore::GetLoadTimingInfo() delegate_=2574072352, this=2573828040, &timing_info=2574229600
│[NetworkModule/21:0306/170243.706622:INFO:url_fetcher_core.cc(1138)] Call ReportLoadTimingInfo, d=2574072352, delegate_=2574072352
![MainWebModule/68:0306/170243.706648:INFO:url_fetcher_core.cc(181)] URLFetcherCore::Stop(), delegate_=2574072352, will now set it to NULL.
│[NetworkModule/21:0306/170243.706679:INFO:net_fetcher.cc(305)] Call SetLoadTimingInfo, h=2573730272, this=2574072344, &timing_info=2574229600
│signal 11

问题调用链

This call:            delegate_->ReportLoadTimingInfo(timing_info);

goes to this:         void NetFetcher::ReportLoadTimingInfo(const net::LoadTimingInfo& timing_info) {
                        // About here another thread comes in and set delegate_ to null.
                        handler()->SetLoadTimingInfo(timing_info);
                      }
                      // About here the other thread deletes the URLFetcherDelegate object, that delegate_ points to.

and down into this:   virtual void SetLoadTimingInfo(const net::LoadTimingInfo& timing_info) {
                        if (!load_timing_info_callback_.is_null()) {
                          load_timing_info_callback_.Run(timing_info);
                        }
                      }

代码修改

--- a/net/url_request/url_fetcher_core.cc
+++ b/net/url_request/url_fetcher_core.cc
@@ -175,8 +175,9 @@ void URLFetcherCore::Start() {
 }
 
 void URLFetcherCore::Stop() {
-  if (delegate_task_runner_)  // May be NULL in tests.
+  if (delegate_task_runner_) {  // May be NULL in tests.
     DCHECK(delegate_task_runner_->RunsTasksInCurrentSequence());
+  }
 
   delegate_ = NULL;
   fetcher_ = NULL;
@@ -779,8 +780,11 @@ void URLFetcherCore::StartURLRequest() {
   if (!extra_request_headers_.IsEmpty())
     request_->SetExtraRequestHeaders(extra_request_headers_);
 
+#if defined(STARBOARD)
   request_->SetLoadTimingInfoCallback(base::Bind(&URLFetcherCore::GetLoadTimingInfo,
       base::Unretained(this)));
+#endif
+
   request_->Start();
 }
 
@@ -1129,6 +1133,14 @@ void URLFetcherCore::AssertHasNoUploadData() const {
 #if defined(STARBOARD)
 void URLFetcherCore::GetLoadTimingInfo(
     const net::LoadTimingInfo& timing_info) {
+  delegate_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&URLFetcherCore::GetLoadTimingInfoInDelegateThread,
+                 this, timing_info));
+}
+
+void URLFetcherCore::GetLoadTimingInfoInDelegateThread(
+    const net::LoadTimingInfo& timing_info) {
   // Check if the URLFetcherCore has been stopped before.
   if (delegate_) {
     delegate_->ReportLoadTimingInfo(timing_info);
diff --git a/net/url_request/url_fetcher_core.h b/net/url_request/url_fetcher_core.h
index 4359ac5495..a06f82f721 100644
--- a/net/url_request/url_fetcher_core.h
+++ b/net/url_request/url_fetcher_core.h
@@ -164,6 +164,7 @@ class URLFetcherCore : public base::RefCountedThreadSafe<URLFetcherCore>,
   static void SetIgnoreCertificateRequests(bool ignored);
 #if defined (STARBOARD)
   void GetLoadTimingInfo(const net::LoadTimingInfo& timing_info);
+  void GetLoadTimingInfoInDelegateThread(const net::LoadTimingInfo& timing_info);
 #endif  // defined(STARBOARD)
  private:
   friend class base::RefCountedThreadSafe<URLFetcherCore>;

解决方案合理性分析

这个解决方案是合理的,核心原因如下:

  • 彻底消除竞态条件:原问题中GetLoadTimingInfo在网络线程执行,而Stop在delegate线程执行,两者并发访问delegate_指针导致对象使用中被删除。通过PostTask将GetLoadTimingInfo的逻辑转发到delegate线程执行,让delegate_的检查和使用都在同一线程完成,从根源避免了多线程冲突。
  • 符合线程模型规范:Cobalt基于Chromium线程模型,delegate_task_runner是专门用于执行delegate相关操作的线程,将回调调度到该线程符合框架设计原则,不会引入新的线程安全问题。
  • 代码修改严谨:新增的GetLoadTimingInfoInDelegateThread方法保持了原有的业务逻辑,仅调整了执行线程;对Stop方法的大括号补全和SetLoadTimingInfoCallback的宏包裹都是规范的代码调整,没有破坏原有功能。

关于请求文件不可用的关联推测:当请求资源不存在时,网络请求会快速终止,触发Stop逻辑的时机更早,此时GetLoadTimingInfo的异步回调可能还未完成,更容易出现delegate_被删除后回调仍在执行的场景。这个关联是成立的,建议构造资源不可用的测试用例,验证是否能稳定复现崩溃,从而确认该触发条件。

内容的提问来源于stack exchange,提问作者Michael

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 05:37:18