From 3d1f128709a3631847fa9573b3238f92f36cf305 Mon Sep 17 00:00:00 2001 From: Doug Turner Date: Fri, 18 Nov 2011 13:17:40 -0800 Subject: [PATCH 1/6] Bug 703680 - support both embedding/android and mobile/android/base. r=khuey --- embedding/Makefile.in | 2 ++ toolkit/mozapps/installer/packager.mk | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/embedding/Makefile.in b/embedding/Makefile.in index d1329b2a1069..b6f74b1d8c17 100644 --- a/embedding/Makefile.in +++ b/embedding/Makefile.in @@ -54,7 +54,9 @@ DIRS += test endif ifeq ($(MOZ_WIDGET_TOOLKIT),android) +ifeq ($(MOZ_BUILD_APP),mobile/xul) DIRS += android endif +endif include $(topsrcdir)/config/rules.mk diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index baeb0cbe7858..33ab1345503f 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -319,10 +319,16 @@ ABI_DIR = armeabi endif endif +ifeq ($(MOZ_BUILD_APP),mobile/xul) +GECKO_APP_AP_PATH = ../embedding/android +else +GECKO_APP_AP_PATH = ../mobile/android/base +endif + PKG_SUFFIX = .apk INNER_MAKE_PACKAGE = \ - make -C ../embedding/android gecko.ap_ && \ - cp ../embedding/android/gecko.ap_ $(_ABS_DIST) && \ + make -C $(GECKO_APP_AP_PATH) gecko.ap_ && \ + cp $(GECKO_APP_AP_PATH)/gecko.ap_ $(_ABS_DIST) && \ ( cd $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH) && \ mkdir -p lib/$(ABI_DIR) && \ mv libmozutils.so $(MOZ_CHILD_PROCESS_NAME) lib/$(ABI_DIR) && \ From 875becf78fae32a2ad1b56a568c4f95441e53d96 Mon Sep 17 00:00:00 2001 From: Sriram Ramasubramanian Date: Fri, 18 Nov 2011 13:18:24 -0800 Subject: [PATCH 2/6] Bug 703305 - Fix elfhack bustage. r=gladium --- toolkit/mozapps/installer/packager.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index 33ab1345503f..655c9491ed4a 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -667,7 +667,7 @@ ifdef USE_ELF_HACK @echo === and your environment \(compiler and linker versions\), and use @echo === --disable-elf-hack until this is fixed. @echo === - cd $(DIST)/bin; find . -name "*$(DLL_SUFFIX)" | xargs $(DEPTH)/build/unix/elfhack/elfhack + cd $(DIST)/bin; find . -name "*$(DLL_SUFFIX)" | xargs ../../build/unix/elfhack/elfhack endif stage-package: $(MOZ_PKG_MANIFEST) $(MOZ_PKG_REMOVALS_GEN) elfhack From 8dcbf6d26d3ca13e301d7e0bcf6bfe57645c729d Mon Sep 17 00:00:00 2001 From: Doug Turner Date: Fri, 18 Nov 2011 14:42:52 -0800 Subject: [PATCH 3/6] Bug 702037 - Merge Android History into mozilla-central. r=marco --- config/autoconf.mk.in | 1 + configure.in | 3 +- toolkit/components/places/Database.cpp | 6 + toolkit/components/places/Makefile.in | 8 + .../components/places/nsAndroidHistory.cpp | 168 ++++++++++++++++++ toolkit/components/places/nsAndroidHistory.h | 72 ++++++++ toolkit/components/places/nsPlacesModule.cpp | 25 ++- 7 files changed, 280 insertions(+), 3 deletions(-) create mode 100644 toolkit/components/places/nsAndroidHistory.cpp create mode 100644 toolkit/components/places/nsAndroidHistory.h diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index 555cfd323a6f..9a4489a40132 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -140,6 +140,7 @@ MOZ_UPDATE_PACKAGING = @MOZ_UPDATE_PACKAGING@ MOZ_DISABLE_PARENTAL_CONTROLS = @MOZ_DISABLE_PARENTAL_CONTROLS@ NS_ENABLE_TSF = @NS_ENABLE_TSF@ MOZ_SPELLCHECK = @MOZ_SPELLCHECK@ +MOZ_ANDROID_HISTORY = @MOZ_ANDROID_HISTORY@ MOZ_JAVA_COMPOSITOR = @MOZ_JAVA_COMPOSITOR@ MOZ_PROFILELOCKING = @MOZ_PROFILELOCKING@ MOZ_FEEDS = @MOZ_FEEDS@ diff --git a/configure.in b/configure.in index bc728678faa5..2e1bea24ff4f 100644 --- a/configure.in +++ b/configure.in @@ -4681,7 +4681,7 @@ NECKO_PROTOCOLS_DEFAULT="about data file ftp http res viewsource websocket wyciw USE_ARM_KUSER= BUILD_CTYPES=1 MOZ_USE_NATIVE_POPUP_WINDOWS= - +MOZ_ANDROID_HISTORY= case "${target}" in *android*|*darwin*) @@ -8464,6 +8464,7 @@ AC_SUBST(MOZ_D3DCOMPILER_CAB) AC_SUBST(MOZ_D3DX9_DLL) AC_SUBST(MOZ_D3DCOMPILER_DLL) +AC_SUBST(MOZ_ANDROID_HISTORY) AC_SUBST(ENABLE_STRIP) AC_SUBST(PKG_SKIP_STRIP) AC_SUBST(USE_ELF_DYNSTR_GC) diff --git a/toolkit/components/places/Database.cpp b/toolkit/components/places/Database.cpp index 9b8b4bc3f65a..8ec740997260 100644 --- a/toolkit/components/places/Database.cpp +++ b/toolkit/components/places/Database.cpp @@ -297,6 +297,12 @@ Database::~Database() nsresult Database::Init() { +#ifdef MOZ_ANDROID_HISTORY + // Currently places has deeply weaved it way throughout the gecko codebase. + // Here we disable all database creation and loading of places. + return NS_ERROR_NOT_IMPLEMENTED; +#endif + MOZ_ASSERT(NS_IsMainThread()); nsCOMPtr storage = diff --git a/toolkit/components/places/Makefile.in b/toolkit/components/places/Makefile.in index e75890dd9026..8534eb839866 100644 --- a/toolkit/components/places/Makefile.in +++ b/toolkit/components/places/Makefile.in @@ -101,6 +101,14 @@ CPPSRCS = \ LOCAL_INCLUDES += -I$(srcdir)/../build +ifdef MOZ_ANDROID_HISTORY +CPPSRCS += nsAndroidHistory.cpp +LOCAL_INCLUDES += \ + -I$(topsrcdir)/docshell/base \ + -I$(topsrcdir)/content/base/src \ + $(NULL) +endif + EXTRA_COMPONENTS = \ toolkitplaces.manifest \ nsLivemarkService.js \ diff --git a/toolkit/components/places/nsAndroidHistory.cpp b/toolkit/components/places/nsAndroidHistory.cpp new file mode 100644 index 000000000000..5faccde4541c --- /dev/null +++ b/toolkit/components/places/nsAndroidHistory.cpp @@ -0,0 +1,168 @@ +/* ***** 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 Android code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Kartikaya Gupta + * + * 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 ***** */ + +#include "nsAndroidHistory.h" +#include "AndroidBridge.h" +#include "Link.h" + +using namespace mozilla; +using mozilla::dom::Link; + +NS_IMPL_ISUPPORTS1(nsAndroidHistory, IHistory) + +nsAndroidHistory* nsAndroidHistory::sHistory = NULL; + +/*static*/ +nsAndroidHistory* +nsAndroidHistory::GetSingleton() +{ + if (!sHistory) { + sHistory = new nsAndroidHistory(); + NS_ENSURE_TRUE(sHistory, nsnull); + } + + NS_ADDREF(sHistory); + return sHistory; +} + +nsAndroidHistory::nsAndroidHistory() +{ + mListeners.Init(); +} + +NS_IMETHODIMP +nsAndroidHistory::RegisterVisitedCallback(nsIURI *aURI, Link *aContent) +{ + if (!aContent || !aURI) + return NS_OK; + + nsCAutoString uri; + nsresult rv = aURI->GetSpec(uri); + if (NS_FAILED(rv)) return rv; + nsString uriString = NS_ConvertUTF8toUTF16(uri); + + nsTArray* list = mListeners.Get(uriString); + if (! list) { + list = new nsTArray(); + mListeners.Put(uriString, list); + } + list->AppendElement(aContent); + + AndroidBridge *bridge = AndroidBridge::Bridge(); + if (bridge) { + bridge->CheckURIVisited(uriString); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsAndroidHistory::UnregisterVisitedCallback(nsIURI *aURI, Link *aContent) +{ + if (!aContent || !aURI) + return NS_OK; + + nsCAutoString uri; + nsresult rv = aURI->GetSpec(uri); + if (NS_FAILED(rv)) return rv; + nsString uriString = NS_ConvertUTF8toUTF16(uri); + + nsTArray* list = mListeners.Get(uriString); + if (! list) + return NS_OK; + + list->RemoveElement(aContent); + if (list->IsEmpty()) { + mListeners.Remove(uriString); + delete list; + } + return NS_OK; +} + +NS_IMETHODIMP +nsAndroidHistory::VisitURI(nsIURI *aURI, nsIURI *aLastVisitedURI, PRUint32 aFlags) +{ + if (!aURI) + return NS_OK; + + if (!(aFlags & VisitFlags::TOP_LEVEL)) + return NS_OK; + + AndroidBridge *bridge = AndroidBridge::Bridge(); + if (bridge) { + nsCAutoString uri; + nsresult rv = aURI->GetSpec(uri); + if (NS_FAILED(rv)) return rv; + nsString uriString = NS_ConvertUTF8toUTF16(uri); + bridge->MarkURIVisited(uriString); + } + return NS_OK; +} + +NS_IMETHODIMP +nsAndroidHistory::SetURITitle(nsIURI *aURI, const nsAString& aTitle) +{ + // we don't do anything with this right now + return NS_OK; +} + +void /*static*/ +nsAndroidHistory::NotifyURIVisited(const nsString& aUriString) +{ + if (! sHistory) + return; + sHistory->mPendingURIs.Push(aUriString); + NS_DispatchToMainThread(sHistory); +} + +NS_IMETHODIMP +nsAndroidHistory::Run() +{ + while (! mPendingURIs.IsEmpty()) { + nsString uriString = mPendingURIs.Pop(); + nsTArray* list = sHistory->mListeners.Get(uriString); + if (list) { + for (unsigned int i = 0; i < list->Length(); i++) { + list->ElementAt(i)->SetLinkState(eLinkState_Visited); + } + // as per the IHistory interface contract, remove the + // Link pointers once they have been notified + mListeners.Remove(uriString); + delete list; + } + } + return NS_OK; +} diff --git a/toolkit/components/places/nsAndroidHistory.h b/toolkit/components/places/nsAndroidHistory.h new file mode 100644 index 000000000000..50467e4e124c --- /dev/null +++ b/toolkit/components/places/nsAndroidHistory.h @@ -0,0 +1,72 @@ +/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * ***** 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 Android code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Kartikaya Gupta + * + * 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 NS_ANDROIDHISTORY_H +#define NS_ANDROIDHISTORY_H + +#include "IHistory.h" +#include "nsDataHashtable.h" +#include "nsTPriorityQueue.h" +#include "nsThreadUtils.h" + +#define NS_ANDROIDHISTORY_CID \ + {0xCCAA4880, 0x44DD, 0x40A7, {0xA1, 0x3F, 0x61, 0x56, 0xFC, 0x88, 0x2C, 0x0B}} + +class nsAndroidHistory : public mozilla::IHistory, public nsIRunnable +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_IHISTORY + NS_DECL_NSIRUNNABLE + + /** + * Obtains a pointer that has had AddRef called on it. Used by the service + * manager only. + */ + static nsAndroidHistory* GetSingleton(); + + nsAndroidHistory(); + static void NotifyURIVisited(const nsString& str); + +private: + static nsAndroidHistory* sHistory; + + nsDataHashtable *> mListeners; + nsTPriorityQueue mPendingURIs; +}; + +#endif diff --git a/toolkit/components/places/nsPlacesModule.cpp b/toolkit/components/places/nsPlacesModule.cpp index 559f0f3486fd..e47c6c2d0ed4 100644 --- a/toolkit/components/places/nsPlacesModule.cpp +++ b/toolkit/components/places/nsPlacesModule.cpp @@ -10,6 +10,10 @@ #include "History.h" #include "nsDocShellCID.h" +#ifdef MOZ_ANDROID_HISTORY +#include "nsAndroidHistory.h" +#endif + using namespace mozilla::places; NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsNavHistory, @@ -20,9 +24,13 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsNavBookmarks, nsNavBookmarks::GetSingleton) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsFaviconService, nsFaviconService::GetSingleton) -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(History, History::GetSingleton) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsPlacesImportExportService, nsPlacesImportExportService::GetSingleton) +#ifdef MOZ_ANDROID_HISTORY +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsAndroidHistory, nsAndroidHistory::GetSingleton) +#else +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(History, History::GetSingleton) +#endif NS_GENERIC_FACTORY_CONSTRUCTOR(nsAnnoProtocolHandler) NS_DEFINE_NAMED_CID(NS_NAVHISTORYSERVICE_CID); @@ -30,16 +38,25 @@ NS_DEFINE_NAMED_CID(NS_ANNOTATIONSERVICE_CID); NS_DEFINE_NAMED_CID(NS_ANNOPROTOCOLHANDLER_CID); NS_DEFINE_NAMED_CID(NS_NAVBOOKMARKSSERVICE_CID); NS_DEFINE_NAMED_CID(NS_FAVICONSERVICE_CID); -NS_DEFINE_NAMED_CID(NS_HISTORYSERVICE_CID); NS_DEFINE_NAMED_CID(NS_PLACESIMPORTEXPORTSERVICE_CID); +#ifdef MOZ_ANDROID_HISTORY +NS_DEFINE_NAMED_CID(NS_ANDROIDHISTORY_CID); +#else +NS_DEFINE_NAMED_CID(NS_HISTORYSERVICE_CID); +#endif + const mozilla::Module::CIDEntry kPlacesCIDs[] = { { &kNS_NAVHISTORYSERVICE_CID, false, NULL, nsNavHistoryConstructor }, { &kNS_ANNOTATIONSERVICE_CID, false, NULL, nsAnnotationServiceConstructor }, { &kNS_ANNOPROTOCOLHANDLER_CID, false, NULL, nsAnnoProtocolHandlerConstructor }, { &kNS_NAVBOOKMARKSSERVICE_CID, false, NULL, nsNavBookmarksConstructor }, { &kNS_FAVICONSERVICE_CID, false, NULL, nsFaviconServiceConstructor }, +#ifdef MOZ_ANDROID_HISTORY + { &kNS_ANDROIDHISTORY_CID, false, NULL, nsAndroidHistoryConstructor }, +#else { &kNS_HISTORYSERVICE_CID, false, NULL, HistoryConstructor }, +#endif { &kNS_PLACESIMPORTEXPORTSERVICE_CID, false, NULL, nsPlacesImportExportServiceConstructor }, { NULL } }; @@ -53,7 +70,11 @@ const mozilla::Module::ContractIDEntry kPlacesContracts[] = { { NS_NAVBOOKMARKSSERVICE_CONTRACTID, &kNS_NAVBOOKMARKSSERVICE_CID }, { NS_FAVICONSERVICE_CONTRACTID, &kNS_FAVICONSERVICE_CID }, { "@mozilla.org/embeddor.implemented/bookmark-charset-resolver;1", &kNS_NAVHISTORYSERVICE_CID }, +#ifdef MOZ_ANDROID_HISTORY + { NS_IHISTORY_CONTRACTID, &kNS_ANDROIDHISTORY_CID }, +#else { NS_IHISTORY_CONTRACTID, &kNS_HISTORYSERVICE_CID }, +#endif { NS_PLACESIMPORTEXPORTSERVICE_CONTRACTID, &kNS_PLACESIMPORTEXPORTSERVICE_CID }, { NULL } }; From 34bde38c1eda0d601813b1f301e28a3de09b8b9a Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 18 Nov 2011 21:42:17 -0800 Subject: [PATCH 4/6] Bug 703821 - Don't squash together draw events if the Java compositor is in use. r=dougt --- widget/src/android/nsAppShell.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/widget/src/android/nsAppShell.cpp b/widget/src/android/nsAppShell.cpp index 9d50114cadca..4fb87b182fa8 100644 --- a/widget/src/android/nsAppShell.cpp +++ b/widget/src/android/nsAppShell.cpp @@ -244,6 +244,9 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait) int curType = curEvent->Type(); int nextType = nextEvent->Type(); + // Do not skip draw events if the Java compositor is in use, since the Java compositor + // updates only the rect that changed - thus we will lose updates. +#ifndef MOZ_JAVA_COMPOSITOR while (nextType == AndroidGeckoEvent::DRAW && mNumDraws > 1) { @@ -263,6 +266,7 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait) nextEvent = PeekNextEvent(); nextType = nextEvent->Type(); } +#endif // If the next type of event isn't the same as the current type, // we don't coalesce. From 981852a1882f855ab9de8e30e88601c4e9787c6d Mon Sep 17 00:00:00 2001 From: Alex Keybl Date: Sat, 19 Nov 2011 03:33:30 -0500 Subject: [PATCH 5/6] Bug 699134, block Roboform <= ver 7.6.1, r=jonas a=akeybl CLOSED TREE --HG-- extra : transplant_source : %E5%D3mu%E2%5B%1F%C2%93%5E%23%C4%CB%9B%8B.%25%3E3%CC --- toolkit/xre/nsWindowsDllBlocklist.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/toolkit/xre/nsWindowsDllBlocklist.cpp b/toolkit/xre/nsWindowsDllBlocklist.cpp index aec54835bf48..f6cfe62bd965 100644 --- a/toolkit/xre/nsWindowsDllBlocklist.cpp +++ b/toolkit/xre/nsWindowsDllBlocklist.cpp @@ -129,7 +129,11 @@ static DllBlockInfo sWindowsDllBlocklist[] = { // Topcrash in Firefox 4 betas (bug 618899) {"accelerator.dll", MAKE_VERSION(3,2,1,6)}, - + + // Topcrash with Roboform in Firefox 8 (bug 699134) + {"rf-firefox.dll", MAKE_VERSION(7,6,1,0)}, + {"roboform.dll", MAKE_VERSION(7,6,1,0)}, + // leave these two in always for tests { "mozdllblockingtest.dll", ALL_VERSIONS }, { "mozdllblockingtest_versioned.dll", 0x0000000400000000ULL }, From a8e21c3f88b8d1ea1c843110b950c2d9c412fd1b Mon Sep 17 00:00:00 2001 From: Benjamin Smedberg Date: Fri, 18 Nov 2011 18:26:00 -0500 Subject: [PATCH 6/6] Bug 699134 - Protect against reentrancy in the LdrLoadDll hook, with less XPCOM stringery and more locking. a=bsmedberg ON A CLOSED TREE --HG-- extra : transplant_source : %9E%CE%8C%9C%FE%BEz%14%60%D7%84%3A%D1%05%16%26G%DEj/ --- toolkit/xre/nsWindowsDllBlocklist.cpp | 70 +++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/toolkit/xre/nsWindowsDllBlocklist.cpp b/toolkit/xre/nsWindowsDllBlocklist.cpp index f6cfe62bd965..77fe237bb61d 100644 --- a/toolkit/xre/nsWindowsDllBlocklist.cpp +++ b/toolkit/xre/nsWindowsDllBlocklist.cpp @@ -39,6 +39,9 @@ #include #include +#include + +#include #ifdef XRE_WANT_DLL_BLOCKLIST #define XRE_SetupDllBlocklist SetupDllBlocklist @@ -148,10 +151,68 @@ static DllBlockInfo sWindowsDllBlocklist[] = { // define this for very verbose dll load debug spew #undef DEBUG_very_verbose +namespace { + typedef NTSTATUS (NTAPI *LdrLoadDll_func) (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle); static LdrLoadDll_func stub_LdrLoadDll = 0; +/** + * Some versions of Windows call LoadLibraryEx to get the version information + * for a DLL, which causes our patched LdrLoadDll implementation to re-enter + * itself and cause infinite recursion and a stack-exhaustion crash. We protect + * against reentrancy by allowing recursive loads of the same DLL. + * + * Note that we don't use __declspec(thread) because that doesn't work in DLLs + * loaded via LoadLibrary and there can be a limited number of TLS slots, so + * we roll our own. + */ +class ReentrancySentinel +{ +public: + explicit ReentrancySentinel(const char* dllName) + { + DWORD currentThreadId = GetCurrentThreadId(); + EnterCriticalSection(&sLock); + mPreviousDllName = (*sThreadMap)[currentThreadId]; + + // If there is a DLL currently being loaded and it has the same name + // as the current attempt, we're re-entering. + mReentered = mPreviousDllName && !stricmp(mPreviousDllName, dllName); + (*sThreadMap)[currentThreadId] = dllName; + LeaveCriticalSection(&sLock); + } + + ~ReentrancySentinel() + { + DWORD currentThreadId = GetCurrentThreadId(); + EnterCriticalSection(&sLock); + (*sThreadMap)[currentThreadId] = mPreviousDllName; + LeaveCriticalSection(&sLock); + } + + bool BailOut() const + { + return mReentered; + }; + + static void InitializeStatics() + { + InitializeCriticalSection(&sLock); + sThreadMap = new std::map; + } + +private: + static CRITICAL_SECTION sLock; + static std::map* sThreadMap; + + const char* mPreviousDllName; + bool mReentered; +}; + +CRITICAL_SECTION ReentrancySentinel::sLock; +std::map* ReentrancySentinel::sThreadMap; + static NTSTATUS NTAPI patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileName, PHANDLE handle) { @@ -239,6 +300,11 @@ patched_LdrLoadDll (PWCHAR filePath, PULONG flags, PUNICODE_STRING moduleFileNam #endif if (info->maxVersion != ALL_VERSIONS) { + ReentrancySentinel sentinel(dllName); + if (sentinel.BailOut()) { + goto continue_loading; + } + // In Windows 8, the first parameter seems to be used for more than just the // path name. For example, its numerical value can be 1. Passing a non-valid // pointer to SearchPathW will cause a crash, so we need to check to see if we @@ -307,11 +373,15 @@ continue_loading: WindowsDllInterceptor NtDllIntercept; +} // anonymous namespace + void XRE_SetupDllBlocklist() { NtDllIntercept.Init("ntdll.dll"); + ReentrancySentinel::InitializeStatics(); + bool ok = NtDllIntercept.AddHook("LdrLoadDll", reinterpret_cast(patched_LdrLoadDll), (void**) &stub_LdrLoadDll); #ifdef DEBUG