diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/app/delay_load_hook_unittest_win.cc | 90 | ||||
-rw-r--r-- | chrome/app/delay_load_hook_win.cc | 84 | ||||
-rw-r--r-- | chrome/app/delay_load_hook_win.h | 17 | ||||
-rw-r--r-- | chrome/chrome.gyp | 21 | ||||
-rw-r--r-- | chrome/chrome.user32.delay.imports | 29 | ||||
-rw-r--r-- | chrome/chrome_dll.gypi | 39 | ||||
-rw-r--r-- | chrome/chrome_tests_unit.gypi | 3 |
7 files changed, 283 insertions, 0 deletions
diff --git a/chrome/app/delay_load_hook_unittest_win.cc b/chrome/app/delay_load_hook_unittest_win.cc new file mode 100644 index 0000000..e599e79 --- /dev/null +++ b/chrome/app/delay_load_hook_unittest_win.cc @@ -0,0 +1,90 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <windows.h> +#if defined(_WIN32_WINNT_WIN8) && _MSC_VER < 1700 +// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h, and in +// delayimp.h previous to VS2012. +#undef FACILITY_VISUALCPP +#endif +#include <DelayIMP.h> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/scoped_native_library.h" +#include "chrome/app/delay_load_hook_win.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class ChromeDelayLoadHookTest : public testing::Test { + public: + ChromeDelayLoadHookTest() : proc_ptr_(NULL) { + } + + virtual void SetUp() OVERRIDE { + SetupInfo("kernel32.dll"); + } + + void SetupInfo(const char* dll_name) { + info_.cb = sizeof(info_); + info_.pidd = NULL; + info_.ppfn = &proc_ptr_; + info_.szDll = dll_name; + info_.dlp.fImportByName = TRUE; + info_.dlp.szProcName = "CreateFileA"; + info_.hmodCur = NULL; + info_.pfnCur = NULL; + info_.dwLastError = 0; + } + + FARPROC proc_ptr_; + DelayLoadInfo info_; +}; + +} // namespace + +TEST_F(ChromeDelayLoadHookTest, HooksAreSetAtLinkTime) { + // This test verifies that referencing the ChromeDelayLoadHook at link + // time results in overriding the delay loader's hook instances in the CRT + // ropriately. + EXPECT_TRUE(__pfnDliNotifyHook2 == ChromeDelayLoadHook); + EXPECT_TRUE(__pfnDliFailureHook2 == ChromeDelayLoadHook); +} + +TEST_F(ChromeDelayLoadHookTest, NonSuffixedDllsAreNotHandled) { + // The hook should ignore non-suffixed DLLs. + SetupInfo("kernel32.dll"); + + HMODULE none = reinterpret_cast<HMODULE>( + ChromeDelayLoadHook(dliNotePreLoadLibrary, &info_)); + // Make sure the library is released on exit. + base::ScopedNativeLibrary lib_holder(none); + + ASSERT_TRUE(none == NULL); +} + +TEST_F(ChromeDelayLoadHookTest, SuffixedDllsAreRedirected) { + // Check that a DLL name of the form "foo-delay.dll" gets redirected to + // the "foo.dll". + SetupInfo("kernel32-delay.dll"); + HMODULE kernel32 = reinterpret_cast<HMODULE>( + ChromeDelayLoadHook(dliNotePreLoadLibrary, &info_)); + + // Make sure the library is released on exit. + base::ScopedNativeLibrary lib_holder(kernel32); + + ASSERT_TRUE(kernel32 == ::GetModuleHandle(L"kernel32.dll")); +} + +TEST_F(ChromeDelayLoadHookTest, IgnoresUnhandledNotifications) { + SetupInfo("kernel32-delay.dll"); + + // The hook should ignore all notifications but the preload notifications. + EXPECT_TRUE(ChromeDelayLoadHook(dliNoteStartProcessing, &info_) == NULL); + EXPECT_TRUE(ChromeDelayLoadHook(dliNotePreGetProcAddress, &info_) == NULL); + EXPECT_TRUE(ChromeDelayLoadHook(dliNoteEndProcessing, &info_) == NULL); + EXPECT_TRUE(ChromeDelayLoadHook(dliFailLoadLib, &info_) == NULL); + EXPECT_TRUE(ChromeDelayLoadHook(dliFailGetProc, &info_) == NULL); +} diff --git a/chrome/app/delay_load_hook_win.cc b/chrome/app/delay_load_hook_win.cc new file mode 100644 index 0000000..e911cc4 --- /dev/null +++ b/chrome/app/delay_load_hook_win.cc @@ -0,0 +1,84 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/app/delay_load_hook_win.h" + +#if defined(_WIN32_WINNT_WIN8) && _MSC_VER < 1700 +// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h, and in +// delayimp.h previous to VS2012. +#undef FACILITY_VISUALCPP +#endif +#include <DelayIMP.h> + +#include "base/logging.h" +#include "base/string_util.h" +#include "base/stringprintf.h" + +// So long as these symbols are supplied to the final binary through an +// object file (as opposed to indirectly through a library), these pointers +// will override the CRT's symbols and direct the notifications to our hook. +// Alternatively referencing the ChromeDelayLoadHook function somehow will +// cause this declaration of these variables to take preference to the delay +// load runtime's defaults (in delayimp.lib). +PfnDliHook __pfnDliNotifyHook2 = ChromeDelayLoadHook; +PfnDliHook __pfnDliFailureHook2 = ChromeDelayLoadHook; + + +namespace { + +FARPROC OnPreLoadLibrary(DelayLoadInfo* info) { + // If the DLL name ends with "-delay.dll", this call is about one of our + // custom import libraries. In this case we need to snip the suffix off, + // and bind to the real DLL. + std::string dll_name(info->szDll); + const char kDelaySuffix[] = "-delay.dll"; + if (EndsWith(dll_name, kDelaySuffix, false)) { + // Trim the "-delay.dll" suffix from the string. + dll_name.resize(dll_name.length() - (sizeof(kDelaySuffix) - 1)); + dll_name.append(".dll"); + + return reinterpret_cast<FARPROC>(::LoadLibraryA(dll_name.c_str())); + } + + return NULL; +} + +} // namespace + +// This function is a delay load notification hook. It is invoked by the +// delay load support in the visual studio runtime. +// See http://msdn.microsoft.com/en-us/library/z9h1h6ty(v=vs.100).aspx for +// details. +FARPROC WINAPI ChromeDelayLoadHook(unsigned reason, DelayLoadInfo* info) { + switch (reason) { + case dliNoteStartProcessing: + case dliNoteEndProcessing: + // Nothing to do here. + break; + + case dliNotePreLoadLibrary: + return OnPreLoadLibrary(info); + break; + + case dliNotePreGetProcAddress: + // Nothing to do here. + break; + + case dliFailLoadLib: + case dliFailGetProc: + // Returning NULL from error notifications will cause the delay load + // runtime to raise a VcppException structured exception, that some code + // might want to handle. + return NULL; + break; + + default: + NOTREACHED() << "Impossible delay load notification."; + break; + } + + // Returning NULL causes the delay load machinery to perform default + // processing for this notification. + return NULL; +} diff --git a/chrome/app/delay_load_hook_win.h b/chrome/app/delay_load_hook_win.h new file mode 100644 index 0000000..44174ee --- /dev/null +++ b/chrome/app/delay_load_hook_win.h @@ -0,0 +1,17 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_APP_DELAY_LOAD_HOOK_WIN_H_ +#define CHROME_APP_DELAY_LOAD_HOOK_WIN_H_ + +#include <windows.h> + +// Fowd. +struct DelayLoadInfo; + +// In release builds, the delay load hook redirects import entries to DLLs +// named "FOO-delay.dll" to "FOO.dll". +FARPROC WINAPI ChromeDelayLoadHook(unsigned reason, DelayLoadInfo* info); + +#endif // CHROME_APP_DELAY_LOAD_HOOK_WIN_H_ diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index f181d4d..be44f74 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -1040,6 +1040,27 @@ ['OS=="win" and target_arch=="ia32"', { 'targets': [ { + 'target_name': 'chrome_user32_delay_imports', + 'type': 'none', + 'variables': { + 'lib_dir': '<(INTERMEDIATE_DIR)', + }, + 'sources': [ + 'chrome.user32.delay.imports' + ], + 'includes': [ + '../build/win/importlibs/create_import_lib.gypi', + ], + 'direct_dependent_settings': { + 'msvs_settings': { + 'VCLinkerTool': { + 'AdditionalLibraryDirectories': ['<(lib_dir)', ], + 'AdditionalDependencies': ['chrome.user32.delay.lib', ], + }, + }, + }, + }, + { 'target_name': 'crash_service_win64', 'type': 'executable', 'product_name': 'crash_service64', diff --git a/chrome/chrome.user32.delay.imports b/chrome/chrome.user32.delay.imports new file mode 100644 index 0000000..baa1231 --- /dev/null +++ b/chrome/chrome.user32.delay.imports @@ -0,0 +1,29 @@ +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# This file is used to create a custom import library for Chrome.dll's use of +# user32.dll APIs added post-Windows XP to obviate the need for delay loading +# all of user32.dll. +{ + 'architecture': 'x86', + + # The DLL to bind to - we delay load these imports. + 'dll_name': 'user32-delay.dll', + + # Name of the generated import library. + 'importlib_name': 'chrome.user32.delay.lib', + + # Chrome.dll uses these post-Windows XP (SP2) exports, and so they must be + # delay loaded for Chrome.dll to load on Windows XP computers. + 'imports': [ + 'CloseGestureInfoHandle@4', + 'CloseTouchInputHandle@4', + 'GetGestureInfo@8', + 'GetTouchInputInfo@16', + 'IsTouchWindow@8', + 'RegisterTouchWindow@8', + 'SetGestureConfig@20', + 'UnregisterTouchWindow@4', + ], +} diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi index 8f5aab4..fe6c2ee6 100644 --- a/chrome/chrome_dll.gypi +++ b/chrome/chrome_dll.gypi @@ -88,6 +88,13 @@ '<(SHARED_INTERMEDIATE_DIR)/ash/ash_resources/ash_wallpaper_resources.rc', ], }], + ['OS=="win" and target_arch=="ia32"', { + # Add a dependency to custom import library for user32 delay + # imports only in x86 builds. + 'dependencies': [ + 'chrome_user32_delay_imports', + ], + },], ['OS=="win"', { 'product_name': 'chrome', 'dependencies': [ @@ -112,6 +119,8 @@ 'app/chrome_main.cc', 'app/chrome_main_delegate.cc', 'app/chrome_main_delegate.h', + 'app/delay_load_hook_win.cc', + 'app/delay_load_hook_win.h', '<(SHARED_INTERMEDIATE_DIR)/chrome_version/chrome_dll_version.rc', '../base/win/dllmain.cc', @@ -169,6 +178,36 @@ 'OutputFile': '$(OutDir)\\initial\\chrome.dll', 'UseLibraryDependencyInputs': "true", }], + ['target_arch=="ia32"', { + # Link against the XP-constrained user32 import library + # instead of the platform-SDK provided one to avoid + # inadvertently taking dependencies on post-XP user32 + # exports. + 'AdditionalDependencies!': [ + 'user32.lib', + ], + 'IgnoreDefaultLibraryNames': [ + 'user32.lib', + ], + # Remove user32 delay load for chrome.dll. + 'DelayLoadDLLs!': [ + 'user32.dll', + ], + 'AdditionalDependencies': [ + 'user32.winxp.lib', + ], + 'DelayLoadDLLs': [ + 'user32-delay.dll', + ], + 'AdditionalLibraryDirectories': [ + '<(DEPTH)/build/win/importlibs/x86', + ], + 'ForceSymbolReferences': [ + # Force the inclusion of the delay load hook in this + # binary. + 'ChromeDelayLoadHook', + ], + }], ], 'DelayLoadDLLs': [ 'comdlg32.dll', diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 9507b05..9350377 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -2340,6 +2340,9 @@ 'app/breakpad_field_trial_win.cc', 'app/breakpad_win.cc', 'app/breakpad_unittest_win.cc', + 'app/delay_load_hook_win.cc', + 'app/delay_load_hook_win.h', + 'app/delay_load_hook_unittest_win.cc', 'app/crash_analysis_win.cc', 'app/hard_error_handler_win.cc', 'app/run_all_unittests.cc', |