Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
michael@0 | 5 | * This Original Code has been modified by IBM Corporation. |
michael@0 | 6 | * Modifications made by IBM described herein are |
michael@0 | 7 | * Copyright (c) International Business Machines |
michael@0 | 8 | * Corporation, 2000 |
michael@0 | 9 | * |
michael@0 | 10 | * Modifications to Mozilla code or documentation |
michael@0 | 11 | * identified per MPL Section 3.3 |
michael@0 | 12 | * |
michael@0 | 13 | * Date Modified by Description of modification |
michael@0 | 14 | * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 |
michael@0 | 15 | */ |
michael@0 | 16 | |
michael@0 | 17 | /* Allow logging in the release build */ |
michael@0 | 18 | #ifdef MOZ_LOGGING |
michael@0 | 19 | #define FORCE_PR_LOG |
michael@0 | 20 | #endif |
michael@0 | 21 | |
michael@0 | 22 | #include "nsNativeComponentLoader.h" |
michael@0 | 23 | |
michael@0 | 24 | #include "prlog.h" |
michael@0 | 25 | #include "prinit.h" |
michael@0 | 26 | #include "prerror.h" |
michael@0 | 27 | |
michael@0 | 28 | #include "nsComponentManager.h" |
michael@0 | 29 | #include "ManifestParser.h" // for LogMessage |
michael@0 | 30 | #include "nsCRTGlue.h" |
michael@0 | 31 | #include "nsThreadUtils.h" |
michael@0 | 32 | #include "nsTraceRefcnt.h" |
michael@0 | 33 | |
michael@0 | 34 | #include "nsIFile.h" |
michael@0 | 35 | #include "mozilla/WindowsDllBlocklist.h" |
michael@0 | 36 | |
michael@0 | 37 | #ifdef XP_WIN |
michael@0 | 38 | #include <windows.h> |
michael@0 | 39 | #endif |
michael@0 | 40 | |
michael@0 | 41 | #ifdef XP_MACOSX |
michael@0 | 42 | #include <signal.h> |
michael@0 | 43 | #endif |
michael@0 | 44 | |
michael@0 | 45 | #ifdef VMS |
michael@0 | 46 | #include <lib$routines.h> |
michael@0 | 47 | #include <ssdef.h> |
michael@0 | 48 | #endif |
michael@0 | 49 | |
michael@0 | 50 | #ifdef DEBUG |
michael@0 | 51 | #define IMPLEMENT_BREAK_AFTER_LOAD |
michael@0 | 52 | #endif |
michael@0 | 53 | |
michael@0 | 54 | using namespace mozilla; |
michael@0 | 55 | |
michael@0 | 56 | static PRLogModuleInfo * |
michael@0 | 57 | GetNativeModuleLoaderLog() |
michael@0 | 58 | { |
michael@0 | 59 | static PRLogModuleInfo *sLog; |
michael@0 | 60 | if (!sLog) |
michael@0 | 61 | sLog = PR_NewLogModule("nsNativeModuleLoader"); |
michael@0 | 62 | return sLog; |
michael@0 | 63 | } |
michael@0 | 64 | |
michael@0 | 65 | #define LOG(level, args) PR_LOG(GetNativeModuleLoaderLog(), level, args) |
michael@0 | 66 | |
michael@0 | 67 | NS_IMPL_QUERY_INTERFACE(nsNativeModuleLoader, |
michael@0 | 68 | mozilla::ModuleLoader) |
michael@0 | 69 | |
michael@0 | 70 | NS_IMPL_ADDREF_USING_AGGREGATOR(nsNativeModuleLoader, |
michael@0 | 71 | nsComponentManagerImpl::gComponentManager) |
michael@0 | 72 | NS_IMPL_RELEASE_USING_AGGREGATOR(nsNativeModuleLoader, |
michael@0 | 73 | nsComponentManagerImpl::gComponentManager) |
michael@0 | 74 | |
michael@0 | 75 | nsresult |
michael@0 | 76 | nsNativeModuleLoader::Init() |
michael@0 | 77 | { |
michael@0 | 78 | MOZ_ASSERT(NS_IsMainThread(), "Startup not on main thread?"); |
michael@0 | 79 | LOG(PR_LOG_DEBUG, ("nsNativeModuleLoader::Init()")); |
michael@0 | 80 | return NS_OK; |
michael@0 | 81 | } |
michael@0 | 82 | |
michael@0 | 83 | class LoadModuleMainThreadRunnable : public nsRunnable |
michael@0 | 84 | { |
michael@0 | 85 | public: |
michael@0 | 86 | LoadModuleMainThreadRunnable(nsNativeModuleLoader* loader, |
michael@0 | 87 | FileLocation &file) |
michael@0 | 88 | : mLoader(loader) |
michael@0 | 89 | , mFile(file) |
michael@0 | 90 | , mResult(nullptr) |
michael@0 | 91 | { } |
michael@0 | 92 | |
michael@0 | 93 | NS_IMETHOD Run() |
michael@0 | 94 | { |
michael@0 | 95 | mResult = mLoader->LoadModule(mFile); |
michael@0 | 96 | return NS_OK; |
michael@0 | 97 | } |
michael@0 | 98 | |
michael@0 | 99 | nsRefPtr<nsNativeModuleLoader> mLoader; |
michael@0 | 100 | FileLocation mFile; |
michael@0 | 101 | const mozilla::Module* mResult; |
michael@0 | 102 | }; |
michael@0 | 103 | |
michael@0 | 104 | const mozilla::Module* |
michael@0 | 105 | nsNativeModuleLoader::LoadModule(FileLocation &aFile) |
michael@0 | 106 | { |
michael@0 | 107 | if (aFile.IsZip()) { |
michael@0 | 108 | NS_ERROR("Binary components cannot be loaded from JARs"); |
michael@0 | 109 | return nullptr; |
michael@0 | 110 | } |
michael@0 | 111 | nsCOMPtr<nsIFile> file = aFile.GetBaseFile(); |
michael@0 | 112 | nsresult rv; |
michael@0 | 113 | |
michael@0 | 114 | if (!NS_IsMainThread()) { |
michael@0 | 115 | // If this call is off the main thread, synchronously proxy it |
michael@0 | 116 | // to the main thread. |
michael@0 | 117 | nsRefPtr<LoadModuleMainThreadRunnable> r = new LoadModuleMainThreadRunnable(this, aFile); |
michael@0 | 118 | NS_DispatchToMainThread(r, NS_DISPATCH_SYNC); |
michael@0 | 119 | return r->mResult; |
michael@0 | 120 | } |
michael@0 | 121 | |
michael@0 | 122 | nsCOMPtr<nsIHashable> hashedFile(do_QueryInterface(file)); |
michael@0 | 123 | if (!hashedFile) { |
michael@0 | 124 | NS_ERROR("nsIFile is not nsIHashable"); |
michael@0 | 125 | return nullptr; |
michael@0 | 126 | } |
michael@0 | 127 | |
michael@0 | 128 | nsAutoCString filePath; |
michael@0 | 129 | file->GetNativePath(filePath); |
michael@0 | 130 | |
michael@0 | 131 | NativeLoadData data; |
michael@0 | 132 | |
michael@0 | 133 | if (mLibraries.Get(hashedFile, &data)) { |
michael@0 | 134 | NS_ASSERTION(data.module, "Corrupt mLibraries hash"); |
michael@0 | 135 | LOG(PR_LOG_DEBUG, |
michael@0 | 136 | ("nsNativeModuleLoader::LoadModule(\"%s\") - found in cache", |
michael@0 | 137 | filePath.get())); |
michael@0 | 138 | return data.module; |
michael@0 | 139 | } |
michael@0 | 140 | |
michael@0 | 141 | // We haven't loaded this module before |
michael@0 | 142 | { |
michael@0 | 143 | #ifdef HAS_DLL_BLOCKLIST |
michael@0 | 144 | AutoSetXPCOMLoadOnMainThread guard; |
michael@0 | 145 | #endif |
michael@0 | 146 | rv = file->Load(&data.library); |
michael@0 | 147 | } |
michael@0 | 148 | |
michael@0 | 149 | if (NS_FAILED(rv)) { |
michael@0 | 150 | char errorMsg[1024] = "<unknown; can't get error from NSPR>"; |
michael@0 | 151 | |
michael@0 | 152 | if (PR_GetErrorTextLength() < (int) sizeof(errorMsg)) |
michael@0 | 153 | PR_GetErrorText(errorMsg); |
michael@0 | 154 | |
michael@0 | 155 | LogMessage("Failed to load native module at path '%s': (%lx) %s", |
michael@0 | 156 | filePath.get(), rv, errorMsg); |
michael@0 | 157 | |
michael@0 | 158 | return nullptr; |
michael@0 | 159 | } |
michael@0 | 160 | |
michael@0 | 161 | #ifdef IMPLEMENT_BREAK_AFTER_LOAD |
michael@0 | 162 | nsAutoCString leafName; |
michael@0 | 163 | file->GetNativeLeafName(leafName); |
michael@0 | 164 | |
michael@0 | 165 | char *env = getenv("XPCOM_BREAK_ON_LOAD"); |
michael@0 | 166 | char *blist; |
michael@0 | 167 | if (env && *env && (blist = strdup(env))) { |
michael@0 | 168 | char *nextTok = blist; |
michael@0 | 169 | while (char *token = NS_strtok(":", &nextTok)) { |
michael@0 | 170 | if (leafName.Find(token, true) != kNotFound) { |
michael@0 | 171 | NS_BREAK(); |
michael@0 | 172 | } |
michael@0 | 173 | } |
michael@0 | 174 | |
michael@0 | 175 | free(blist); |
michael@0 | 176 | } |
michael@0 | 177 | #endif |
michael@0 | 178 | |
michael@0 | 179 | void *module = PR_FindSymbol(data.library, "NSModule"); |
michael@0 | 180 | if (!module) { |
michael@0 | 181 | LogMessage("Native module at path '%s' doesn't export symbol `NSModule`.", |
michael@0 | 182 | filePath.get()); |
michael@0 | 183 | PR_UnloadLibrary(data.library); |
michael@0 | 184 | return nullptr; |
michael@0 | 185 | } |
michael@0 | 186 | |
michael@0 | 187 | data.module = *(mozilla::Module const *const *) module; |
michael@0 | 188 | if (mozilla::Module::kVersion != data.module->mVersion) { |
michael@0 | 189 | LogMessage("Native module at path '%s' is incompatible with this version of Firefox, has version %i, expected %i.", |
michael@0 | 190 | filePath.get(), data.module->mVersion, |
michael@0 | 191 | mozilla::Module::kVersion); |
michael@0 | 192 | PR_UnloadLibrary(data.library); |
michael@0 | 193 | return nullptr; |
michael@0 | 194 | } |
michael@0 | 195 | |
michael@0 | 196 | mLibraries.Put(hashedFile, data); // infallible |
michael@0 | 197 | return data.module; |
michael@0 | 198 | } |
michael@0 | 199 | |
michael@0 | 200 | PLDHashOperator |
michael@0 | 201 | nsNativeModuleLoader::ReleaserFunc(nsIHashable* aHashedFile, |
michael@0 | 202 | NativeLoadData& aLoadData, void*) |
michael@0 | 203 | { |
michael@0 | 204 | aLoadData.module = nullptr; |
michael@0 | 205 | return PL_DHASH_NEXT; |
michael@0 | 206 | } |
michael@0 | 207 | |
michael@0 | 208 | PLDHashOperator |
michael@0 | 209 | nsNativeModuleLoader::UnloaderFunc(nsIHashable* aHashedFile, |
michael@0 | 210 | NativeLoadData& aLoadData, void*) |
michael@0 | 211 | { |
michael@0 | 212 | if (PR_LOG_TEST(GetNativeModuleLoaderLog(), PR_LOG_DEBUG)) { |
michael@0 | 213 | nsCOMPtr<nsIFile> file(do_QueryInterface(aHashedFile)); |
michael@0 | 214 | |
michael@0 | 215 | nsAutoCString filePath; |
michael@0 | 216 | file->GetNativePath(filePath); |
michael@0 | 217 | |
michael@0 | 218 | LOG(PR_LOG_DEBUG, |
michael@0 | 219 | ("nsNativeModuleLoader::UnloaderFunc(\"%s\")", filePath.get())); |
michael@0 | 220 | } |
michael@0 | 221 | |
michael@0 | 222 | #ifdef NS_BUILD_REFCNT_LOGGING |
michael@0 | 223 | nsTraceRefcnt::SetActivityIsLegal(false); |
michael@0 | 224 | #endif |
michael@0 | 225 | |
michael@0 | 226 | #if 0 |
michael@0 | 227 | // XXXbsmedberg: do this as soon as the static-destructor crash(es) |
michael@0 | 228 | // are fixed |
michael@0 | 229 | PRStatus ret = PR_UnloadLibrary(aLoadData.library); |
michael@0 | 230 | NS_ASSERTION(ret == PR_SUCCESS, "Failed to unload library"); |
michael@0 | 231 | #endif |
michael@0 | 232 | |
michael@0 | 233 | #ifdef NS_BUILD_REFCNT_LOGGING |
michael@0 | 234 | nsTraceRefcnt::SetActivityIsLegal(true); |
michael@0 | 235 | #endif |
michael@0 | 236 | |
michael@0 | 237 | return PL_DHASH_REMOVE; |
michael@0 | 238 | } |
michael@0 | 239 | |
michael@0 | 240 | void |
michael@0 | 241 | nsNativeModuleLoader::UnloadLibraries() |
michael@0 | 242 | { |
michael@0 | 243 | MOZ_ASSERT(NS_IsMainThread(), "Shutdown not on main thread?"); |
michael@0 | 244 | mLibraries.Enumerate(ReleaserFunc, nullptr); |
michael@0 | 245 | mLibraries.Enumerate(UnloaderFunc, nullptr); |
michael@0 | 246 | } |