Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/Bootstrap.h"
8 :
9 : #include "nspr.h"
10 : #include "nsDebug.h"
11 : #include "nsIServiceManager.h"
12 : #include "nsXPCOMPrivate.h"
13 : #include "nsCOMPtr.h"
14 : #include <stdlib.h>
15 : #include <stdio.h>
16 :
17 : #include "mozilla/FileUtils.h"
18 : #include "mozilla/Sprintf.h"
19 : #include "mozilla/UniquePtrExtensions.h"
20 :
21 : using namespace mozilla;
22 :
23 : #define XPCOM_DEPENDENT_LIBS_LIST "dependentlibs.list"
24 :
25 : #if defined(XP_WIN)
26 : #define READ_TEXTMODE L"rt"
27 : #else
28 : #define READ_TEXTMODE "r"
29 : #endif
30 :
31 : typedef void (*NSFuncPtr)();
32 :
33 : #if defined(XP_WIN)
34 : #include <windows.h>
35 : #include <mbstring.h>
36 :
37 : typedef HINSTANCE LibHandleType;
38 :
39 : static LibHandleType
40 : GetLibHandle(pathstr_t aDependentLib)
41 : {
42 : LibHandleType libHandle =
43 : LoadLibraryExW(aDependentLib, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
44 :
45 : #ifdef DEBUG
46 : if (!libHandle) {
47 : DWORD err = GetLastError();
48 : LPWSTR lpMsgBuf;
49 : FormatMessageW(
50 : FORMAT_MESSAGE_ALLOCATE_BUFFER |
51 : FORMAT_MESSAGE_FROM_SYSTEM |
52 : FORMAT_MESSAGE_IGNORE_INSERTS,
53 : nullptr,
54 : err,
55 : MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
56 : (LPWSTR)&lpMsgBuf,
57 : 0,
58 : nullptr
59 : );
60 : wprintf(L"Error loading %ls: %s\n", aDependentLib, lpMsgBuf);
61 : LocalFree(lpMsgBuf);
62 : }
63 : #endif
64 :
65 : return libHandle;
66 : }
67 :
68 : static NSFuncPtr
69 : GetSymbol(LibHandleType aLibHandle, const char* aSymbol)
70 : {
71 : return (NSFuncPtr)GetProcAddress(aLibHandle, aSymbol);
72 : }
73 :
74 : static void
75 : CloseLibHandle(LibHandleType aLibHandle)
76 : {
77 : FreeLibrary(aLibHandle);
78 : }
79 :
80 : #else
81 : #include <dlfcn.h>
82 :
83 : #if defined(MOZ_LINKER)
84 : extern "C" {
85 : NS_HIDDEN __typeof(dlopen) __wrap_dlopen;
86 : NS_HIDDEN __typeof(dlsym) __wrap_dlsym;
87 : NS_HIDDEN __typeof(dlclose) __wrap_dlclose;
88 : }
89 :
90 : #define dlopen __wrap_dlopen
91 : #define dlsym __wrap_dlsym
92 : #define dlclose __wrap_dlclose
93 : #endif
94 :
95 : typedef void* LibHandleType;
96 :
97 : static LibHandleType
98 33 : GetLibHandle(pathstr_t aDependentLib)
99 : {
100 : LibHandleType libHandle = dlopen(aDependentLib,
101 : RTLD_GLOBAL | RTLD_LAZY
102 : #ifdef XP_MACOSX
103 : | RTLD_FIRST
104 : #endif
105 33 : );
106 33 : if (!libHandle) {
107 0 : fprintf(stderr, "XPCOMGlueLoad error for file %s:\n%s\n", aDependentLib,
108 0 : dlerror());
109 : }
110 33 : return libHandle;
111 : }
112 :
113 : static NSFuncPtr
114 3 : GetSymbol(LibHandleType aLibHandle, const char* aSymbol)
115 : {
116 3 : return (NSFuncPtr)dlsym(aLibHandle, aSymbol);
117 : }
118 :
119 : #ifndef MOZ_LINKER
120 : static void
121 0 : CloseLibHandle(LibHandleType aLibHandle)
122 : {
123 0 : dlclose(aLibHandle);
124 0 : }
125 : #endif
126 : #endif
127 :
128 : struct DependentLib
129 : {
130 : LibHandleType libHandle;
131 : DependentLib* next;
132 : };
133 :
134 : static DependentLib* sTop;
135 :
136 : static void
137 33 : AppendDependentLib(LibHandleType aLibHandle)
138 : {
139 33 : auto* d = new DependentLib;
140 33 : if (!d) {
141 0 : return;
142 : }
143 :
144 33 : d->next = sTop;
145 33 : d->libHandle = aLibHandle;
146 :
147 33 : sTop = d;
148 : }
149 :
150 : static bool
151 33 : ReadDependentCB(pathstr_t aDependentLib)
152 : {
153 : #ifndef MOZ_LINKER
154 : // We do this unconditionally because of data in bug 771745
155 33 : ReadAheadLib(aDependentLib);
156 : #endif
157 33 : LibHandleType libHandle = GetLibHandle(aDependentLib);
158 33 : if (libHandle) {
159 33 : AppendDependentLib(libHandle);
160 : }
161 :
162 33 : return libHandle;
163 : }
164 :
165 : #ifdef XP_WIN
166 : static bool
167 : ReadDependentCB(const char* aDependentLib)
168 : {
169 : wchar_t wideDependentLib[MAX_PATH];
170 : MultiByteToWideChar(CP_UTF8, 0, aDependentLib, -1, wideDependentLib, MAX_PATH);
171 : return ReadDependentCB(wideDependentLib);
172 : }
173 :
174 : inline FILE*
175 : TS_tfopen(const char* path, const wchar_t* mode)
176 : {
177 : wchar_t wPath[MAX_PATH];
178 : MultiByteToWideChar(CP_UTF8, 0, path, -1, wPath, MAX_PATH);
179 : return _wfopen(wPath, mode);
180 : }
181 : #else
182 : inline FILE*
183 3 : TS_tfopen(const char* aPath, const char* aMode)
184 : {
185 3 : return fopen(aPath, aMode);
186 : }
187 : #endif
188 :
189 : /* RAII wrapper for FILE descriptors */
190 : struct ScopedCloseFileTraits
191 : {
192 : typedef FILE* type;
193 3 : static type empty() { return nullptr; }
194 6 : static void release(type aFile)
195 : {
196 6 : if (aFile) {
197 3 : fclose(aFile);
198 : }
199 6 : }
200 : };
201 : typedef Scoped<ScopedCloseFileTraits> ScopedCloseFile;
202 :
203 : #ifndef MOZ_LINKER
204 : static void
205 0 : XPCOMGlueUnload()
206 : {
207 0 : while (sTop) {
208 0 : CloseLibHandle(sTop->libHandle);
209 :
210 0 : DependentLib* temp = sTop;
211 0 : sTop = sTop->next;
212 :
213 0 : delete temp;
214 : }
215 0 : }
216 : #endif
217 :
218 : #if defined(XP_WIN)
219 : // like strpbrk but finds the *last* char, not the first
220 : static const char*
221 : ns_strrpbrk(const char* string, const char* strCharSet)
222 : {
223 : const char* found = nullptr;
224 : for (; *string; ++string) {
225 : for (const char* search = strCharSet; *search; ++search) {
226 : if (*search == *string) {
227 : found = string;
228 : // Since we're looking for the last char, we save "found"
229 : // until we're at the end of the string.
230 : }
231 : }
232 : }
233 :
234 : return found;
235 : }
236 : #endif
237 :
238 : static nsresult
239 3 : XPCOMGlueLoad(const char* aXPCOMFile)
240 : {
241 : #ifdef MOZ_LINKER
242 : if (!ReadDependentCB(aXPCOMFile)) {
243 : return NS_ERROR_FAILURE;
244 : }
245 : #else
246 : char xpcomDir[MAXPATHLEN];
247 : #ifdef XP_WIN
248 : const char* lastSlash = ns_strrpbrk(aXPCOMFile, "/\\");
249 : #elif XP_MACOSX
250 : // On OSX, the dependentlibs.list file lives under Contents/Resources.
251 : // However, the actual libraries listed in dependentlibs.list live under
252 : // Contents/MacOS. We want to read the list from Contents/Resources, then
253 : // load the libraries from Contents/MacOS.
254 : const char *tempSlash = strrchr(aXPCOMFile, '/');
255 : size_t tempLen = size_t(tempSlash - aXPCOMFile);
256 : if (tempLen > MAXPATHLEN) {
257 : return NS_ERROR_FAILURE;
258 : }
259 : char tempBuffer[MAXPATHLEN];
260 : memcpy(tempBuffer, aXPCOMFile, tempLen);
261 : tempBuffer[tempLen] = '\0';
262 : const char *slash = strrchr(tempBuffer, '/');
263 : tempLen = size_t(slash - tempBuffer);
264 : const char *lastSlash = aXPCOMFile + tempLen;
265 : #else
266 3 : const char* lastSlash = strrchr(aXPCOMFile, '/');
267 : #endif
268 : char* cursor;
269 3 : if (lastSlash) {
270 3 : size_t len = size_t(lastSlash - aXPCOMFile);
271 :
272 3 : if (len > MAXPATHLEN - sizeof(XPCOM_FILE_PATH_SEPARATOR
273 : #ifdef XP_MACOSX
274 : "Resources"
275 : XPCOM_FILE_PATH_SEPARATOR
276 : #endif
277 : XPCOM_DEPENDENT_LIBS_LIST)) {
278 0 : return NS_ERROR_FAILURE;
279 : }
280 3 : memcpy(xpcomDir, aXPCOMFile, len);
281 3 : strcpy(xpcomDir + len, XPCOM_FILE_PATH_SEPARATOR
282 : #ifdef XP_MACOSX
283 : "Resources"
284 : XPCOM_FILE_PATH_SEPARATOR
285 : #endif
286 3 : XPCOM_DEPENDENT_LIBS_LIST);
287 3 : cursor = xpcomDir + len + 1;
288 : } else {
289 0 : strcpy(xpcomDir, XPCOM_DEPENDENT_LIBS_LIST);
290 0 : cursor = xpcomDir;
291 : }
292 :
293 3 : if (getenv("MOZ_RUN_GTEST")) {
294 0 : strcat(xpcomDir, ".gtest");
295 : }
296 :
297 6 : ScopedCloseFile flist;
298 3 : flist = TS_tfopen(xpcomDir, READ_TEXTMODE);
299 3 : if (!flist) {
300 0 : return NS_ERROR_FAILURE;
301 : }
302 :
303 : #ifdef XP_MACOSX
304 : tempLen = size_t(cursor - xpcomDir);
305 : if (tempLen > MAXPATHLEN - sizeof("MacOS" XPCOM_FILE_PATH_SEPARATOR) - 1) {
306 : return NS_ERROR_FAILURE;
307 : }
308 : strcpy(cursor, "MacOS" XPCOM_FILE_PATH_SEPARATOR);
309 : cursor += strlen(cursor);
310 : #endif
311 3 : *cursor = '\0';
312 :
313 : char buffer[MAXPATHLEN];
314 :
315 69 : while (fgets(buffer, sizeof(buffer), flist)) {
316 33 : int l = strlen(buffer);
317 :
318 : // ignore empty lines and comments
319 33 : if (l == 0 || *buffer == '#') {
320 0 : continue;
321 : }
322 :
323 : // cut the trailing newline, if present
324 33 : if (buffer[l - 1] == '\n') {
325 33 : buffer[l - 1] = '\0';
326 : }
327 :
328 33 : if (l + size_t(cursor - xpcomDir) > MAXPATHLEN) {
329 0 : return NS_ERROR_FAILURE;
330 : }
331 :
332 33 : strcpy(cursor, buffer);
333 33 : if (!ReadDependentCB(xpcomDir)) {
334 0 : XPCOMGlueUnload();
335 0 : return NS_ERROR_FAILURE;
336 : }
337 : }
338 : #endif
339 3 : return NS_OK;
340 : }
341 :
342 : #if defined(MOZ_WIDGET_GTK) && (defined(MOZ_MEMORY) || defined(__FreeBSD__) || defined(__NetBSD__))
343 : #define MOZ_GSLICE_INIT
344 : #endif
345 :
346 : #ifdef MOZ_GSLICE_INIT
347 : #include <glib.h>
348 :
349 : class GSliceInit {
350 : public:
351 3 : GSliceInit() {
352 3 : mHadGSlice = bool(getenv("G_SLICE"));
353 3 : if (!mHadGSlice) {
354 : // Disable the slice allocator, since jemalloc already uses similar layout
355 : // algorithms, and using a sub-allocator tends to increase fragmentation.
356 : // This must be done before g_thread_init() is called.
357 : // glib >= 2.36 initializes g_slice as a side effect of its various static
358 : // initializers, so this needs to happen before glib is loaded, which is
359 : // this is hooked in XPCOMGlueStartup before libxul is loaded. This
360 : // relies on the main executable not depending on glib.
361 3 : setenv("G_SLICE", "always-malloc", 1);
362 : }
363 3 : }
364 :
365 6 : ~GSliceInit() {
366 : #if MOZ_WIDGET_GTK == 2
367 : if (sTop) {
368 : auto XRE_GlibInit = (void (*)(void)) GetSymbol(sTop->libHandle,
369 : "XRE_GlibInit");
370 : // Initialize glib enough for G_SLICE to have an effect before it is unset.
371 : // unset.
372 : XRE_GlibInit();
373 : }
374 : #endif
375 3 : if (!mHadGSlice) {
376 3 : unsetenv("G_SLICE");
377 : }
378 3 : }
379 :
380 : private:
381 : bool mHadGSlice;
382 : };
383 : #endif
384 :
385 : namespace mozilla {
386 :
387 : Bootstrap::UniquePtr
388 3 : GetBootstrap(const char* aXPCOMFile)
389 : {
390 : #ifdef MOZ_GSLICE_INIT
391 6 : GSliceInit gSliceInit;
392 : #endif
393 :
394 3 : if (!aXPCOMFile) {
395 0 : return nullptr;
396 : }
397 :
398 3 : char *lastSlash = strrchr(const_cast<char *>(aXPCOMFile), XPCOM_FILE_PATH_SEPARATOR[0]);
399 3 : if (!lastSlash) {
400 0 : return nullptr;
401 : }
402 3 : size_t base_len = size_t(lastSlash - aXPCOMFile) + 1;
403 :
404 6 : UniqueFreePtr<char> file(reinterpret_cast<char*>(malloc(base_len + sizeof(XPCOM_DLL))));
405 3 : memcpy(file.get(), aXPCOMFile, base_len);
406 3 : memcpy(file.get() + base_len, XPCOM_DLL, sizeof(XPCOM_DLL));
407 :
408 3 : if (NS_FAILED(XPCOMGlueLoad(file.get()))) {
409 0 : return nullptr;
410 : }
411 :
412 3 : GetBootstrapType func = (GetBootstrapType)GetSymbol(sTop->libHandle, "XRE_GetBootstrap");
413 3 : if (!func) {
414 0 : return nullptr;
415 : }
416 :
417 6 : Bootstrap::UniquePtr b;
418 3 : (*func)(b);
419 :
420 3 : return b;
421 : }
422 :
423 : } // namespace mozilla
|