Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: extensions/renderer/render_frame_observer_natives.cc

Issue 1684953002: Fix re-entrancy and lifetime issue in RenderFrameObserverNatives::OnDocumentElementCreated (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Nits + Invalidate weak ptrs upon Invalidate() Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « extensions/renderer/render_frame_observer_natives.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/renderer/render_frame_observer_natives.h" 5 #include "extensions/renderer/render_frame_observer_natives.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/macros.h" 8 #include "base/macros.h"
9 #include "base/message_loop/message_loop.h" 9 #include "base/message_loop/message_loop.h"
10 #include "content/public/renderer/render_frame.h" 10 #include "content/public/renderer/render_frame.h"
11 #include "content/public/renderer/render_frame_observer.h" 11 #include "content/public/renderer/render_frame_observer.h"
12 #include "extensions/renderer/extension_frame_helper.h" 12 #include "extensions/renderer/extension_frame_helper.h"
13 #include "extensions/renderer/script_context.h" 13 #include "extensions/renderer/script_context.h"
14 14
15 namespace extensions { 15 namespace extensions {
16 16
17 namespace { 17 namespace {
18 18
19 // Deletes itself when done. 19 // Deletes itself when done.
20 class LoadWatcher : public content::RenderFrameObserver { 20 class LoadWatcher : public content::RenderFrameObserver {
21 public: 21 public:
22 LoadWatcher(ScriptContext* context, 22 LoadWatcher(content::RenderFrame* frame,
23 content::RenderFrame* frame, 23 const base::Callback<void(bool)>& callback)
24 v8::Local<v8::Function> cb) 24 : content::RenderFrameObserver(frame), callback_(callback) {}
25 : content::RenderFrameObserver(frame), 25
26 context_(context), 26 void DidCreateDocumentElement() override {
27 callback_(context->isolate(), cb) { 27 // The callback must be run as soon as the root element is available.
28 if (ExtensionFrameHelper::Get(frame)-> 28 // Running the callback may trigger DidCreateDocumentElement or
29 did_create_current_document_element()) { 29 // DidFailProvisionalLoad, so delete this before running the callback.
30 // If the document element is already created, then we can call the 30 base::Callback<void(bool)> callback = callback_;
31 // callback immediately (though post it to the message loop so as to not 31 delete this;
32 // call it re-entrantly). 32 callback.Run(true);
33 // The Unretained is safe because this class manages its own lifetime.
34 base::MessageLoop::current()->PostTask(
35 FROM_HERE,
36 base::Bind(&LoadWatcher::CallbackAndDie, base::Unretained(this),
37 true));
38 }
39 } 33 }
40 34
41 void DidCreateDocumentElement() override { CallbackAndDie(true); }
42
43 void DidFailProvisionalLoad(const blink::WebURLError& error) override { 35 void DidFailProvisionalLoad(const blink::WebURLError& error) override {
44 CallbackAndDie(false); 36 // Use PostTask to avoid running user scripts while handling this
37 // DidFailProvisionalLoad notification.
38 base::MessageLoop::current()->PostTask(FROM_HERE,
39 base::Bind(callback_, false));
40 delete this;
45 } 41 }
46 42
47 private: 43 private:
48 void CallbackAndDie(bool succeeded) { 44 base::Callback<void(bool)> callback_;
49 v8::Isolate* isolate = context_->isolate();
50 v8::HandleScope handle_scope(isolate);
51 v8::Local<v8::Value> args[] = {v8::Boolean::New(isolate, succeeded)};
52 context_->CallFunction(v8::Local<v8::Function>::New(isolate, callback_),
53 arraysize(args), args);
54 delete this;
55 }
56
57 ScriptContext* context_;
58 v8::Global<v8::Function> callback_;
59 45
60 DISALLOW_COPY_AND_ASSIGN(LoadWatcher); 46 DISALLOW_COPY_AND_ASSIGN(LoadWatcher);
61 }; 47 };
62 48
63 } // namespace 49 } // namespace
64 50
65 RenderFrameObserverNatives::RenderFrameObserverNatives(ScriptContext* context) 51 RenderFrameObserverNatives::RenderFrameObserverNatives(ScriptContext* context)
66 : ObjectBackedNativeHandler(context) { 52 : ObjectBackedNativeHandler(context), weak_ptr_factory_(this) {
67 RouteFunction( 53 RouteFunction(
68 "OnDocumentElementCreated", 54 "OnDocumentElementCreated",
69 base::Bind(&RenderFrameObserverNatives::OnDocumentElementCreated, 55 base::Bind(&RenderFrameObserverNatives::OnDocumentElementCreated,
70 base::Unretained(this))); 56 base::Unretained(this)));
71 } 57 }
72 58
59 RenderFrameObserverNatives::~RenderFrameObserverNatives() {}
60
61 void RenderFrameObserverNatives::Invalidate() {
62 weak_ptr_factory_.InvalidateWeakPtrs();
63 ObjectBackedNativeHandler::Invalidate();
64 }
65
73 void RenderFrameObserverNatives::OnDocumentElementCreated( 66 void RenderFrameObserverNatives::OnDocumentElementCreated(
74 const v8::FunctionCallbackInfo<v8::Value>& args) { 67 const v8::FunctionCallbackInfo<v8::Value>& args) {
75 CHECK(args.Length() == 2); 68 CHECK(args.Length() == 2);
76 CHECK(args[0]->IsInt32()); 69 CHECK(args[0]->IsInt32());
77 CHECK(args[1]->IsFunction()); 70 CHECK(args[1]->IsFunction());
78 71
79 int frame_id = args[0]->Int32Value(); 72 int frame_id = args[0]->Int32Value();
80 73
81 content::RenderFrame* frame = content::RenderFrame::FromRoutingID(frame_id); 74 content::RenderFrame* frame = content::RenderFrame::FromRoutingID(frame_id);
82 if (!frame) { 75 if (!frame) {
83 LOG(WARNING) << "No render frame found to register LoadWatcher."; 76 LOG(WARNING) << "No render frame found to register LoadWatcher.";
84 return; 77 return;
85 } 78 }
86 79
87 new LoadWatcher(context(), frame, args[1].As<v8::Function>()); 80 v8::Global<v8::Function> v8_callback(context()->isolate(),
Devlin 2016/02/10 20:30:47 Something else I just thought of: v8::Globals are
robwu 2016/02/10 20:45:49 I don't know, I'm a complete noob with V8 (I just
Devlin 2016/02/10 20:59:00 Let's go with this for now - it's certainly better
81 args[1].As<v8::Function>());
82 base::Callback<void(bool)> callback(
83 base::Bind(&RenderFrameObserverNatives::InvokeCallback,
84 weak_ptr_factory_.GetWeakPtr(), base::Passed(&v8_callback)));
85 if (ExtensionFrameHelper::Get(frame)->did_create_current_document_element()) {
86 // If the document element is already created, then we can call the callback
87 // immediately (though use PostTask to ensure that the callback is called
88 // asynchronously).
89 base::MessageLoop::current()->PostTask(FROM_HERE,
90 base::Bind(callback, true));
91 } else {
92 new LoadWatcher(frame, callback);
93 }
88 94
89 args.GetReturnValue().Set(true); 95 args.GetReturnValue().Set(true);
90 } 96 }
91 97
98 void RenderFrameObserverNatives::InvokeCallback(
99 v8::Global<v8::Function> callback,
100 bool succeeded) {
101 v8::Isolate* isolate = context()->isolate();
102 v8::HandleScope handle_scope(isolate);
103 v8::Local<v8::Value> args[] = {v8::Boolean::New(isolate, succeeded)};
104 context()->CallFunction(v8::Local<v8::Function>::New(isolate, callback),
105 arraysize(args), args);
106 }
107
92 } // namespace extensions 108 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/render_frame_observer_natives.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698