fix: avoid double free when destroying WebContents (#31104)

This commit is contained in:
Cheng Zhao 2021-09-27 16:20:55 +09:00 committed by GitHub
parent 1a6a8f55af
commit 2360012cad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 18 additions and 2 deletions

View file

@ -953,18 +953,31 @@ WebContents::~WebContents() {
// InspectableWebContents will be automatically destroyed. // InspectableWebContents will be automatically destroyed.
} }
void WebContents::DeleteThisIfAlive() {
// It is possible that the FirstWeakCallback has been called but the
// SecondWeakCallback has not, in this case the garbage collection of
// WebContents has already started and we should not |delete this|.
// Calling |GetWrapper| can detect this corner case.
auto* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Object> wrapper;
if (!GetWrapper(isolate).ToLocal(&wrapper))
return;
delete this;
}
void WebContents::Destroy() { void WebContents::Destroy() {
// The content::WebContents should be destroyed asyncronously when possible // The content::WebContents should be destroyed asyncronously when possible
// as user may choose to destroy WebContents during an event of it. // as user may choose to destroy WebContents during an event of it.
if (Browser::Get()->is_shutting_down() || IsGuest() || if (Browser::Get()->is_shutting_down() || IsGuest() ||
type_ == Type::kBrowserView) { type_ == Type::kBrowserView) {
delete this; DeleteThisIfAlive();
} else { } else {
base::PostTask(FROM_HERE, {content::BrowserThread::UI}, base::PostTask(FROM_HERE, {content::BrowserThread::UI},
base::BindOnce( base::BindOnce(
[](base::WeakPtr<WebContents> contents) { [](base::WeakPtr<WebContents> contents) {
if (contents) if (contents)
delete contents.get(); contents->DeleteThisIfAlive();
}, },
GetWeakPtr())); GetWeakPtr()));
} }

View file

@ -451,6 +451,9 @@ class WebContents : public gin::Wrappable<WebContents>,
WebContents(v8::Isolate* isolate, const gin_helper::Dictionary& options); WebContents(v8::Isolate* isolate, const gin_helper::Dictionary& options);
~WebContents() override; ~WebContents() override;
// Delete this if garbage collection has not started.
void DeleteThisIfAlive();
// Creates a InspectableWebContents object and takes ownership of // Creates a InspectableWebContents object and takes ownership of
// |web_contents|. // |web_contents|.
void InitWithWebContents(std::unique_ptr<content::WebContents> web_contents, void InitWithWebContents(std::unique_ptr<content::WebContents> web_contents,