Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/browser/app/nsBrowserApp.cpp
Line
Count
Source (jump to first uncovered line)
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 "application.ini.h"
9
#include "mozilla/Bootstrap.h"
10
#if defined(XP_WIN)
11
#include <windows.h>
12
#include <stdlib.h>
13
#elif defined(XP_UNIX)
14
#include <sys/resource.h>
15
#include <unistd.h>
16
#endif
17
18
#include <stdio.h>
19
#include <stdarg.h>
20
#include <time.h>
21
22
#include "nsCOMPtr.h"
23
#include "nsIFile.h"
24
25
#ifdef XP_WIN
26
#include "LauncherProcessWin.h"
27
28
#define XRE_WANT_ENVIRON
29
#define strcasecmp _stricmp
30
#ifdef MOZ_SANDBOX
31
#include "mozilla/sandboxing/SandboxInitialization.h"
32
#endif
33
#endif
34
#include "BinaryPath.h"
35
36
#include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
37
38
#include "mozilla/Sprintf.h"
39
#include "mozilla/StartupTimeline.h"
40
#include "mozilla/WindowsDllBlocklist.h"
41
42
#ifdef LIBFUZZER
43
#include "FuzzerDefs.h"
44
#endif
45
46
#ifdef MOZ_LINUX_32_SSE2_STARTUP_ERROR
47
#include <cpuid.h>
48
#include "mozilla/Unused.h"
49
50
static bool
51
IsSSE2Available()
52
{
53
  // The rest of the app has been compiled to assume that SSE2 is present
54
  // unconditionally, so we can't use the normal copy of SSE.cpp here.
55
  // Since SSE.cpp caches the results and we need them only transiently,
56
  // instead of #including SSE.cpp here, let's just inline the specific check
57
  // that's needed.
58
  unsigned int level = 1u;
59
  unsigned int eax, ebx, ecx, edx;
60
  unsigned int bits = (1u<<26);
61
  unsigned int max = __get_cpuid_max(0, nullptr);
62
  if (level > max) {
63
    return false;
64
  }
65
  __cpuid_count(level, 0, eax, ebx, ecx, edx);
66
  return (edx & bits) == bits;
67
}
68
69
static const char sSSE2Message[] =
70
    "This browser version requires a processor with the SSE2 instruction "
71
    "set extension.\nYou may be able to obtain a version that does not "
72
    "require SSE2 from your Linux distribution.\n";
73
74
__attribute__((constructor))
75
static void
76
SSE2Check()
77
{
78
  if (IsSSE2Available()) {
79
    return;
80
  }
81
  // Using write() in order to avoid jemalloc-based buffering. Ignoring return
82
  // values, since there isn't much we could do on failure and there is no
83
  // point in trying to recover from errors.
84
  MOZ_UNUSED(write(STDERR_FILENO,
85
                   sSSE2Message,
86
                   MOZ_ARRAY_LENGTH(sSSE2Message) - 1));
87
  // _exit() instead of exit() to avoid running the usual "at exit" code.
88
  _exit(255);
89
}
90
#endif
91
92
#if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID)
93
#define MOZ_BROWSER_CAN_BE_CONTENTPROC
94
#include "../../ipc/contentproc/plugin-container.cpp"
95
#endif
96
97
using namespace mozilla;
98
99
#ifdef XP_MACOSX
100
#define kOSXResourcesFolder "Resources"
101
#endif
102
3
#define kDesktopFolder "browser"
103
104
static MOZ_FORMAT_PRINTF(1, 2) void Output(const char *fmt, ... )
105
0
{
106
0
  va_list ap;
107
0
  va_start(ap, fmt);
108
0
109
0
#ifndef XP_WIN
110
0
  vfprintf(stderr, fmt, ap);
111
#else
112
  char msg[2048];
113
  vsnprintf_s(msg, _countof(msg), _TRUNCATE, fmt, ap);
114
115
  wchar_t wide_msg[2048];
116
  MultiByteToWideChar(CP_UTF8,
117
                      0,
118
                      msg,
119
                      -1,
120
                      wide_msg,
121
                      _countof(wide_msg));
122
#if MOZ_WINCONSOLE
123
  fwprintf_s(stderr, 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", MB_OK
133
                                               | MB_ICONERROR
134
                                               | MB_SETFOREGROUND);
135
    }
136
    FreeLibrary(user32);
137
  }
138
#endif
139
#endif
140
141
0
  va_end(ap);
142
0
}
143
144
/**
145
 * Return true if |arg| matches the given argument name.
146
 */
147
static bool IsArg(const char* arg, const char* s)
148
9
{
149
9
  if (*arg == '-')
150
9
  {
151
9
    if (*++arg == '-')
152
0
      ++arg;
153
9
    return !strcasecmp(arg, s);
154
9
  }
155
0
156
#if defined(XP_WIN)
157
  if (*arg == '/')
158
    return !strcasecmp(++arg, s);
159
#endif
160
161
0
  return false;
162
0
}
163
164
Bootstrap::UniquePtr gBootstrap;
165
166
static int do_main(int argc, char* argv[], char* envp[])
167
3
{
168
3
  // Allow firefox.exe to launch XULRunner apps via -app <application.ini>
169
3
  // Note that -app must be the *first* argument.
170
3
  const char *appDataFile = getenv("XUL_APP_FILE");
171
3
  if ((!appDataFile || !*appDataFile) &&
172
3
      (argc > 1 && IsArg(argv[1], "app"))) {
173
0
    if (argc == 2) {
174
0
      Output("Incorrect number of arguments passed to -app");
175
0
      return 255;
176
0
    }
177
0
    appDataFile = argv[2];
178
0
179
0
    char appEnv[MAXPATHLEN];
180
0
    SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]);
181
0
    if (putenv(strdup(appEnv))) {
182
0
      Output("Couldn't set %s.\n", appEnv);
183
0
      return 255;
184
0
    }
185
0
    argv[2] = argv[0];
186
0
    argv += 2;
187
0
    argc -= 2;
188
3
  } else if (argc > 1 && IsArg(argv[1], "xpcshell")) {
189
0
    for (int i = 1; i < argc; i++) {
190
0
      argv[i] = argv[i + 1];
191
0
    }
192
0
193
0
    XREShellData shellData;
194
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
195
    shellData.sandboxBrokerServices =
196
      sandboxing::GetInitializedBrokerServices();
197
#endif
198
199
0
    return gBootstrap->XRE_XPCShellMain(--argc, argv, envp, &shellData);
200
0
  }
201
3
202
3
  BootstrapConfig config;
203
3
204
3
  if (appDataFile && *appDataFile) {
205
0
    config.appData = nullptr;
206
0
    config.appDataPath = appDataFile;
207
3
  } else {
208
3
    // no -app flag so we use the compiled-in app data
209
3
    config.appData = &sAppData;
210
3
    config.appDataPath = kDesktopFolder;
211
3
  }
212
3
213
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
214
  sandbox::BrokerServices* brokerServices =
215
    sandboxing::GetInitializedBrokerServices();
216
  sandboxing::PermissionsService* permissionsService =
217
    sandboxing::GetPermissionsService();
218
#if defined(MOZ_CONTENT_SANDBOX)
219
  if (!brokerServices) {
220
    Output("Couldn't initialize the broker services.\n");
221
    return 255;
222
  }
223
#endif
224
  config.sandboxBrokerServices = brokerServices;
225
  config.sandboxPermissionsService = permissionsService;
226
#endif
227
228
3
#ifdef LIBFUZZER
229
3
  if (getenv("LIBFUZZER"))
230
3
    gBootstrap->XRE_LibFuzzerSetDriver(fuzzer::FuzzerDriver);
231
3
#endif
232
3
233
3
  return gBootstrap->XRE_main(argc, argv, config);
234
3
}
235
236
static nsresult
237
InitXPCOMGlue()
238
3
{
239
3
  UniqueFreePtr<char> exePath = BinaryPath::Get();
240
3
  if (!exePath) {
241
0
    Output("Couldn't find the application directory.\n");
242
0
    return NS_ERROR_FAILURE;
243
0
  }
244
3
245
3
  gBootstrap = mozilla::GetBootstrap(exePath.get());
246
3
  if (!gBootstrap) {
247
0
    Output("Couldn't load XPCOM.\n");
248
0
    return NS_ERROR_FAILURE;
249
0
  }
250
3
251
3
  // This will set this thread as the main thread.
252
3
  gBootstrap->NS_LogInit();
253
3
254
3
  return NS_OK;
255
3
}
256
257
#ifdef HAS_DLL_BLOCKLIST
258
// NB: This must be extern, as this value is checked elsewhere
259
uint32_t gBlocklistInitFlags = eDllBlocklistInitFlagDefault;
260
#endif
261
262
int main(int argc, char* argv[], char* envp[])
263
3
{
264
3
  mozilla::TimeStamp start = mozilla::TimeStamp::Now();
265
3
266
3
#ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
267
3
  // We are launching as a content process, delegate to the appropriate
268
3
  // main
269
3
  if (argc > 1 && IsArg(argv[1], "contentproc")) {
270
#ifdef HAS_DLL_BLOCKLIST
271
    DllBlocklist_Initialize(eDllBlocklistInitFlagIsChildProcess);
272
#endif
273
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
274
    // We need to initialize the sandbox TargetServices before InitXPCOMGlue
275
    // because we might need the sandbox broker to give access to some files.
276
    if (IsSandboxedProcess() && !sandboxing::GetInitializedTargetServices()) {
277
      Output("Failed to initialize the sandbox target services.");
278
      return 255;
279
    }
280
#endif
281
282
0
    nsresult rv = InitXPCOMGlue();
283
0
    if (NS_FAILED(rv)) {
284
0
      return 255;
285
0
    }
286
0
287
0
    int result = content_process_main(gBootstrap.get(), argc, argv);
288
0
289
#if defined(DEBUG) && defined(HAS_DLL_BLOCKLIST)
290
    DllBlocklist_Shutdown();
291
#endif
292
293
0
    // InitXPCOMGlue calls NS_LogInit, so we need to balance it here.
294
0
    gBootstrap->NS_LogTerm();
295
0
296
0
    return result;
297
0
  }
298
3
#endif
299
3
300
#ifdef HAS_DLL_BLOCKLIST
301
  DllBlocklist_Initialize(gBlocklistInitFlags);
302
#endif
303
304
3
  nsresult rv = InitXPCOMGlue();
305
3
  if (NS_FAILED(rv)) {
306
0
    return 255;
307
0
  }
308
3
309
3
  gBootstrap->XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
310
3
311
3
#ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
312
3
  gBootstrap->XRE_EnableSameExecutableForContentProc();
313
3
#endif
314
3
315
3
  int result = do_main(argc, argv, envp);
316
3
317
3
  gBootstrap->NS_LogTerm();
318
3
319
#if defined(DEBUG) && defined(HAS_DLL_BLOCKLIST)
320
  DllBlocklist_Shutdown();
321
#endif
322
323
#ifdef XP_MACOSX
324
  // Allow writes again. While we would like to catch writes from static
325
  // destructors to allow early exits to use _exit, we know that there is
326
  // at least one such write that we don't control (see bug 826029). For
327
  // now we enable writes again and early exits will have to use exit instead
328
  // of _exit.
329
  gBootstrap->XRE_StopLateWriteChecks();
330
#endif
331
332
3
  gBootstrap.reset();
333
3
334
3
  return result;
335
3
}