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

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/lazy_instance.h"
8 #include "base/scoped_comptr_win.h" 8 #include "base/scoped_comptr_win.h"
9
10 #include "chrome_frame/exception_barrier.h" 9 #include "chrome_frame/exception_barrier.h"
11 #include "chrome_frame/function_stub.h" 10 #include "chrome_frame/function_stub.h"
11 #include "chrome_frame/urlmon_moniker.h"
12 #include "chrome_frame/utils.h" 12 #include "chrome_frame/utils.h"
13 #include "chrome_frame/vtable_patch_manager.h" 13 #include "chrome_frame/vtable_patch_manager.h"
14 14
15 namespace buggy_bho { 15 namespace buggy_bho {
16 16
17 base::ThreadLocalPointer<BuggyBhoTls> BuggyBhoTls::s_bad_object_tls_; 17 base::LazyInstance<BuggyBhoHandler>
18 g_buggy_bho_handler(base::LINKER_INITIALIZED);
18 19
19 struct ModuleAndVersion { 20 struct ModuleAndVersion {
20 const char* module_name_; 21 const char* module_name_;
21 const uint32 major_version_; 22 const uint32 major_version_;
22 const uint32 minor_version_; 23 const uint32 minor_version_;
23 }; 24 };
24 25
25 const ModuleAndVersion kBuggyModules[] = { 26 const ModuleAndVersion kBuggyModules[] = {
26 { "askbar.dll", 4, 1 }, // troublemaker: 4.1.0.5. 27 { "askbar.dll", 4, 1 }, // troublemaker: 4.1.0.5.
27 { "gbieh.dll", 3, 8 }, // troublemaker: 3.8.14.12 28 { "gbieh.dll", 3, 8 }, // troublemaker: 3.8.14.12
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 (HIWORD(version) == buggy.major_version_ && 69 (HIWORD(version) == buggy.major_version_ &&
69 LOWORD(version) <= buggy.minor_version_)) { 70 LOWORD(version) <= buggy.minor_version_)) {
70 return true; 71 return true;
71 } 72 }
72 } 73 }
73 } 74 }
74 75
75 return false; 76 return false;
76 } 77 }
77 78
78 BuggyBhoTls::BuggyBhoTls() : previous_instance_(s_bad_object_tls_.Get()) { 79 BuggyBhoHandler::BuggyBhoHandler() {
79 s_bad_object_tls_.Set(this);
80 } 80 }
81 81
82 BuggyBhoTls::~BuggyBhoTls() { 82 BuggyBhoHandler::~BuggyBhoHandler() {
83 DCHECK(FromCurrentThread() == this);
84 s_bad_object_tls_.Set(previous_instance_);
85 } 83 }
86 84
87 void BuggyBhoTls::AddBuggyObject(IDispatch* obj) { 85 BuggyBhoHandler* BuggyBhoHandler::GetInstance() {
88 bad_objects_.push_back(obj); 86 return g_buggy_bho_handler.Pointer();
89 } 87 }
90 88
91 bool BuggyBhoTls::IsBuggyObject(IDispatch* obj) const { 89 void BuggyBhoHandler::ClearBuggyObjectsForThread(
92 return std::find(bad_objects_.begin(), bad_objects_.end(), obj) != 90 base::PlatformThreadId thread_id) {
93 bad_objects_.end(); 91 DCHECK(GetInstance())
92 << "You must first have an instance of BuggyBhoHandler.";
93
94 base::AutoLock lock(GetInstance()->lock_);
tommi (sloooow) - chröme 2011/02/11 14:49:02 If you store the object list in the tls, you would
95
96 std::vector<ObjectInfo>::iterator index =
97 GetInstance()->bad_objects_.begin();
98 while (index != GetInstance()->bad_objects_.end()) {
99 if (index->object_thread_id == thread_id) {
100 index = GetInstance()->bad_objects_.erase(index);
101 } else {
102 ++index;
103 }
104 }
105 }
106
107 void BuggyBhoHandler::AddBuggyObject(IDispatch* obj) {
108 base::AutoLock lock(lock_);
109 ObjectInfo object_info;
110 object_info.disp_interface = obj;
111 object_info.object_thread_id = base::PlatformThread::CurrentId();
112 bad_objects_.push_back(object_info);
113 }
114
115 bool BuggyBhoHandler::ShouldSkipInvoke(IDispatch* obj) {
116 NavigationManager* navigation_mgr = NavigationManager::GetThreadInstance();
117 DCHECK(navigation_mgr);
118 if (navigation_mgr && IsChromeFrameDocument(navigation_mgr->web_browser())) {
119 base::AutoLock lock(lock_);
120 std::vector<ObjectInfo>::iterator index;
121 for (index = bad_objects_.begin(); index != bad_objects_.end(); ++index) {
122 if (index->disp_interface == obj)
123 return true;
124 }
125 }
126 return false;
94 } 127 }
95 128
96 // static 129 // static
97 BuggyBhoTls* BuggyBhoTls::FromCurrentThread() { 130 STDMETHODIMP BuggyBhoHandler::BuggyBhoInvoke(InvokeFunc original, IDispatch* me,
98 return s_bad_object_tls_.Get();
99 }
100
101 // static
102 STDMETHODIMP BuggyBhoTls::BuggyBhoInvoke(InvokeFunc original, IDispatch* me,
103 DISPID dispid, REFIID riid, LCID lcid, 131 DISPID dispid, REFIID riid, LCID lcid,
104 WORD flags, DISPPARAMS* params, 132 WORD flags, DISPPARAMS* params,
105 VARIANT* result, EXCEPINFO* ei, 133 VARIANT* result, EXCEPINFO* ei,
106 UINT* err) { 134 UINT* err) {
107 DVLOG(1) << __FUNCTION__; 135 DVLOG(1) << __FUNCTION__;
108 136
109 const BuggyBhoTls* tls = BuggyBhoTls::FromCurrentThread(); 137 DCHECK(GetInstance())
110 if (tls && tls->IsBuggyObject(me)) { 138 << "You must first have an instance of BuggyBhoHandler.";
139
140 if (GetInstance()->ShouldSkipInvoke(me)) {
111 // Ignore this call and avoid the bug. 141 // Ignore this call and avoid the bug.
112 // TODO(tommi): Maybe we should check a specific list of DISPIDs too? 142 // TODO(tommi): Maybe we should check a specific list of DISPIDs too?
113 return S_OK; 143 return S_OK;
114 } 144 }
115 145
116 // No need to report crashes in those known-to-be-buggy DLLs. 146 // No need to report crashes in those known-to-be-buggy DLLs.
117 ExceptionBarrierReportOnlyModule barrier; 147 ExceptionBarrierReportOnlyModule barrier;
118 return original(me, dispid, riid, lcid, flags, params, result, ei, err); 148 return original(me, dispid, riid, lcid, flags, params, result, ei, err);
119 } 149 }
120 150
121 // static 151 // static
122 HRESULT BuggyBhoTls::PatchInvokeMethod(PROC* invoke) { 152 HRESULT BuggyBhoHandler::PatchInvokeMethod(PROC* invoke) {
123 CCritSecLock lock(_pAtlModule->m_csStaticDataInitAndTypeInfo.m_sec, true); 153 CCritSecLock lock(_pAtlModule->m_csStaticDataInitAndTypeInfo.m_sec, true);
124 154
125 FunctionStub* stub = FunctionStub::FromCode(*invoke); 155 FunctionStub* stub = FunctionStub::FromCode(*invoke);
126 if (stub) 156 if (stub)
127 return S_FALSE; 157 return S_FALSE;
128 158
129 DWORD flags = 0; 159 DWORD flags = 0;
130 if (!::VirtualProtect(invoke, sizeof(PROC), PAGE_EXECUTE_READWRITE, &flags)) 160 if (!::VirtualProtect(invoke, sizeof(PROC), PAGE_EXECUTE_READWRITE, &flags))
131 return AtlHresultFromLastError(); 161 return AtlHresultFromLastError();
132 162
(...skipping 14 matching lines...) Expand all
147 ::FlushInstructionCache(::GetCurrentProcess(), invoke, sizeof(PROC)); 177 ::FlushInstructionCache(::GetCurrentProcess(), invoke, sizeof(PROC));
148 } 178 }
149 } 179 }
150 180
151 ::VirtualProtect(invoke, sizeof(PROC), flags, &flags); 181 ::VirtualProtect(invoke, sizeof(PROC), flags, &flags);
152 182
153 return hr; 183 return hr;
154 } 184 }
155 185
156 // static 186 // static
157 bool BuggyBhoTls::PatchIfBuggy(CONNECTDATA* cd, const IID& diid) { 187 bool BuggyBhoHandler::PatchIfBuggy(CONNECTDATA* cd, const IID& diid) {
158 DCHECK(cd); 188 DCHECK(cd);
159 PROC* methods = *reinterpret_cast<PROC**>(cd->pUnk); 189 PROC* methods = *reinterpret_cast<PROC**>(cd->pUnk);
160 HMODULE mod = GetModuleFromAddress(methods[0]); 190 HMODULE mod = GetModuleFromAddress(methods[0]);
161 if (!IsBuggyBho(mod)) 191 if (!IsBuggyBho(mod))
162 return false; 192 return false;
163 193
164 ScopedComPtr<IDispatch> disp; 194 ScopedComPtr<IDispatch> disp;
165 HRESULT hr = cd->pUnk->QueryInterface(diid, 195 HRESULT hr = cd->pUnk->QueryInterface(diid,
166 reinterpret_cast<void**>(disp.Receive())); 196 reinterpret_cast<void**>(disp.Receive()));
167 if (FAILED(hr)) // Sometimes only IDispatch QI is supported 197 if (FAILED(hr)) // Sometimes only IDispatch QI is supported
168 hr = disp.QueryFrom(cd->pUnk); 198 hr = disp.QueryFrom(cd->pUnk);
169 DCHECK(SUCCEEDED(hr)); 199 DCHECK(SUCCEEDED(hr));
170 200
171 if (SUCCEEDED(hr)) { 201 if (SUCCEEDED(hr)) {
172 const int kInvokeIndex = 6; 202 const int kInvokeIndex = 6;
173 DCHECK(static_cast<IUnknown*>(disp) == cd->pUnk); 203 DCHECK(static_cast<IUnknown*>(disp) == cd->pUnk);
174 if (SUCCEEDED(PatchInvokeMethod(&methods[kInvokeIndex]))) { 204 if (SUCCEEDED(PatchInvokeMethod(&methods[kInvokeIndex]))) {
175 BuggyBhoTls* tls = BuggyBhoTls::FromCurrentThread(); 205 BuggyBhoHandler* instance = GetInstance();
176 DCHECK(tls); 206 DCHECK(instance);
177 if (tls) { 207 instance->AddBuggyObject(disp);
178 tls->AddBuggyObject(disp);
179 }
180 } 208 }
181 } 209 }
182 210
183 return false; 211 return false;
184 } 212 }
185 213
186 // static 214 // static
187 HRESULT BuggyBhoTls::PatchBuggyBHOs(IWebBrowser2* browser) { 215 HRESULT BuggyBhoHandler::PatchBuggyBHOs(IWebBrowser2* browser) {
188 DCHECK(browser); 216 DCHECK(browser);
189 DCHECK(BuggyBhoTls::FromCurrentThread()) 217 DCHECK(GetInstance())
190 << "You must first have an instance of BuggyBhoTls on this thread"; 218 << "You must first have an instance of BuggyBhoHandler.";
219 // Serialized as we could be called from multiple threads and the same BHO
220 // could be loaded in multiple IE windows.
221 base::AutoLock lock(GetInstance()->lock_);
191 222
192 ScopedComPtr<IConnectionPointContainer> cpc; 223 ScopedComPtr<IConnectionPointContainer> cpc;
193 HRESULT hr = cpc.QueryFrom(browser); 224 HRESULT hr = cpc.QueryFrom(browser);
194 if (SUCCEEDED(hr)) { 225 if (SUCCEEDED(hr)) {
195 const GUID sinks[] = { DIID_DWebBrowserEvents2, DIID_DWebBrowserEvents }; 226 const GUID sinks[] = { DIID_DWebBrowserEvents2, DIID_DWebBrowserEvents };
196 for (size_t i = 0; i < arraysize(sinks); ++i) { 227 for (size_t i = 0; i < arraysize(sinks); ++i) {
197 ScopedComPtr<IConnectionPoint> cp; 228 ScopedComPtr<IConnectionPoint> cp;
198 cpc->FindConnectionPoint(sinks[i], cp.Receive()); 229 cpc->FindConnectionPoint(sinks[i], cp.Receive());
199 if (cp) { 230 if (cp) {
200 ScopedComPtr<IEnumConnections> connections; 231 ScopedComPtr<IEnumConnections> connections;
201 cp->EnumConnections(connections.Receive()); 232 cp->EnumConnections(connections.Receive());
202 if (connections) { 233 if (connections) {
203 CONNECTDATA cd = {0}; 234 CONNECTDATA cd = {0};
204 DWORD fetched = 0; 235 DWORD fetched = 0;
205 while (connections->Next(1, &cd, &fetched) == S_OK && fetched) { 236 while (connections->Next(1, &cd, &fetched) == S_OK && fetched) {
206 PatchIfBuggy(&cd, sinks[i]); 237 PatchIfBuggy(&cd, sinks[i]);
207 cd.pUnk->Release(); 238 cd.pUnk->Release();
208 fetched = 0; 239 fetched = 0;
209 } 240 }
210 } 241 }
211 } 242 }
212 } 243 }
213 } 244 }
214
215 return hr; 245 return hr;
216 } 246 }
217 247
218 } // end namespace buggy_bho 248 } // end namespace buggy_bho
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698