diff -r 000000000000 -r 6474c204b198 xpcom/components/nsNativeComponentLoader.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xpcom/components/nsNativeComponentLoader.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,246 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ + +/* Allow logging in the release build */ +#ifdef MOZ_LOGGING +#define FORCE_PR_LOG +#endif + +#include "nsNativeComponentLoader.h" + +#include "prlog.h" +#include "prinit.h" +#include "prerror.h" + +#include "nsComponentManager.h" +#include "ManifestParser.h" // for LogMessage +#include "nsCRTGlue.h" +#include "nsThreadUtils.h" +#include "nsTraceRefcnt.h" + +#include "nsIFile.h" +#include "mozilla/WindowsDllBlocklist.h" + +#ifdef XP_WIN +#include +#endif + +#ifdef XP_MACOSX +#include +#endif + +#ifdef VMS +#include +#include +#endif + +#ifdef DEBUG +#define IMPLEMENT_BREAK_AFTER_LOAD +#endif + +using namespace mozilla; + +static PRLogModuleInfo * +GetNativeModuleLoaderLog() +{ + static PRLogModuleInfo *sLog; + if (!sLog) + sLog = PR_NewLogModule("nsNativeModuleLoader"); + return sLog; +} + +#define LOG(level, args) PR_LOG(GetNativeModuleLoaderLog(), level, args) + +NS_IMPL_QUERY_INTERFACE(nsNativeModuleLoader, + mozilla::ModuleLoader) + +NS_IMPL_ADDREF_USING_AGGREGATOR(nsNativeModuleLoader, + nsComponentManagerImpl::gComponentManager) +NS_IMPL_RELEASE_USING_AGGREGATOR(nsNativeModuleLoader, + nsComponentManagerImpl::gComponentManager) + +nsresult +nsNativeModuleLoader::Init() +{ + MOZ_ASSERT(NS_IsMainThread(), "Startup not on main thread?"); + LOG(PR_LOG_DEBUG, ("nsNativeModuleLoader::Init()")); + return NS_OK; +} + +class LoadModuleMainThreadRunnable : public nsRunnable +{ +public: + LoadModuleMainThreadRunnable(nsNativeModuleLoader* loader, + FileLocation &file) + : mLoader(loader) + , mFile(file) + , mResult(nullptr) + { } + + NS_IMETHOD Run() + { + mResult = mLoader->LoadModule(mFile); + return NS_OK; + } + + nsRefPtr mLoader; + FileLocation mFile; + const mozilla::Module* mResult; +}; + +const mozilla::Module* +nsNativeModuleLoader::LoadModule(FileLocation &aFile) +{ + if (aFile.IsZip()) { + NS_ERROR("Binary components cannot be loaded from JARs"); + return nullptr; + } + nsCOMPtr file = aFile.GetBaseFile(); + nsresult rv; + + if (!NS_IsMainThread()) { + // If this call is off the main thread, synchronously proxy it + // to the main thread. + nsRefPtr r = new LoadModuleMainThreadRunnable(this, aFile); + NS_DispatchToMainThread(r, NS_DISPATCH_SYNC); + return r->mResult; + } + + nsCOMPtr hashedFile(do_QueryInterface(file)); + if (!hashedFile) { + NS_ERROR("nsIFile is not nsIHashable"); + return nullptr; + } + + nsAutoCString filePath; + file->GetNativePath(filePath); + + NativeLoadData data; + + if (mLibraries.Get(hashedFile, &data)) { + NS_ASSERTION(data.module, "Corrupt mLibraries hash"); + LOG(PR_LOG_DEBUG, + ("nsNativeModuleLoader::LoadModule(\"%s\") - found in cache", + filePath.get())); + return data.module; + } + + // We haven't loaded this module before + { +#ifdef HAS_DLL_BLOCKLIST + AutoSetXPCOMLoadOnMainThread guard; +#endif + rv = file->Load(&data.library); + } + + if (NS_FAILED(rv)) { + char errorMsg[1024] = ""; + + if (PR_GetErrorTextLength() < (int) sizeof(errorMsg)) + PR_GetErrorText(errorMsg); + + LogMessage("Failed to load native module at path '%s': (%lx) %s", + filePath.get(), rv, errorMsg); + + return nullptr; + } + +#ifdef IMPLEMENT_BREAK_AFTER_LOAD + nsAutoCString leafName; + file->GetNativeLeafName(leafName); + + char *env = getenv("XPCOM_BREAK_ON_LOAD"); + char *blist; + if (env && *env && (blist = strdup(env))) { + char *nextTok = blist; + while (char *token = NS_strtok(":", &nextTok)) { + if (leafName.Find(token, true) != kNotFound) { + NS_BREAK(); + } + } + + free(blist); + } +#endif + + void *module = PR_FindSymbol(data.library, "NSModule"); + if (!module) { + LogMessage("Native module at path '%s' doesn't export symbol `NSModule`.", + filePath.get()); + PR_UnloadLibrary(data.library); + return nullptr; + } + + data.module = *(mozilla::Module const *const *) module; + if (mozilla::Module::kVersion != data.module->mVersion) { + LogMessage("Native module at path '%s' is incompatible with this version of Firefox, has version %i, expected %i.", + filePath.get(), data.module->mVersion, + mozilla::Module::kVersion); + PR_UnloadLibrary(data.library); + return nullptr; + } + + mLibraries.Put(hashedFile, data); // infallible + return data.module; +} + +PLDHashOperator +nsNativeModuleLoader::ReleaserFunc(nsIHashable* aHashedFile, + NativeLoadData& aLoadData, void*) +{ + aLoadData.module = nullptr; + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsNativeModuleLoader::UnloaderFunc(nsIHashable* aHashedFile, + NativeLoadData& aLoadData, void*) +{ + if (PR_LOG_TEST(GetNativeModuleLoaderLog(), PR_LOG_DEBUG)) { + nsCOMPtr file(do_QueryInterface(aHashedFile)); + + nsAutoCString filePath; + file->GetNativePath(filePath); + + LOG(PR_LOG_DEBUG, + ("nsNativeModuleLoader::UnloaderFunc(\"%s\")", filePath.get())); + } + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcnt::SetActivityIsLegal(false); +#endif + +#if 0 + // XXXbsmedberg: do this as soon as the static-destructor crash(es) + // are fixed + PRStatus ret = PR_UnloadLibrary(aLoadData.library); + NS_ASSERTION(ret == PR_SUCCESS, "Failed to unload library"); +#endif + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcnt::SetActivityIsLegal(true); +#endif + + return PL_DHASH_REMOVE; +} + +void +nsNativeModuleLoader::UnloadLibraries() +{ + MOZ_ASSERT(NS_IsMainThread(), "Shutdown not on main thread?"); + mLibraries.Enumerate(ReleaserFunc, nullptr); + mLibraries.Enumerate(UnloaderFunc, nullptr); +}