diff options
Diffstat (limited to 'chrome_frame')
-rw-r--r-- | chrome_frame/chrome_active_document.cc | 74 | ||||
-rw-r--r-- | chrome_frame/chrome_active_document.h | 35 | ||||
-rw-r--r-- | chrome_frame/test/util_unittests.cc | 10 | ||||
-rw-r--r-- | chrome_frame/utils.cc | 23 | ||||
-rw-r--r-- | chrome_frame/utils.h | 7 |
5 files changed, 128 insertions, 21 deletions
diff --git a/chrome_frame/chrome_active_document.cc b/chrome_frame/chrome_active_document.cc index fc896a0..bd8d7a4 100644 --- a/chrome_frame/chrome_active_document.cc +++ b/chrome_frame/chrome_active_document.cc @@ -18,6 +18,7 @@ #include "base/command_line.h" #include "base/file_util.h" +#include "base/file_version_info.h" #include "base/logging.h" #include "base/path_service.h" #include "base/process_util.h" @@ -432,7 +433,7 @@ STDMETHODIMP ChromeActiveDocument::Reset() { return S_OK; } -STDMETHODIMP ChromeActiveDocument::GetSize(unsigned long* size) { +STDMETHODIMP ChromeActiveDocument::GetSize(DWORD* size) { if (!size) return E_POINTER; @@ -449,7 +450,7 @@ STDMETHODIMP ChromeActiveDocument::GetPrivacyImpacted(BOOL* privacy_impacted) { } STDMETHODIMP ChromeActiveDocument::Next(BSTR* url, BSTR* policy, - long* reserved, unsigned long* flags) { + LONG* reserved, DWORD* flags) { if (!url || !policy || !flags) return E_POINTER; @@ -754,10 +755,12 @@ void ChromeActiveDocument::UpdateNavigationState( // Now call the FireNavigateCompleteEvent which makes IE update the text // in the address-bar. doc_object_svc->FireNavigateComplete2(this, 0); - doc_object_svc->FireDocumentComplete(this, 0); + if (ShouldFireDocumentComplete()) + doc_object_svc->FireDocumentComplete(this, 0); } else if (web_browser_events_svc) { web_browser_events_svc->FireNavigateComplete2Event(); - web_browser_events_svc->FireDocumentCompleteEvent(); + if (ShouldFireDocumentComplete()) + web_browser_events_svc->FireDocumentCompleteEvent(); } } @@ -916,8 +919,8 @@ HRESULT ChromeActiveDocument::IEExec(const GUID* cmd_group_guid, return hr; } -unsigned long ChromeActiveDocument::MapUrlToZone(const wchar_t* url) { - unsigned long zone = URLZONE_INVALID; +DWORD ChromeActiveDocument::MapUrlToZone(const wchar_t* url) { + DWORD zone = URLZONE_INVALID; if (security_manager_.get() == NULL) { HRESULT hr = CoCreateInstance( CLSID_InternetSecurityManager, @@ -1251,3 +1254,62 @@ LRESULT ChromeActiveDocument::OnFirePrivacyChange(UINT message, WPARAM wparam, NOTREACHED() << "Failed to retrieve IWebBrowser2 interface."; return 0; } + +namespace { +struct ModuleAndVersion { + const char* module_name_; + const uint32 major_version_; + const uint32 minor_version_; +}; +} // end namespace + +// static +bool ChromeActiveDocument::ShouldFireDocumentComplete() { + typedef enum ModuleCheckResult { + CHECK_NOT_DONE, + DOCUMENT_COMPLETE_OK, + DOCUMENT_COMPLETE_NOT_OK + }; + + static ModuleCheckResult results = CHECK_NOT_DONE; + + if (results == CHECK_NOT_DONE) { + // These modules are missing some checks in their DocumentComplete + // implementation that causes a crash. + static const ModuleAndVersion buggy_modules[] = { + { "askbar.dll", 4, 1 }, // biggest troublemaker: 4.1.0.5. + { "gbieh.dll", 3, 8 }, // biggest troublemaker: 3.8.14.12 + { "gbiehcef.dll", 3, 8 }, // biggest troublemaker: 3.8.11.23 + }; + + for (size_t i = 0; results == CHECK_NOT_DONE && + i < arraysize(buggy_modules); ++i) { + const ModuleAndVersion& module = buggy_modules[i]; + HMODULE mod = ::GetModuleHandleA(module.module_name_); + if (mod) { + wchar_t path[MAX_PATH * 2] = {0}; + ::GetModuleFileNameW(mod, path, arraysize(path)); + scoped_ptr<FileVersionInfo> version_info( + FileVersionInfo::CreateFileVersionInfo(FilePath(path))); + DCHECK(version_info.get()); + if (version_info.get()) { + uint32 major = 0, minor = 0; + if (!ParseVersion(version_info->file_version(), &major, &minor)) + ParseVersion(version_info->product_version(), &major, &minor); + if (major < module.major_version_ || + (major == module.major_version_ && + minor <= module.minor_version_)) { + DLOG(WARNING) << "Buggy module found: " << module.module_name_; + results = DOCUMENT_COMPLETE_NOT_OK; + } + } + } + } + + if (results == CHECK_NOT_DONE) + results = DOCUMENT_COMPLETE_OK; + } + + return results == DOCUMENT_COMPLETE_OK; +} + diff --git a/chrome_frame/chrome_active_document.h b/chrome_frame/chrome_active_document.h index 1360ff1..6bd8e4d 100644 --- a/chrome_frame/chrome_active_document.h +++ b/chrome_frame/chrome_active_document.h @@ -9,10 +9,11 @@ #include <atlcom.h> #include <atlctl.h> #include <htiframe.h> -#include <map> #include <mshtmcid.h> #include <perhist.h> +#include <map> + #include "base/scoped_ptr.h" #include "base/scoped_comptr_win.h" #include "base/thread.h" @@ -130,16 +131,16 @@ extern const DWORD kIEEncodingIdArray[]; // This macro should be defined in the public section of the class. #define BEGIN_EXEC_COMMAND_MAP(theClass) \ - public: \ - HRESULT ProcessExecCommand(const GUID* cmd_group_guid, DWORD command_id, \ - DWORD cmd_exec_opt, VARIANT* in_args, \ - VARIANT* out_args) { \ - HRESULT hr = OLECMDERR_E_NOTSUPPORTED; \ - do { + public: \ + HRESULT ProcessExecCommand(const GUID* cmd_group_guid, DWORD command_id, \ + DWORD cmd_exec_opt, VARIANT* in_args, \ + VARIANT* out_args) { \ + HRESULT hr = OLECMDERR_E_NOTSUPPORTED; \ + do { #define EXEC_COMMAND_HANDLER(group, id, handler) \ if ((id == command_id) && ((group != NULL && cmd_group_guid != NULL && \ - IsEqualGUID(*(GUID*)group,*cmd_group_guid)) || \ + IsEqualGUID(*reinterpret_cast<const GUID*>(group), *cmd_group_guid)) || \ (group == NULL && cmd_group_guid == NULL))) { \ hr = S_OK; \ handler(cmd_group_guid, command_id, cmd_exec_opt, in_args, out_args); \ @@ -148,7 +149,7 @@ extern const DWORD kIEEncodingIdArray[]; #define EXEC_COMMAND_HANDLER_NO_ARGS(group, id, handler) \ if ((id == command_id) && ((group != NULL && cmd_group_guid != NULL && \ - IsEqualGUID(*(GUID*)group,*cmd_group_guid)) || \ + IsEqualGUID(*reinterpret_cast<const GUID*>(group), *cmd_group_guid)) || \ (group == NULL && cmd_group_guid == NULL))) { \ hr = S_OK; \ handler(); \ @@ -157,7 +158,7 @@ extern const DWORD kIEEncodingIdArray[]; #define EXEC_COMMAND_HANDLER_GENERIC(group, id, code) \ if ((id == command_id) && ((group != NULL && cmd_group_guid != NULL && \ - IsEqualGUID(*(GUID*)group,*cmd_group_guid)) || \ + IsEqualGUID(*reinterpret_cast<const GUID*>(group), *cmd_group_guid)) || \ (group == NULL && cmd_group_guid == NULL))) { \ hr = S_OK; \ code; \ @@ -176,7 +177,8 @@ extern const DWORD kIEEncodingIdArray[]; commands++; \ } \ if (id_in_group_commands && ((group != NULL && cmd_group_guid != NULL && \ - IsEqualGUID(*(GUID*)group,*cmd_group_guid)) || \ + IsEqualGUID(*reinterpret_cast<const GUID*>(group), \ + *cmd_group_guid)) || \ (group == NULL && cmd_group_guid == NULL))) { \ hr = S_OK; \ handler(cmd_group_guid, command_id, cmd_exec_opt, in_args, out_args); \ @@ -343,10 +345,9 @@ END_EXEC_COMMAND_MAP() // IEnumPrivacyRecords STDMETHOD(Reset)(); - STDMETHOD(GetSize)(unsigned long* size); + STDMETHOD(GetSize)(ULONG* size); STDMETHOD(GetPrivacyImpacted)(BOOL* privacy_impacted); - STDMETHOD(Next)(BSTR* url, BSTR* policy, long* reserved, - unsigned long* flags); + STDMETHOD(Next)(BSTR* url, BSTR* policy, LONG* reserved, DWORD* flags); protected: // ChromeFrameActivexBase overrides @@ -379,7 +380,7 @@ END_EXEC_COMMAND_MAP() HRESULT IEExec(const GUID* cmd_group_guid, DWORD command_id, DWORD cmd_exec_opt, VARIANT* in_args, VARIANT* out_args); - unsigned long MapUrlToZone(const wchar_t* url); + DWORD MapUrlToZone(const wchar_t* url); // Parses the URL and returns information whether it is a new navigation and // the actual url after stripping out the cf: prefix if any. @@ -421,6 +422,10 @@ END_EXEC_COMMAND_MAP() LRESULT OnFirePrivacyChange(UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled); + // Checks for the presence of known-to-be-buggy BHOs. If we find any + // we do not fire the DocumentComplete event to avoid a crash. + static bool ShouldFireDocumentComplete(); + protected: typedef std::map<int, bool> EnabledCommandsMap; diff --git a/chrome_frame/test/util_unittests.cc b/chrome_frame/test/util_unittests.cc index 0187f5d..cedff5d 100644 --- a/chrome_frame/test/util_unittests.cc +++ b/chrome_frame/test/util_unittests.cc @@ -137,3 +137,13 @@ TEST(UtilTests, ParseAttachTabUrlTest) { &disposition)); } +TEST(UtilTests, ParseVersionTest) { + uint32 high = 0, low = 0; + EXPECT_FALSE(ParseVersion(L"", &high, &low)); + EXPECT_TRUE(ParseVersion(L"1", &high, &low) && high == 1 && low == 0); + EXPECT_TRUE(ParseVersion(L"1.", &high, &low) && high == 1 && low == 0); + EXPECT_TRUE(ParseVersion(L"1.2", &high, &low) && high == 1 && low == 2); + EXPECT_TRUE(ParseVersion(L"1.2.3.4", &high, &low) && high == 1 && low == 2); + EXPECT_TRUE(ParseVersion(L"10.20", &high, &low) && high == 10 && low == 20); +} + diff --git a/chrome_frame/utils.cc b/chrome_frame/utils.cc index a864200..6a9d0a2 100644 --- a/chrome_frame/utils.cc +++ b/chrome_frame/utils.cc @@ -534,6 +534,29 @@ bool GetModuleVersion(HMODULE module, uint32* high, uint32* low) { return ok; } +bool ParseVersion(const std::wstring& version, uint32* high, uint32* low) { + DCHECK(high); + if (!isdigit(version[0])) + return false; + + *high = _wtoi(version.c_str()); + if (low) { + *low = 0; + size_t i = version.find(L'.'); + if (i != std::wstring::npos) { + *low = _wtoi(version.c_str() + i + 1); + } + } + + return true; +} + +HMODULE GetModuleFromAddress(void* address) { + MEMORY_BASIC_INFORMATION info = {0}; + ::VirtualQuery(address, &info, sizeof(info)); + return reinterpret_cast<HMODULE>(info.AllocationBase); +} + namespace { const int kMaxSubmenuDepth = 10; diff --git a/chrome_frame/utils.h b/chrome_frame/utils.h index 11b050d..5561331 100644 --- a/chrome_frame/utils.h +++ b/chrome_frame/utils.h @@ -189,6 +189,13 @@ FilePath GetIETemporaryFilesFolder(); // @returns true if the version info was successfully retrieved. bool GetModuleVersion(HMODULE module, uint32* high, uint32* low); +// Parses a version string and returns the major, minor versions or 0 if not +// present in the string. The rest of the version string is ignored. +bool ParseVersion(const std::wstring& version, uint32* high, uint32* low); + +// @returns the module handle to which an address belongs. +HMODULE GetModuleFromAddress(void* address); + // Return if the IEXPLORE is in private mode. The IEIsInPrivateBrowsing() checks // whether current process is IEXPLORE. bool IsIEInPrivate(); |