/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 | } |