From ffa07f5b9a032f3fc8fb726e781bce76163b5e71 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Thu, 4 Nov 2010 14:45:51 -0400 Subject: [PATCH] Bug 603679 - Fix a regression causing the Shockwave plugin to fail to load; r=bsmedberg a=blocking-beta8+ --- dom/plugins/Makefile.in | 1 + dom/plugins/PluginProcessChild.cpp | 27 +++++++++ ipc/app/MozillaRuntimeMain.cpp | 24 ++++---- modules/plugin/base/src/Makefile.in | 1 + modules/plugin/base/src/nsPluginsDirWin.cpp | 27 +++++---- toolkit/xre/Makefile.in | 1 + toolkit/xre/nsSetDllDirectory.cpp | 64 +++++++++++++++++++++ toolkit/xre/nsSetDllDirectory.h | 56 ++++++++++++++++++ toolkit/xre/nsWindowsWMain.cpp | 12 ++-- 9 files changed, 182 insertions(+), 31 deletions(-) create mode 100644 toolkit/xre/nsSetDllDirectory.cpp create mode 100644 toolkit/xre/nsSetDllDirectory.h diff --git a/dom/plugins/Makefile.in b/dom/plugins/Makefile.in index 1152357787f..8833fccc83d 100644 --- a/dom/plugins/Makefile.in +++ b/dom/plugins/Makefile.in @@ -140,6 +140,7 @@ endif LOCAL_INCLUDES = \ -I$(topsrcdir)/modules/plugin/base/public/ \ -I$(topsrcdir)/modules/plugin/base/src/ \ + -I$(topsrcdir)/toolkit/xre \ $(NULL) include $(topsrcdir)/config/config.mk diff --git a/dom/plugins/PluginProcessChild.cpp b/dom/plugins/PluginProcessChild.cpp index 07b8dbd13b4..8151b10870e 100644 --- a/dom/plugins/PluginProcessChild.cpp +++ b/dom/plugins/PluginProcessChild.cpp @@ -52,6 +52,21 @@ using mozilla::ipc::IOThreadChild; +#ifdef OS_WIN +#include "nsSetDllDirectory.h" +#include + +namespace { + +std::size_t caseInsensitiveFind(std::string aHaystack, std::string aNeedle) { + std::transform(aHaystack.begin(), aHaystack.end(), aHaystack.begin(), ::tolower); + std::transform(aNeedle.begin(), aNeedle.end(), aNeedle.begin(), ::tolower); + return aHaystack.find(aNeedle); +} + +} +#endif + namespace mozilla { namespace plugins { @@ -86,6 +101,18 @@ PluginProcessChild::Init() pluginFilename = WideToUTF8(values[0]); + bool protectCurrentDirectory = true; + // Don't use SetDllDirectory for Shockwave Director + const std::string shockwaveDirectorPluginFilename("\\np32dsw.dll"); + std::size_t index = caseInsensitiveFind(pluginFilename, shockwaveDirectorPluginFilename); + if (index != std::string::npos && + index + shockwaveDirectorPluginFilename.length() == pluginFilename.length()) { + protectCurrentDirectory = false; + } + if (protectCurrentDirectory) { + NS_SetDllDirectory(L""); + } + #else # error Sorry #endif diff --git a/ipc/app/MozillaRuntimeMain.cpp b/ipc/app/MozillaRuntimeMain.cpp index c764af4bd01..094325c5d27 100644 --- a/ipc/app/MozillaRuntimeMain.cpp +++ b/ipc/app/MozillaRuntimeMain.cpp @@ -48,7 +48,11 @@ #ifdef XP_WIN #include // we want a wmain entry point +// but we don't want its DLL load protection, because we'll handle it here +#define XRE_DONT_PROTECT_DLL_LOAD #include "nsWindowsWMain.cpp" + +#include "nsSetDllDirectory.h" #endif int @@ -58,23 +62,21 @@ main(int argc, char* argv[]) MessageBox(NULL, L"Hi", L"Hi", MB_OK); #endif -#ifdef XP_WIN - typedef BOOL - (WINAPI *pfnSetDllDirectory) (LPCWSTR); - pfnSetDllDirectory setDllDirectory = - reinterpret_cast - (GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetDllDirectoryW")); - if (setDllDirectory) { - setDllDirectory(L""); - } -#endif - // Check for the absolute minimum number of args we need to move // forward here. We expect the last arg to be the child process type. if (argc < 1) return 1; GeckoProcessType proctype = XRE_StringToChildProcessType(argv[--argc]); +#ifdef XP_WIN + // For plugins, this is done in PluginProcessChild::Init, as we need to + // avoid it for unsupported plugins. See PluginProcessChild::Init for + // the details. + if (proctype != GeckoProcessType_Plugin) { + mozilla::NS_SetDllDirectory(L""); + } +#endif + nsresult rv = XRE_InitChildProcess(argc, argv, proctype); NS_ENSURE_SUCCESS(rv, 1); diff --git a/modules/plugin/base/src/Makefile.in b/modules/plugin/base/src/Makefile.in index d26eb8865be..c6f84367bba 100644 --- a/modules/plugin/base/src/Makefile.in +++ b/modules/plugin/base/src/Makefile.in @@ -77,6 +77,7 @@ ifneq (,$(filter WINNT WINCE,$(OS_ARCH))) CPPSRCS += nsPluginsDirWin.cpp CPPSRCS += nsPluginNativeWindowWin.cpp CPPSRCS += nsPluginDirServiceProvider.cpp + LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre else ifeq ($(MOZ_WIDGET_TOOLKIT),os2) CPPSRCS += nsPluginsDirOS2.cpp diff --git a/modules/plugin/base/src/nsPluginsDirWin.cpp b/modules/plugin/base/src/nsPluginsDirWin.cpp index d72a8cd243d..c2f86edc31f 100644 --- a/modules/plugin/base/src/nsPluginsDirWin.cpp +++ b/modules/plugin/base/src/nsPluginsDirWin.cpp @@ -54,6 +54,8 @@ #include "nsString.h" #include "nsILocalFile.h" +#include "nsUnicharUtils.h" +#include "nsSetDllDirectory.h" /* Local helper functions */ @@ -266,14 +268,7 @@ nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary) if (!plugin) return NS_ERROR_NULL_POINTER; - typedef BOOL - (WINAPI *pfnSetDllDirectory) (LPCWSTR); - pfnSetDllDirectory setDllDirectory = - reinterpret_cast - (GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetDllDirectoryW")); - if (setDllDirectory) { - setDllDirectory(NULL); - } + PRBool protectCurrentDirectory = PR_TRUE; #ifndef WINCE nsAutoString pluginFolderPath; @@ -283,6 +278,10 @@ nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary) if (kNotFound == idx) return NS_ERROR_FILE_INVALID_PATH; + if (Substring(pluginFolderPath, idx).LowerCaseEqualsLiteral("\\np32dsw.dll")) { + protectCurrentDirectory = PR_FALSE; + } + pluginFolderPath.SetLength(idx); BOOL restoreOrigDir = FALSE; @@ -296,10 +295,18 @@ nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary) } #endif + if (protectCurrentDirectory) { + mozilla::NS_SetDllDirectory(NULL); + } + nsresult rv = plugin->Load(outLibrary); if (NS_FAILED(rv)) *outLibrary = NULL; + if (protectCurrentDirectory) { + mozilla::NS_SetDllDirectory(L""); + } + #ifndef WINCE if (restoreOrigDir) { BOOL bCheck = SetCurrentDirectoryW(aOrigDir); @@ -307,10 +314,6 @@ nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary) } #endif - if (setDllDirectory) { - setDllDirectory(L""); - } - return rv; } diff --git a/toolkit/xre/Makefile.in b/toolkit/xre/Makefile.in index 8813ec9b887..f23bc3d6839 100644 --- a/toolkit/xre/Makefile.in +++ b/toolkit/xre/Makefile.in @@ -89,6 +89,7 @@ endif ifeq ($(MOZ_WIDGET_TOOLKIT),windows) CPPSRCS += nsNativeAppSupportWin.cpp +CPPSRCS += nsSetDllDirectory.cpp DEFINES += -DWIN32_LEAN_AND_MEAN -DUNICODE -D_UNICODE EXPORTS = nsWindowsDllInterceptor.h else diff --git a/toolkit/xre/nsSetDllDirectory.cpp b/toolkit/xre/nsSetDllDirectory.cpp new file mode 100644 index 00000000000..f1e634c121e --- /dev/null +++ b/toolkit/xre/nsSetDllDirectory.cpp @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ehsan Akhgari (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef XP_WIN +#error This file only makes sense on Windows. +#endif + +#include +#include "nsSetDllDirectory.h" + +namespace mozilla { + +XPCOM_API(void) +NS_SetDllDirectory(const WCHAR *aDllDirectory) +{ + typedef BOOL + (WINAPI *pfnSetDllDirectory) (LPCWSTR); + static pfnSetDllDirectory setDllDirectory = nsnull; + if (!setDllDirectory) { + setDllDirectory = reinterpret_cast + (GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetDllDirectoryW")); + } + if (setDllDirectory) { + setDllDirectory(aDllDirectory); + } +} + +} + diff --git a/toolkit/xre/nsSetDllDirectory.h b/toolkit/xre/nsSetDllDirectory.h new file mode 100644 index 00000000000..f9d1fc975ef --- /dev/null +++ b/toolkit/xre/nsSetDllDirectory.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ehsan Akhgari (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsSetDllDirectory_h +#define nsSetDllDirectory_h + +#ifndef XP_WIN +#error This file only makes sense on Windows. +#endif + +#include + +namespace mozilla { + +// Sets the directory from which DLLs can be loaded if the SetDllDirectory OS +// API is available. +XPCOM_API(void) NS_SetDllDirectory(const WCHAR *aDllDirectory); + +} + +#endif diff --git a/toolkit/xre/nsWindowsWMain.cpp b/toolkit/xre/nsWindowsWMain.cpp index 3cc5178df24..85de7b1fde2 100644 --- a/toolkit/xre/nsWindowsWMain.cpp +++ b/toolkit/xre/nsWindowsWMain.cpp @@ -7,6 +7,7 @@ #endif #include "nsUTF8Utils.h" +#include "nsSetDllDirectory.h" #if defined(_MSC_VER) && defined(_M_IX86) && defined(XRE_WANT_DLL_BLOCKLIST) #include "nsWindowsDllBlocklist.cpp" @@ -90,14 +91,9 @@ void ExtractEnvironmentFromCL(int &argc, char **&argv) int wmain(int argc, WCHAR **argv) { - typedef BOOL - (WINAPI *pfnSetDllDirectory) (LPCWSTR); - pfnSetDllDirectory setDllDirectory = - reinterpret_cast - (GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "SetDllDirectoryW")); - if (setDllDirectory) { - setDllDirectory(L""); - } +#ifndef XRE_DONT_PROTECT_DLL_LOAD + mozilla::NS_SetDllDirectory(L""); +#endif #ifdef XRE_WANT_DLL_BLOCKLIST SetupDllBlocklist();