Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/browser/app/nsBrowserApp.cpp
Warning:line 178, column 15
Potential memory leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name nsBrowserApp.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/browser/app -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/browser/app -resource-dir /usr/lib/llvm-18/lib/clang/18 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D XPCOM_GLUE -D MOZ_HAS_MOZGLUE -D MOZ_GECKODRIVER -D FIREFOX_ICO="/var/lib/jenkins/workspace/firefox-scan-build/browser/branding/unofficial/firefox.ico" -D DOCUMENT_ICO="/var/lib/jenkins/workspace/firefox-scan-build/browser/branding/unofficial/document.ico" -D NEWWINDOW_ICO="/var/lib/jenkins/workspace/firefox-scan-build/browser/branding/unofficial/newwindow.ico" -D NEWTAB_ICO="/var/lib/jenkins/workspace/firefox-scan-build/browser/branding/unofficial/newtab.ico" -D PBMODE_ICO="/var/lib/jenkins/workspace/firefox-scan-build/browser/branding/unofficial/pbmode.ico" -D DOCUMENT_PDF_ICO="/var/lib/jenkins/workspace/firefox-scan-build/browser/branding/unofficial/document_pdf.ico" -I /var/lib/jenkins/workspace/firefox-scan-build/browser/app -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/browser/app -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/build -I /var/lib/jenkins/workspace/firefox-scan-build/toolkit/xre -I /var/lib/jenkins/workspace/firefox-scan-build/xpcom/base -I /var/lib/jenkins/workspace/firefox-scan-build/xpcom/build -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/x86_64-linux-gnu/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-16-034744-15991-1 -x c++ /var/lib/jenkins/workspace/firefox-scan-build/browser/app/nsBrowserApp.cpp
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6#include "nsXULAppAPI.h"
7#include "mozilla/XREAppData.h"
8#include "XREShellData.h"
9#include "application.ini.h"
10#include "mozilla/Bootstrap.h"
11#include "mozilla/ProcessType.h"
12#include "mozilla/RuntimeExceptionModule.h"
13#include "mozilla/ScopeExit.h"
14#include "BrowserDefines.h"
15#if defined(XP_WIN)
16# include <windows.h>
17# include <stdlib.h>
18#elif defined(XP_UNIX1)
19# include <sys/resource.h>
20# include <unistd.h>
21# include <fcntl.h>
22#endif
23
24#include <stdio.h>
25#include <stdarg.h>
26#include <time.h>
27
28#include "nsCOMPtr.h"
29
30#ifdef XP_WIN
31# include "mozilla/PreXULSkeletonUI.h"
32# include "freestanding/SharedSection.h"
33# include "LauncherProcessWin.h"
34# include "mozilla/GeckoArgs.h"
35# include "mozilla/mscom/ProcessRuntime.h"
36# include "mozilla/WindowsDllBlocklist.h"
37# include "mozilla/WindowsDpiInitialization.h"
38# include "mozilla/WindowsProcessMitigations.h"
39
40# define XRE_WANT_ENVIRON
41# define strcasecmp _stricmp
42# ifdef MOZ_SANDBOX1
43# include "mozilla/sandboxing/SandboxInitialization.h"
44# endif
45#endif
46#include "BinaryPath.h"
47
48#include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
49
50#include "mozilla/Sprintf.h"
51#include "mozilla/StartupTimeline.h"
52#include "BaseProfiler.h"
53
54#ifdef LIBFUZZER
55# include "FuzzerDefs.h"
56#endif
57
58#ifdef MOZ_LINUX_32_SSE2_STARTUP_ERROR
59# include <cpuid.h>
60# include "mozilla/Unused.h"
61
62static bool IsSSE2Available() {
63 // The rest of the app has been compiled to assume that SSE2 is present
64 // unconditionally, so we can't use the normal copy of SSE.cpp here.
65 // Since SSE.cpp caches the results and we need them only transiently,
66 // instead of #including SSE.cpp here, let's just inline the specific check
67 // that's needed.
68 unsigned int level = 1u;
69 unsigned int eax, ebx, ecx, edx;
70 unsigned int bits = (1u << 26);
71 unsigned int max = __get_cpuid_max(0, nullptr);
72 if (level > max) {
73 return false;
74 }
75 __cpuid_count(level, 0, eax, ebx, ecx, edx);
76 return (edx & bits) == bits;
77}
78
79static const char sSSE2Message[] =
80 "This browser version requires a processor with the SSE2 instruction "
81 "set extension.\nYou may be able to obtain a version that does not "
82 "require SSE2 from your Linux distribution.\n";
83
84__attribute__((constructor)) static void SSE2Check() {
85 if (IsSSE2Available()) {
86 return;
87 }
88 // Using write() in order to avoid jemalloc-based buffering. Ignoring return
89 // values, since there isn't much we could do on failure and there is no
90 // point in trying to recover from errors.
91 MOZ_UNUSED(do { if (write(2, sSSE2Message, sizeof(mozilla::detail::ArrayLengthHelper
(sSSE2Message)) - 1)) { (void)0; } } while (0)
92 write(STDERR_FILENO, sSSE2Message, MOZ_ARRAY_LENGTH(sSSE2Message) - 1))do { if (write(2, sSSE2Message, sizeof(mozilla::detail::ArrayLengthHelper
(sSSE2Message)) - 1)) { (void)0; } } while (0)
;
93 // _exit() instead of exit() to avoid running the usual "at exit" code.
94 _exit(255);
95}
96#endif
97
98#if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID)
99# define MOZ_BROWSER_CAN_BE_CONTENTPROC
100# include "../../ipc/contentproc/plugin-container.cpp"
101#endif
102
103using namespace mozilla;
104
105#ifdef XP_MACOSX
106# define kOSXResourcesFolder "Resources"
107#endif
108#define kDesktopFolder"browser" "browser"
109
110static MOZ_FORMAT_PRINTF(1, 2)__attribute__((format(printf, 1, 2))) void Output(const char* fmt, ...) {
111 va_list ap;
112 va_start(ap, fmt)__builtin_va_start(ap, fmt);
113
114#ifndef XP_WIN
115 vfprintf(stderrstderr, fmt, ap);
116#else
117 char msg[2048];
118 vsnprintf_s(msg, _countof(msg), _TRUNCATE, fmt, ap);
119
120 wchar_t wide_msg[2048];
121 MultiByteToWideChar(CP_UTF8, 0, msg, -1, wide_msg, _countof(wide_msg));
122# if MOZ_WINCONSOLE
123 fwprintf_s(stderrstderr, wide_msg);
124# else
125 // Linking user32 at load-time interferes with the DLL blocklist (bug 932100).
126 // This is a rare codepath, so we can load user32 at run-time instead.
127 HMODULE user32 = LoadLibraryW(L"user32.dll");
128 if (user32) {
129 decltype(MessageBoxW)* messageBoxW =
130 (decltype(MessageBoxW)*)GetProcAddress(user32, "MessageBoxW");
131 if (messageBoxW) {
132 messageBoxW(nullptr, wide_msg, L"Firefox",
133 MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
134 }
135 FreeLibrary(user32);
136 }
137# endif
138#endif
139
140 va_end(ap)__builtin_va_end(ap);
141}
142
143/**
144 * Return true if |arg| matches the given argument name.
145 */
146static bool IsArg(const char* arg, const char* s) {
147 if (*arg == '-') {
148 if (*++arg == '-') ++arg;
149 return !strcasecmp(arg, s);
150 }
151
152#if defined(XP_WIN)
153 if (*arg == '/') return !strcasecmp(++arg, s);
154#endif
155
156 return false;
157}
158
159Bootstrap::UniquePtr gBootstrap;
160
161static int do_main(int argc, char* argv[], char* envp[]) {
162 // Allow firefox.exe to launch XULRunner apps via -app <application.ini>
163 // Note that -app must be the *first* argument.
164 const char* appDataFile = getenv("XUL_APP_FILE");
165 if ((!appDataFile
6.1
'appDataFile' is null
|| !*appDataFile) && (argc
6.2
'argc' is > 1
> 1 && IsArg(argv[1], "app"))) {
7
Taking true branch
166 if (argc == 2) {
8
Assuming 'argc' is not equal to 2
9
Taking false branch
167 Output("Incorrect number of arguments passed to -app");
168 return 255;
169 }
170 appDataFile = argv[2];
171
172 char appEnv[MAXPATHLEN4096];
173 SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]);
174 if (putenv(strdup(appEnv))) {
10
Memory is allocated
11
Assuming the condition is false
12
Taking false branch
175 Output("Couldn't set %s.\n", appEnv);
176 return 255;
177 }
178 argv[2] = argv[0];
13
Potential memory leak
179 argv += 2;
180 argc -= 2;
181 } else if (argc > 1 && IsArg(argv[1], "xpcshell")) {
182 for (int i = 1; i < argc; i++) {
183 argv[i] = argv[i + 1];
184 }
185
186 XREShellData shellData;
187#if defined(XP_WIN) && defined(MOZ_SANDBOX1)
188 shellData.sandboxBrokerServices =
189 sandboxing::GetInitializedBrokerServices();
190#endif
191
192#ifdef LIBFUZZER
193 shellData.fuzzerDriver = fuzzer::FuzzerDriver;
194#endif
195#ifdef AFLFUZZ
196 shellData.fuzzerDriver = afl_interface_raw;
197#endif
198
199 return gBootstrap->XRE_XPCShellMain(--argc, argv, envp, &shellData);
200 }
201
202 BootstrapConfig config;
203
204 if (appDataFile && *appDataFile) {
205 config.appData = nullptr;
206 config.appDataPath = appDataFile;
207 } else {
208 // no -app flag so we use the compiled-in app data
209 config.appData = &sAppData;
210 config.appDataPath = kDesktopFolder"browser";
211 }
212
213#if defined(XP_WIN) && defined(MOZ_SANDBOX1)
214 sandbox::BrokerServices* brokerServices =
215 sandboxing::GetInitializedBrokerServices();
216 if (!brokerServices) {
217 Output("Couldn't initialize the broker services.\n");
218 return 255;
219 }
220 config.sandboxBrokerServices = brokerServices;
221#endif
222
223#ifdef LIBFUZZER
224 if (getenv("FUZZER"))
225 gBootstrap->XRE_LibFuzzerSetDriver(fuzzer::FuzzerDriver);
226#endif
227
228 EnsureBrowserCommandlineSafe(argc, argv);
229
230 return gBootstrap->XRE_main(argc, argv, config);
231}
232
233static nsresult InitXPCOMGlue(LibLoadingStrategy aLibLoadingStrategy) {
234 if (gBootstrap) {
235 return NS_OK;
236 }
237
238 UniqueFreePtr<char> exePath = BinaryPath::Get();
239 if (!exePath) {
240 Output("Couldn't find the application directory.\n");
241 return NS_ERROR_FAILURE;
242 }
243
244 auto bootstrapResult =
245 mozilla::GetBootstrap(exePath.get(), aLibLoadingStrategy);
246 if (bootstrapResult.isErr()) {
247 Output("Couldn't load XPCOM.\n");
248 return NS_ERROR_FAILURE;
249 }
250
251 gBootstrap = bootstrapResult.unwrap();
252
253 // This will set this thread as the main thread.
254 gBootstrap->NS_LogInit();
255
256 return NS_OK;
257}
258
259#ifdef HAS_DLL_BLOCKLIST
260// NB: This must be extern, as this value is checked elsewhere
261uint32_t gBlocklistInitFlags = eDllBlocklistInitFlagDefault;
262#endif
263
264#if defined(XP_UNIX1)
265static void ReserveDefaultFileDescriptors() {
266 // Reserve the lower positions of the file descriptors to make sure
267 // we don't reuse stdin/stdout/stderr in case they we closed
268 // before launch.
269 // Otherwise code explicitly writing to fd 1 or 2 might accidentally
270 // write to something else, like in bug 1820896 where FD 1 is
271 // reused for the X server display connection.
272 int fd = open("/dev/null", O_RDONLY00);
273 for (int i = 0; i < 2; i++) {
274 mozilla::Unused << dup(fd);
275 }
276}
277#endif
278
279int main(int argc, char* argv[], char* envp[]) {
280#if defined(XP_UNIX1)
281 ReserveDefaultFileDescriptors();
282#endif
283#if defined(MOZ_ENABLE_FORKSERVER1)
284 if (strcmp(argv[argc - 1], "forkserver") == 0) {
1
Assuming the condition is false
2
Taking false branch
285 nsresult rv = InitXPCOMGlue(LibLoadingStrategy::NoReadAhead);
286 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
287 return 255;
288 }
289
290 // Run a fork server in this process, single thread. When it
291 // returns, it means the fork server have been stopped or a new
292 // content process is created.
293 //
294 // For the later case, XRE_ForkServer() will return false, running
295 // in a content process just forked from the fork server process.
296 // argc & argv will be updated with the values passing from the
297 // chrome process. With the new values, this function
298 // continues the reset of the code acting as a content process.
299 if (gBootstrap->XRE_ForkServer(&argc, &argv)) {
300 // Return from the fork server in the fork server process.
301 // Stop the fork server.
302 gBootstrap->NS_LogTerm();
303 return 0;
304 }
305 // In a content process forked from the fork server.
306 // Start acting as a content process.
307 }
308#endif
309
310 mozilla::TimeStamp start = mozilla::TimeStamp::Now();
311
312 AUTO_BASE_PROFILER_INIT::mozilla::baseprofiler::AutoProfilerInit raiiObject312;
313 AUTO_BASE_PROFILER_LABEL("nsBrowserApp main", OTHER)::mozilla::baseprofiler::AutoProfilerLabel raiiObject313( "nsBrowserApp main"
, nullptr, ::mozilla::baseprofiler::ProfilingCategoryPair::OTHER
)
;
314
315 // Make sure we unregister the runtime exception module before returning.
316 // We do this here to cover both registers for child and main processes.
317 auto unregisterRuntimeExceptionModule =
318 MakeScopeExit([] { CrashReporter::UnregisterRuntimeExceptionModule(); });
319
320#ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
321 // We are launching as a content process, delegate to the appropriate
322 // main
323 if (argc > 1 && IsArg(argv[1], "contentproc")) {
3
Assuming 'argc' is > 1
4
Taking false branch
324 // Set the process type. We don't remove the arg here as that will be done
325 // later in common code.
326 SetGeckoProcessType(argv[argc - 1]);
327
328 // Register an external module to report on otherwise uncatchable
329 // exceptions. Note that in child processes this must be called after Gecko
330 // process type has been set.
331 CrashReporter::RegisterRuntimeExceptionModule();
332
333# if defined(XP_WIN) && defined(MOZ_SANDBOX1)
334 // We need to set whether our process is supposed to have win32k locked down
335 // from the command line setting before DllBlocklist_Initialize,
336 // GetInitializedTargetServices and WindowsDpiInitialization.
337 Maybe<bool> win32kLockedDown =
338 mozilla::geckoargs::sWin32kLockedDown.Get(argc, argv);
339 if (win32kLockedDown.isSome() && *win32kLockedDown) {
340 mozilla::SetWin32kLockedDownInPolicy();
341 }
342# endif
343
344# ifdef HAS_DLL_BLOCKLIST
345 uint32_t initFlags =
346 gBlocklistInitFlags | eDllBlocklistInitFlagIsChildProcess;
347 SetDllBlocklistProcessTypeFlags(initFlags, GetGeckoProcessType());
348 DllBlocklist_Initialize(initFlags);
349# endif // HAS_DLL_BLOCKLIST
350
351# if defined(XP_WIN) && defined(MOZ_SANDBOX1)
352 // We need to initialize the sandbox TargetServices before InitXPCOMGlue
353 // because we might need the sandbox broker to give access to some files.
354 if (IsSandboxedProcess() && !sandboxing::GetInitializedTargetServices()) {
355 Output("Failed to initialize the sandbox target services.");
356 return 255;
357 }
358# endif
359# if defined(XP_WIN)
360 // Ideally, we would be able to set our DPI awareness in
361 // firefox.exe.manifest Unfortunately, that would cause Win32k calls when
362 // user32.dll gets loaded, which would be incompatible with Win32k Lockdown
363 //
364 // MSDN says that it's allowed-but-not-recommended to initialize DPI
365 // programatically, as long as it's done before any HWNDs are created.
366 // Thus, we do it almost as soon as we possibly can
367 {
368 auto result = mozilla::WindowsDpiInitialization();
369 (void)result; // Ignore errors since some tools block DPI calls
370 }
371# endif
372
373 nsresult rv = InitXPCOMGlue(LibLoadingStrategy::NoReadAhead);
374 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
375 return 255;
376 }
377
378 int result = content_process_main(gBootstrap.get(), argc, argv);
379
380# if defined(DEBUG1) && defined(HAS_DLL_BLOCKLIST)
381 DllBlocklist_Shutdown();
382# endif
383
384 // InitXPCOMGlue calls NS_LogInit, so we need to balance it here.
385 gBootstrap->NS_LogTerm();
386
387 return result;
388 }
389#endif
390
391 // Register an external module to report on otherwise uncatchable exceptions.
392 CrashReporter::RegisterRuntimeExceptionModule();
393
394#ifdef HAS_DLL_BLOCKLIST
395 DllBlocklist_Initialize(gBlocklistInitFlags);
396#endif
397
398// We will likely only ever support this as a command line argument on Windows
399// and OSX, so we're ifdefing here just to not create any expectations.
400#if defined(XP_WIN) || defined(XP_MACOSX)
401 if (argc > 1 && IsArg(argv[1], "silentmode")) {
402 ::putenv(const_cast<char*>("MOZ_APP_SILENT_START=1"));
403# if defined(XP_WIN)
404 // On windows We also want to set a separate variable, which we want to
405 // persist across restarts, which will let us keep the process alive
406 // even if the last window is closed.
407 ::putenv(const_cast<char*>("MOZ_APP_ALLOW_WINDOWLESS=1"));
408# endif
409# if defined(XP_MACOSX)
410 ::putenv(const_cast<char*>("MOZ_APP_NO_DOCK=1"));
411# endif
412 }
413#endif
414
415#if defined(XP_WIN)
416
417 // Ideally, we would be able to set our DPI awareness in firefox.exe.manifest
418 // Unfortunately, that would cause Win32k calls when user32.dll gets loaded,
419 // which would be incompatible with Win32k Lockdown
420 //
421 // MSDN says that it's allowed-but-not-recommended to initialize DPI
422 // programatically, as long as it's done before any HWNDs are created.
423 // Thus, we do it almost as soon as we possibly can
424 {
425 auto result = mozilla::WindowsDpiInitialization();
426 (void)result; // Ignore errors since some tools block DPI calls
427 }
428
429 // Once the browser process hits the main function, we no longer need
430 // a writable section handle because all dependent modules have been
431 // loaded.
432 mozilla::freestanding::gSharedSection.ConvertToReadOnly();
433
434 mozilla::CreateAndStorePreXULSkeletonUI(GetModuleHandle(nullptr), argc, argv);
435#endif
436
437 nsresult rv = InitXPCOMGlue(LibLoadingStrategy::ReadAhead);
438 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5
Taking false branch
439 return 255;
440 }
441
442 gBootstrap->XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
443
444#ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
445 gBootstrap->XRE_EnableSameExecutableForContentProc();
446#endif
447
448 int result = do_main(argc, argv, envp);
6
Calling 'do_main'
449
450#if defined(XP_WIN)
451 CleanupProcessRuntime();
452#endif
453
454 gBootstrap->NS_LogTerm();
455
456#if defined(DEBUG1) && defined(HAS_DLL_BLOCKLIST)
457 DllBlocklist_Shutdown();
458#endif
459
460#ifdef XP_MACOSX
461 // Allow writes again. While we would like to catch writes from static
462 // destructors to allow early exits to use _exit, we know that there is
463 // at least one such write that we don't control (see bug 826029). For
464 // now we enable writes again and early exits will have to use exit instead
465 // of _exit.
466 gBootstrap->XRE_StopLateWriteChecks();
467#endif
468
469 gBootstrap.reset();
470
471 return result;
472}