mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-27 12:50:09 +00:00
Bug 1023941 - Part 5: Loader hook to redirect the missing import. r=bsmedberg
--HG-- extra : rebase_source : 7cf2e857f51dcfcc95bb806d49ef13b794f5ba5b
This commit is contained in:
parent
999888a513
commit
36c74581b8
@ -25,6 +25,7 @@
|
||||
|
||||
#ifdef XP_WIN
|
||||
// we want a wmain entry point
|
||||
#define XRE_DONT_SUPPORT_XPSP2 // See https://bugzil.la/1023941#c32
|
||||
#include "nsWindowsWMain.cpp"
|
||||
#define snprintf _snprintf
|
||||
#define strcasecmp _stricmp
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#include <windows.h>
|
||||
#define XRE_DONT_SUPPORT_XPSP2 // this app doesn't ship
|
||||
#include "nsWindowsWMain.cpp"
|
||||
#endif
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
// we want a wmain entry point
|
||||
#define XRE_DONT_PROTECT_DLL_LOAD
|
||||
#define XRE_DONT_SUPPORT_XPSP2 // xpcshell does not ship
|
||||
#define XRE_WANT_ENVIRON
|
||||
#include "nsWindowsWMain.cpp"
|
||||
#endif
|
||||
|
146
toolkit/xre/WindowsCrtPatch.h
Normal file
146
toolkit/xre/WindowsCrtPatch.h
Normal file
@ -0,0 +1,146 @@
|
||||
/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* This file works around an incompatibility between Visual Studio 2013's
|
||||
* C Runtime DLL and Windows XP Service Pack 2.
|
||||
*
|
||||
* On XP SP2, msvcr120.dll fails to load, because it has a load-time dependency
|
||||
* on a kernel32 export named GetLogicalProcessorInformation, which is only
|
||||
* available in XP SP3 and newer. Microsoft has declared this to be by design.
|
||||
* See: https://connect.microsoft.com/VisualStudio/feedback/details/811379/
|
||||
*
|
||||
* The CRT calls GetLogicalProcessorInformation only from the concurrency
|
||||
* runtime, which our code does not use. A potential workaround is to
|
||||
* static-link the CRT into all of our binaries and let the linker drop the
|
||||
* unused API calls. We don't want to take that approach, due to concerns
|
||||
* about binary bloat and jemalloc integration.
|
||||
*
|
||||
* Instead we hook the Windows loader and patch out the missing import.
|
||||
* We intercept ntdll!RtlImageNtHeader, which is a helper API called during
|
||||
* the DLL loading process. We walk the PE image and redirect the
|
||||
* GetLogicalProcessorInformation import to something benign like DebugBreak,
|
||||
* before the loader populates msvcr120.dll's import table.
|
||||
*
|
||||
* This is a fragile hack that only works if we can set up the hook before
|
||||
* Windows tries to load msvcr120.dll. This means that all .exe files:
|
||||
* 1) must static-link the CRT
|
||||
* 2) must delay-load anything with ties to msvcr120.dll (e.g. mozglue.dll)
|
||||
* 3) must not call malloc, because the linker would substitute our mozglue
|
||||
* replacements, which leads to the CRT loading mozglue before main.
|
||||
* The remainder of our binaries can continue to dynamic-link the CRT.
|
||||
* Assertions enforce that our hooks are installed before msvcr120.dll.
|
||||
*/
|
||||
|
||||
#ifndef WindowsCrtPatch_h
|
||||
#define WindowsCrtPatch_h
|
||||
|
||||
#include "nsWindowsDllInterceptor.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
||||
namespace WindowsCrtPatch {
|
||||
|
||||
mozilla::WindowsDllInterceptor NtdllIntercept;
|
||||
|
||||
typedef PIMAGE_NT_HEADERS (NTAPI *RtlImageNtHeader_func)(HMODULE module);
|
||||
static RtlImageNtHeader_func stub_RtlImageNtHeader = 0;
|
||||
|
||||
// A helper to simplify the use of Relative Virtual Addresses.
|
||||
template <typename T>
|
||||
class RVAPtr
|
||||
{
|
||||
public:
|
||||
RVAPtr(HMODULE module, size_t rva)
|
||||
: _ptr(reinterpret_cast<T*>(reinterpret_cast<char*>(module) + rva)) {}
|
||||
operator T*() { return _ptr; }
|
||||
T* operator ->() { return _ptr; }
|
||||
T* operator ++() { return ++_ptr; }
|
||||
|
||||
private:
|
||||
T* _ptr;
|
||||
};
|
||||
|
||||
void
|
||||
PatchModuleImports(HMODULE module, PIMAGE_NT_HEADERS headers)
|
||||
{
|
||||
static const WORD MAGIC_DOS = 0x5a4d; // "MZ"
|
||||
static const DWORD MAGIC_PE = 0x4550; // "PE\0\0"
|
||||
RVAPtr<IMAGE_DOS_HEADER> dosStub(module, 0);
|
||||
|
||||
if (!module ||
|
||||
!headers ||
|
||||
dosStub->e_magic != MAGIC_DOS ||
|
||||
headers != RVAPtr<IMAGE_NT_HEADERS>(module, dosStub->e_lfanew) ||
|
||||
headers->Signature != MAGIC_PE ||
|
||||
headers->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The format of the import directory is described in:
|
||||
// "An In-Depth Look into the Win32 Portable Executable File Format, Part 2"
|
||||
// http://msdn.microsoft.com/en-us/magazine/cc301808.aspx
|
||||
|
||||
IMAGE_DATA_DIRECTORY* importDirectory =
|
||||
&headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
||||
RVAPtr<IMAGE_IMPORT_DESCRIPTOR> descriptor(module, importDirectory->VirtualAddress);
|
||||
|
||||
for (; descriptor->OriginalFirstThunk; ++descriptor) {
|
||||
RVAPtr<char> importedModule(module, descriptor->Name);
|
||||
if (!stricmp(importedModule, "kernel32.dll")) {
|
||||
RVAPtr<IMAGE_THUNK_DATA> thunk(module, descriptor->OriginalFirstThunk);
|
||||
for (; thunk->u1.AddressOfData; ++thunk) {
|
||||
RVAPtr<IMAGE_IMPORT_BY_NAME> import(module, thunk->u1.AddressOfData);
|
||||
if (!strcmp(import->Name, "GetLogicalProcessorInformation")) {
|
||||
memcpy(import->Name, "DebugBreak", sizeof("DebugBreak"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS NTAPI
|
||||
patched_RtlImageNtHeader(HMODULE module)
|
||||
{
|
||||
PIMAGE_NT_HEADERS headers = stub_RtlImageNtHeader(module);
|
||||
|
||||
if (module == GetModuleHandleA("msvcr120.dll")) {
|
||||
PatchModuleImports(module, headers);
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
// Non-inline to make the asserts stand out
|
||||
MOZ_NEVER_INLINE void
|
||||
Init()
|
||||
{
|
||||
// If the C Runtime DLL is already loaded, our hooks will be ineffective,
|
||||
// and we will fail to load on XP SP2 when built with Visual Studio 2013.
|
||||
// We assert the absence of these modules on all Windows builds in order to
|
||||
// catch breakage faster.
|
||||
//
|
||||
// If these assertions fail, see the comment at the top of this file for
|
||||
// possible causes. Any changes to the lines below MUST be tested on XP SP2!
|
||||
MOZ_ASSERT(!GetModuleHandleA("mozglue.dll"));
|
||||
MOZ_ASSERT(!GetModuleHandleA("msvcr120.dll"));
|
||||
MOZ_ASSERT(!GetModuleHandleA("msvcr120d.dll"));
|
||||
|
||||
// Temporary until we fully switch over to VS 2013:
|
||||
MOZ_ASSERT(!GetModuleHandleA("msvcr100.dll"));
|
||||
MOZ_ASSERT(!GetModuleHandleA("msvcr100d.dll"));
|
||||
|
||||
#if defined(_M_IX86) && defined(_MSC_VER) && _MSC_VER >= 1800
|
||||
if (!mozilla::IsXPSP3OrLater()) {
|
||||
NtdllIntercept.Init("ntdll.dll");
|
||||
NtdllIntercept.AddHook("RtlImageNtHeader",
|
||||
reinterpret_cast<intptr_t>(patched_RtlImageNtHeader),
|
||||
reinterpret_cast<void**>(&stub_RtlImageNtHeader));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace WindowsCrtPatch
|
||||
|
||||
#endif // WindowsCrtPatch_h
|
@ -16,6 +16,10 @@
|
||||
#include "nsSetDllDirectory.h"
|
||||
#endif
|
||||
|
||||
#ifndef XRE_DONT_SUPPORT_XPSP2
|
||||
#include "WindowsCrtPatch.h"
|
||||
#endif
|
||||
|
||||
#ifdef __MINGW32__
|
||||
|
||||
/* MingW currently does not implement a wide version of the
|
||||
@ -76,6 +80,10 @@ FreeAllocStrings(int argc, char **argv)
|
||||
|
||||
int wmain(int argc, WCHAR **argv)
|
||||
{
|
||||
#ifndef XRE_DONT_SUPPORT_XPSP2
|
||||
WindowsCrtPatch::Init();
|
||||
#endif
|
||||
|
||||
#ifndef XRE_DONT_PROTECT_DLL_LOAD
|
||||
mozilla::SanitizeEnvironmentVariables();
|
||||
SetDllDirectoryW(L"");
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "nsINIParser.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#define XRE_DONT_SUPPORT_XPSP2 // See https://bugzil.la/1023941#c32
|
||||
#include "nsWindowsWMain.cpp"
|
||||
#endif
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user