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

Side by Side Diff: chrome_frame/buggy_bho_handling.cc

Issue 6493002: A number of poorly written IE BHO's crash IE if ChromeFrame is the currently ... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 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 | Annotate | Revision Log
« no previous file with comments | « chrome_frame/buggy_bho_handling.h ('k') | chrome_frame/chrome_active_document.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "chrome_frame/buggy_bho_handling.h" 5 #include "chrome_frame/buggy_bho_handling.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/scoped_comptr_win.h" 8 #include "base/scoped_comptr_win.h"
9 9
10 #include "chrome_frame/exception_barrier.h" 10 #include "chrome_frame/exception_barrier.h"
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 (HIWORD(version) == buggy.major_version_ && 68 (HIWORD(version) == buggy.major_version_ &&
69 LOWORD(version) <= buggy.minor_version_)) { 69 LOWORD(version) <= buggy.minor_version_)) {
70 return true; 70 return true;
71 } 71 }
72 } 72 }
73 } 73 }
74 74
75 return false; 75 return false;
76 } 76 }
77 77
78 BuggyBhoTls::BuggyBhoTls() : previous_instance_(s_bad_object_tls_.Get()) { 78 BuggyBhoTls::BuggyBhoTls()
79 : patched_(false) {
80 DCHECK(s_bad_object_tls_.Get() == NULL);
79 s_bad_object_tls_.Set(this); 81 s_bad_object_tls_.Set(this);
80 } 82 }
81 83
82 BuggyBhoTls::~BuggyBhoTls() { 84 BuggyBhoTls::~BuggyBhoTls() {
83 DCHECK(FromCurrentThread() == this); 85 DCHECK(BuggyBhoTls::GetInstance() == this);
84 s_bad_object_tls_.Set(previous_instance_); 86 s_bad_object_tls_.Set(NULL);
85 } 87 }
86 88
87 void BuggyBhoTls::AddBuggyObject(IDispatch* obj) { 89 void BuggyBhoTls::AddBuggyObject(IDispatch* obj) {
88 bad_objects_.push_back(obj); 90 bad_objects_.push_back(obj);
89 } 91 }
90 92
91 bool BuggyBhoTls::IsBuggyObject(IDispatch* obj) const { 93 bool BuggyBhoTls::ShouldSkipInvoke(IDispatch* obj) const {
92 return std::find(bad_objects_.begin(), bad_objects_.end(), obj) != 94 DCHECK(web_browser2_ != NULL);
93 bad_objects_.end(); 95 if (IsChromeFrameDocument(web_browser2_)) {
96 return std::find(bad_objects_.begin(), bad_objects_.end(), obj) !=
97 bad_objects_.end();
98 }
99 return false;
94 } 100 }
95 101
96 // static 102 // static
97 BuggyBhoTls* BuggyBhoTls::FromCurrentThread() { 103 BuggyBhoTls* BuggyBhoTls::GetInstance() {
98 return s_bad_object_tls_.Get(); 104 BuggyBhoTls* tls_instance = s_bad_object_tls_.Get();
105 if (!tls_instance) {
106 tls_instance = new BuggyBhoTls();
107 DCHECK(s_bad_object_tls_.Get() != NULL);
108 }
109 return tls_instance;
110 }
111
112 // static
113 void BuggyBhoTls::DestroyInstance() {
114 BuggyBhoTls* tls_instance = s_bad_object_tls_.Get();
115 if (tls_instance) {
116 delete tls_instance;
117 DCHECK(s_bad_object_tls_.Get() == NULL);
118 }
119 }
120
121 HRESULT BuggyBhoTls::PatchBuggyBHOs(IWebBrowser2* browser) {
122 if (patched_)
123 return S_FALSE;
124
125 DCHECK(browser);
126 DCHECK(web_browser2_ == NULL);
127
128 ScopedComPtr<IConnectionPointContainer> cpc;
129 HRESULT hr = cpc.QueryFrom(browser);
130 if (SUCCEEDED(hr)) {
131 const GUID sinks[] = { DIID_DWebBrowserEvents2, DIID_DWebBrowserEvents };
132 for (size_t i = 0; i < arraysize(sinks); ++i) {
133 ScopedComPtr<IConnectionPoint> cp;
134 cpc->FindConnectionPoint(sinks[i], cp.Receive());
135 if (cp) {
136 ScopedComPtr<IEnumConnections> connections;
137 cp->EnumConnections(connections.Receive());
138 if (connections) {
139 CONNECTDATA cd = {0};
140 DWORD fetched = 0;
141 while (connections->Next(1, &cd, &fetched) == S_OK && fetched) {
142 PatchIfBuggy(cd.pUnk, sinks[i]);
143 cd.pUnk->Release();
144 fetched = 0;
145 }
146 }
147 }
148 }
149 }
150 patched_ = true;
151 web_browser2_ = browser;
152 return hr;
153 }
154
155 bool BuggyBhoTls::PatchIfBuggy(IUnknown* unk, const IID& diid) {
156 DCHECK(unk);
157 PROC* methods = *reinterpret_cast<PROC**>(unk);
158 HMODULE mod = GetModuleFromAddress(methods[0]);
159 if (!IsBuggyBho(mod))
160 return false;
161
162 ScopedComPtr<IDispatch> disp;
163 HRESULT hr = unk->QueryInterface(diid,
164 reinterpret_cast<void**>(disp.Receive()));
165 if (FAILED(hr)) // Sometimes only IDispatch QI is supported
166 hr = disp.QueryFrom(unk);
167 DCHECK(SUCCEEDED(hr));
168
169 if (SUCCEEDED(hr)) {
170 const int kInvokeIndex = 6;
171 DCHECK(static_cast<IUnknown*>(disp) == unk);
172 if (SUCCEEDED(PatchInvokeMethod(&methods[kInvokeIndex]))) {
173 AddBuggyObject(disp);
174 }
175 }
176 return false;
99 } 177 }
100 178
101 // static 179 // static
102 STDMETHODIMP BuggyBhoTls::BuggyBhoInvoke(InvokeFunc original, IDispatch* me, 180 STDMETHODIMP BuggyBhoTls::BuggyBhoInvoke(InvokeFunc original, IDispatch* me,
103 DISPID dispid, REFIID riid, LCID lcid, 181 DISPID dispid, REFIID riid, LCID lcid,
104 WORD flags, DISPPARAMS* params, 182 WORD flags, DISPPARAMS* params,
105 VARIANT* result, EXCEPINFO* ei, 183 VARIANT* result, EXCEPINFO* ei,
106 UINT* err) { 184 UINT* err) {
107 DVLOG(1) << __FUNCTION__; 185 DVLOG(1) << __FUNCTION__;
108 186
109 const BuggyBhoTls* tls = BuggyBhoTls::FromCurrentThread(); 187 DCHECK(BuggyBhoTls::GetInstance())
110 if (tls && tls->IsBuggyObject(me)) { 188 << "You must first have an instance of BuggyBhoTls on this thread";
189 if (BuggyBhoTls::GetInstance() &&
190 BuggyBhoTls::GetInstance()->ShouldSkipInvoke(me)) {
111 // Ignore this call and avoid the bug. 191 // Ignore this call and avoid the bug.
112 // TODO(tommi): Maybe we should check a specific list of DISPIDs too? 192 // TODO(tommi): Maybe we should check a specific list of DISPIDs too?
113 return S_OK; 193 return S_OK;
114 } 194 }
115 195
116 // No need to report crashes in those known-to-be-buggy DLLs. 196 // No need to report crashes in those known-to-be-buggy DLLs.
117 ExceptionBarrierReportOnlyModule barrier; 197 ExceptionBarrierReportOnlyModule barrier;
118 return original(me, dispid, riid, lcid, flags, params, result, ei, err); 198 return original(me, dispid, riid, lcid, flags, params, result, ei, err);
119 } 199 }
120 200
(...skipping 19 matching lines...) Expand all
140 if (!vtable_patch::internal::ReplaceFunctionPointer( 220 if (!vtable_patch::internal::ReplaceFunctionPointer(
141 reinterpret_cast<void**>(invoke), stub->code(), 221 reinterpret_cast<void**>(invoke), stub->code(),
142 reinterpret_cast<void*>(stub->argument()))) { 222 reinterpret_cast<void*>(stub->argument()))) {
143 hr = E_UNEXPECTED; 223 hr = E_UNEXPECTED;
144 FunctionStub::Destroy(stub); 224 FunctionStub::Destroy(stub);
145 } else { 225 } else {
146 PinModule(); // No backing out now. 226 PinModule(); // No backing out now.
147 ::FlushInstructionCache(::GetCurrentProcess(), invoke, sizeof(PROC)); 227 ::FlushInstructionCache(::GetCurrentProcess(), invoke, sizeof(PROC));
148 } 228 }
149 } 229 }
150
151 ::VirtualProtect(invoke, sizeof(PROC), flags, &flags); 230 ::VirtualProtect(invoke, sizeof(PROC), flags, &flags);
152
153 return hr;
154 }
155
156 // static
157 bool BuggyBhoTls::PatchIfBuggy(CONNECTDATA* cd, const IID& diid) {
158 DCHECK(cd);
159 PROC* methods = *reinterpret_cast<PROC**>(cd->pUnk);
160 HMODULE mod = GetModuleFromAddress(methods[0]);
161 if (!IsBuggyBho(mod))
162 return false;
163
164 ScopedComPtr<IDispatch> disp;
165 HRESULT hr = cd->pUnk->QueryInterface(diid,
166 reinterpret_cast<void**>(disp.Receive()));
167 if (FAILED(hr)) // Sometimes only IDispatch QI is supported
168 hr = disp.QueryFrom(cd->pUnk);
169 DCHECK(SUCCEEDED(hr));
170
171 if (SUCCEEDED(hr)) {
172 const int kInvokeIndex = 6;
173 DCHECK(static_cast<IUnknown*>(disp) == cd->pUnk);
174 if (SUCCEEDED(PatchInvokeMethod(&methods[kInvokeIndex]))) {
175 BuggyBhoTls* tls = BuggyBhoTls::FromCurrentThread();
176 DCHECK(tls);
177 if (tls) {
178 tls->AddBuggyObject(disp);
179 }
180 }
181 }
182
183 return false;
184 }
185
186 // static
187 HRESULT BuggyBhoTls::PatchBuggyBHOs(IWebBrowser2* browser) {
188 DCHECK(browser);
189 DCHECK(BuggyBhoTls::FromCurrentThread())
190 << "You must first have an instance of BuggyBhoTls on this thread";
191
192 ScopedComPtr<IConnectionPointContainer> cpc;
193 HRESULT hr = cpc.QueryFrom(browser);
194 if (SUCCEEDED(hr)) {
195 const GUID sinks[] = { DIID_DWebBrowserEvents2, DIID_DWebBrowserEvents };
196 for (size_t i = 0; i < arraysize(sinks); ++i) {
197 ScopedComPtr<IConnectionPoint> cp;
198 cpc->FindConnectionPoint(sinks[i], cp.Receive());
199 if (cp) {
200 ScopedComPtr<IEnumConnections> connections;
201 cp->EnumConnections(connections.Receive());
202 if (connections) {
203 CONNECTDATA cd = {0};
204 DWORD fetched = 0;
205 while (connections->Next(1, &cd, &fetched) == S_OK && fetched) {
206 PatchIfBuggy(&cd, sinks[i]);
207 cd.pUnk->Release();
208 fetched = 0;
209 }
210 }
211 }
212 }
213 }
214
215 return hr; 231 return hr;
216 } 232 }
217 233
218 } // end namespace buggy_bho 234 } // end namespace buggy_bho
OLDNEW
« no previous file with comments | « chrome_frame/buggy_bho_handling.h ('k') | chrome_frame/chrome_active_document.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698