diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc index f6b2445c233a5..567ab3301668c 100644 --- a/content/browser/service_worker/service_worker_context_core.cc +++ b/content/browser/service_worker/service_worker_context_core.cc @@ -950,6 +950,17 @@ void ServiceWorkerContextCore::RemoveLiveVersion(int64_t id) { CHECK(it != live_versions_.end()); ServiceWorkerVersion* version = it->second; + // Erase the map entry before dispatching observers. This method is called + // from inside ~ServiceWorkerVersion() (refcount already 0), and the + // synchronous OnStoppedSync chain can re-enter + // ServiceWorkerContextWrapper::FinishedExternalRequest(), which wraps + // GetLiveVersion() in a scoped_refptr. If the dying object is still present + // in `live_versions_`, that takes AddRef on a refcount==0 object and + // produces a double-free when the local scoped_refptr is dropped. `version` + // remains valid for the rest of this method because the destructor body has + // not yet completed. + live_versions_.erase(it); + if (version->running_status() != blink::EmbeddedWorkerStatus::kStopped) { // Notify all observers that this live version is stopped, as it will // be removed from |live_versions_|. @@ -971,8 +982,6 @@ void ServiceWorkerContextCore::RemoveLiveVersion(int64_t id) { observer_list_->Notify( FROM_HERE, &ServiceWorkerContextCoreObserver::OnLiveVersionDestroyed, id); - - live_versions_.erase(it); } std::vector