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

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
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 DCHECK(BuggyBhoTls::GetInstance() == NULL);
tommi (sloooow) - chröme 2011/02/11 19:34:15 lint will probably ask you to use DCHECK_EQ here a
ananta 2011/02/11 21:19:35 DCHECK_EQ would need a reintepret_cast. I left thi
79 s_bad_object_tls_.Set(this); 80 s_bad_object_tls_.Set(this);
80 } 81 }
81 82
82 BuggyBhoTls::~BuggyBhoTls() { 83 BuggyBhoTls::~BuggyBhoTls() {
83 DCHECK(FromCurrentThread() == this); 84 DCHECK(BuggyBhoTls::GetInstance() == this);
84 s_bad_object_tls_.Set(previous_instance_); 85 s_bad_object_tls_.Set(NULL);
85 } 86 }
86 87
87 void BuggyBhoTls::AddBuggyObject(IDispatch* obj) { 88 void BuggyBhoTls::AddBuggyObject(IDispatch* obj) {
88 bad_objects_.push_back(obj); 89 bad_objects_.push_back(obj);
89 } 90 }
90 91
91 bool BuggyBhoTls::IsBuggyObject(IDispatch* obj) const { 92 bool BuggyBhoTls::ShouldSkipInvoke(IDispatch* obj) const {
92 return std::find(bad_objects_.begin(), bad_objects_.end(), obj) != 93 DCHECK(web_browser2_ != NULL);
93 bad_objects_.end(); 94 if (IsChromeFrameDocument(web_browser2_)) {
95 return std::find(bad_objects_.begin(), bad_objects_.end(), obj) !=
96 bad_objects_.end();
97 }
98 return false;
94 } 99 }
95 100
96 // static 101 // static
97 BuggyBhoTls* BuggyBhoTls::FromCurrentThread() { 102 BuggyBhoTls* BuggyBhoTls::GetInstance() {
98 return s_bad_object_tls_.Get(); 103 BuggyBhoTls* tls_instance = s_bad_object_tls_.Get();
104 if (!tls_instance) {
105 tls_instance = new BuggyBhoTls();
106 DCHECK(s_bad_object_tls_.Get() != NULL);
107 }
108 return tls_instance;
109 }
110
111 // static
112 void BuggyBhoTls::DestroyInstance() {
113 BuggyBhoTls* tls_instance = s_bad_object_tls_.Get();
114 if (tls_instance) {
115 delete tls_instance;
tommi (sloooow) - chröme 2011/02/11 19:34:15 also set s_bad_object_tls to NULL
ananta 2011/02/11 21:19:35 That happens in the destructor. Added a DCHECK aft
116 }
117 }
118
119 HRESULT BuggyBhoTls::PatchBuggyBHOs(IWebBrowser2* browser) {
120 DCHECK(browser);
tommi (sloooow) - chröme 2011/02/11 19:34:15 should we also dcheck that web_browser2_ is NULL?
ananta 2011/02/11 21:19:35 Done.
121
122 ScopedComPtr<IConnectionPointContainer> cpc;
123 HRESULT hr = cpc.QueryFrom(browser);
124 if (SUCCEEDED(hr)) {
125 const GUID sinks[] = { DIID_DWebBrowserEvents2, DIID_DWebBrowserEvents };
126 for (size_t i = 0; i < arraysize(sinks); ++i) {
127 ScopedComPtr<IConnectionPoint> cp;
128 cpc->FindConnectionPoint(sinks[i], cp.Receive());
129 if (cp) {
130 ScopedComPtr<IEnumConnections> connections;
131 cp->EnumConnections(connections.Receive());
132 if (connections) {
133 CONNECTDATA cd = {0};
134 DWORD fetched = 0;
135 while (connections->Next(1, &cd, &fetched) == S_OK && fetched) {
136 PatchIfBuggy(&cd, sinks[i]);
137 cd.pUnk->Release();
138 fetched = 0;
139 }
140 }
141 }
142 }
143 }
144 web_browser2_ = browser;
145 return hr;
146 }
147
148 bool BuggyBhoTls::PatchIfBuggy(CONNECTDATA* cd, const IID& diid) {
amit 2011/02/11 19:49:40 nit: why not pass cd->punk directly?
ananta 2011/02/11 21:19:35 Done.
149 DCHECK(cd);
150 PROC* methods = *reinterpret_cast<PROC**>(cd->pUnk);
151 HMODULE mod = GetModuleFromAddress(methods[0]);
152 if (!IsBuggyBho(mod))
153 return false;
154
155 ScopedComPtr<IDispatch> disp;
156 HRESULT hr = cd->pUnk->QueryInterface(diid,
157 reinterpret_cast<void**>(disp.Receive()));
158 if (FAILED(hr)) // Sometimes only IDispatch QI is supported
159 hr = disp.QueryFrom(cd->pUnk);
160 DCHECK(SUCCEEDED(hr));
161
162 if (SUCCEEDED(hr)) {
163 const int kInvokeIndex = 6;
164 DCHECK(static_cast<IUnknown*>(disp) == cd->pUnk);
165 if (SUCCEEDED(PatchInvokeMethod(&methods[kInvokeIndex]))) {
166 AddBuggyObject(disp);
167 }
168 }
169 return false;
99 } 170 }
100 171
101 // static 172 // static
102 STDMETHODIMP BuggyBhoTls::BuggyBhoInvoke(InvokeFunc original, IDispatch* me, 173 STDMETHODIMP BuggyBhoTls::BuggyBhoInvoke(InvokeFunc original, IDispatch* me,
103 DISPID dispid, REFIID riid, LCID lcid, 174 DISPID dispid, REFIID riid, LCID lcid,
104 WORD flags, DISPPARAMS* params, 175 WORD flags, DISPPARAMS* params,
105 VARIANT* result, EXCEPINFO* ei, 176 VARIANT* result, EXCEPINFO* ei,
106 UINT* err) { 177 UINT* err) {
107 DVLOG(1) << __FUNCTION__; 178 DVLOG(1) << __FUNCTION__;
108 179
109 const BuggyBhoTls* tls = BuggyBhoTls::FromCurrentThread(); 180 DCHECK(BuggyBhoTls::GetInstance())
110 if (tls && tls->IsBuggyObject(me)) { 181 << "You must first have an instance of BuggyBhoTls on this thread";
182 if (BuggyBhoTls::GetInstance() &&
amit 2011/02/11 19:49:40 Maybe we can avoid the TLS altogether with followi
183 BuggyBhoTls::GetInstance()->ShouldSkipInvoke(me)) {
111 // Ignore this call and avoid the bug. 184 // Ignore this call and avoid the bug.
112 // TODO(tommi): Maybe we should check a specific list of DISPIDs too? 185 // TODO(tommi): Maybe we should check a specific list of DISPIDs too?
113 return S_OK; 186 return S_OK;
114 } 187 }
115 188
116 // No need to report crashes in those known-to-be-buggy DLLs. 189 // No need to report crashes in those known-to-be-buggy DLLs.
117 ExceptionBarrierReportOnlyModule barrier; 190 ExceptionBarrierReportOnlyModule barrier;
118 return original(me, dispid, riid, lcid, flags, params, result, ei, err); 191 return original(me, dispid, riid, lcid, flags, params, result, ei, err);
119 } 192 }
120 193
(...skipping 19 matching lines...) Expand all
140 if (!vtable_patch::internal::ReplaceFunctionPointer( 213 if (!vtable_patch::internal::ReplaceFunctionPointer(
141 reinterpret_cast<void**>(invoke), stub->code(), 214 reinterpret_cast<void**>(invoke), stub->code(),
142 reinterpret_cast<void*>(stub->argument()))) { 215 reinterpret_cast<void*>(stub->argument()))) {
143 hr = E_UNEXPECTED; 216 hr = E_UNEXPECTED;
144 FunctionStub::Destroy(stub); 217 FunctionStub::Destroy(stub);
145 } else { 218 } else {
146 PinModule(); // No backing out now. 219 PinModule(); // No backing out now.
147 ::FlushInstructionCache(::GetCurrentProcess(), invoke, sizeof(PROC)); 220 ::FlushInstructionCache(::GetCurrentProcess(), invoke, sizeof(PROC));
148 } 221 }
149 } 222 }
150
151 ::VirtualProtect(invoke, sizeof(PROC), flags, &flags); 223 ::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; 224 return hr;
216 } 225 }
217 226
218 } // end namespace buggy_bho 227 } // end namespace buggy_bho
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698