diff options
Diffstat (limited to 'xpcom/components/nsNativeModuleLoader.cpp')
-rw-r--r-- | xpcom/components/nsNativeModuleLoader.cpp | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/xpcom/components/nsNativeModuleLoader.cpp b/xpcom/components/nsNativeModuleLoader.cpp new file mode 100644 index 000000000..6452f5d1b --- /dev/null +++ b/xpcom/components/nsNativeModuleLoader.cpp @@ -0,0 +1,220 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 + */ + +#include "nsNativeModuleLoader.h" + +#include "mozilla/Logging.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 <windows.h> +#endif + +#ifdef XP_MACOSX +#include <signal.h> +#endif + +#ifdef DEBUG +#define IMPLEMENT_BREAK_AFTER_LOAD +#endif + +using namespace mozilla; + +static LazyLogModule sNativeModuleLoaderLog("nsNativeModuleLoader"); +#define LOG(level, args) MOZ_LOG(sNativeModuleLoaderLog, level, args) + +nsresult +nsNativeModuleLoader::Init() +{ + MOZ_ASSERT(NS_IsMainThread(), "Startup not on main thread?"); + LOG(LogLevel::Debug, ("nsNativeModuleLoader::Init()")); + return NS_OK; +} + +class LoadModuleMainThreadRunnable : public Runnable +{ +public: + LoadModuleMainThreadRunnable(nsNativeModuleLoader* aLoader, + FileLocation& aFile) + : mManager(nsComponentManagerImpl::gComponentManager) + , mLoader(aLoader) + , mFile(aFile) + , mResult(nullptr) + { + } + + NS_IMETHOD Run() override + { + mResult = mLoader->LoadModule(mFile); + return NS_OK; + } + + RefPtr<nsComponentManagerImpl> mManager; + nsNativeModuleLoader* 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<nsIFile> file = aFile.GetBaseFile(); + nsresult rv; + + if (!NS_IsMainThread()) { + // If this call is off the main thread, synchronously proxy it + // to the main thread. + RefPtr<LoadModuleMainThreadRunnable> r = + new LoadModuleMainThreadRunnable(this, aFile); + NS_DispatchToMainThread(r, NS_DISPATCH_SYNC); + return r->mResult; + } + + nsCOMPtr<nsIHashable> 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.mModule, "Corrupt mLibraries hash"); + LOG(LogLevel::Debug, + ("nsNativeModuleLoader::LoadModule(\"%s\") - found in cache", + filePath.get())); + return data.mModule; + } + + // We haven't loaded this module before + { +#ifdef HAS_DLL_BLOCKLIST + AutoSetXPCOMLoadOnMainThread guard; +#endif + rv = file->Load(&data.mLibrary); + } + + if (NS_FAILED(rv)) { + char errorMsg[1024] = "<unknown; can't get error from NSPR>"; + + 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.mLibrary, "NSModule"); + if (!module) { + LogMessage("Native module at path '%s' doesn't export symbol `NSModule`.", + filePath.get()); + PR_UnloadLibrary(data.mLibrary); + return nullptr; + } + + data.mModule = *(mozilla::Module const* const*)module; + if (mozilla::Module::kVersion != data.mModule->mVersion) { + LogMessage("Native module at path '%s' is incompatible with this version of Firefox, has version %i, expected %i.", + filePath.get(), data.mModule->mVersion, + mozilla::Module::kVersion); + PR_UnloadLibrary(data.mLibrary); + return nullptr; + } + + mLibraries.Put(hashedFile, data); // infallible + return data.mModule; +} + +void +nsNativeModuleLoader::UnloadLibraries() +{ + MOZ_ASSERT(NS_IsMainThread(), "Shutdown not on main thread?"); + + for (auto iter = mLibraries.Iter(); !iter.Done(); iter.Next()) { + NativeLoadData& loadData = iter.Data(); + loadData.mModule = nullptr; + } + + for (auto iter = mLibraries.Iter(); !iter.Done(); iter.Next()) { + if (MOZ_LOG_TEST(sNativeModuleLoaderLog, LogLevel::Debug)) { + nsIHashable* hashedFile = iter.Key(); + nsCOMPtr<nsIFile> file(do_QueryInterface(hashedFile)); + + nsAutoCString filePath; + file->GetNativePath(filePath); + + LOG(LogLevel::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 + NativeLoadData& loadData = iter.Data(); + PRStatus ret = PR_UnloadLibrary(loadData.mLibrary); + NS_ASSERTION(ret == PR_SUCCESS, "Failed to unload library"); +#endif + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcnt::SetActivityIsLegal(true); +#endif + + iter.Remove(); + } +} |