/src/mozilla-central/xpcom/glue/standalone/nsXPCOMGlue.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 6 | #define XPCOM_DEPENDENT_LIBS_LIST "dependentlibs.list" |
24 | | |
25 | | #if defined(XP_WIN) |
26 | | #define READ_TEXTMODE L"rt" |
27 | | #else |
28 | 3 | #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 | | GetLibHandle(pathstr_t aDependentLib) |
99 | 36 | { |
100 | 36 | LibHandleType libHandle = dlopen(aDependentLib, |
101 | 36 | RTLD_GLOBAL | RTLD_LAZY |
102 | | #ifdef XP_MACOSX |
103 | | | RTLD_FIRST |
104 | | #endif |
105 | | ); |
106 | 36 | if (!libHandle) { |
107 | 0 | fprintf(stderr, "XPCOMGlueLoad error for file %s:\n%s\n", aDependentLib, |
108 | 0 | dlerror()); |
109 | 0 | } |
110 | 36 | return libHandle; |
111 | 36 | } |
112 | | |
113 | | static NSFuncPtr |
114 | | GetSymbol(LibHandleType aLibHandle, const char* aSymbol) |
115 | 3 | { |
116 | 3 | return (NSFuncPtr)dlsym(aLibHandle, aSymbol); |
117 | 3 | } |
118 | | |
119 | | #ifndef MOZ_LINKER |
120 | | static void |
121 | | CloseLibHandle(LibHandleType aLibHandle) |
122 | 0 | { |
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 | | AppendDependentLib(LibHandleType aLibHandle) |
138 | 36 | { |
139 | 36 | auto* d = new DependentLib; |
140 | 36 | if (!d) { |
141 | 0 | return; |
142 | 0 | } |
143 | 36 | |
144 | 36 | d->next = sTop; |
145 | 36 | d->libHandle = aLibHandle; |
146 | 36 | |
147 | 36 | sTop = d; |
148 | 36 | } |
149 | | |
150 | | static bool |
151 | | ReadDependentCB(pathstr_t aDependentLib) |
152 | 36 | { |
153 | 36 | #ifndef MOZ_LINKER |
154 | 36 | // We do this unconditionally because of data in bug 771745 |
155 | 36 | ReadAheadLib(aDependentLib); |
156 | 36 | #endif |
157 | 36 | LibHandleType libHandle = GetLibHandle(aDependentLib); |
158 | 36 | if (libHandle) { |
159 | 36 | AppendDependentLib(libHandle); |
160 | 36 | } |
161 | 36 | |
162 | 36 | return libHandle; |
163 | 36 | } |
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 | | TS_tfopen(const char* aPath, const char* aMode) |
184 | 3 | { |
185 | 3 | return fopen(aPath, aMode); |
186 | 3 | } |
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 | | static void release(type aFile) |
195 | 6 | { |
196 | 6 | if (aFile) { |
197 | 3 | fclose(aFile); |
198 | 3 | } |
199 | 6 | } |
200 | | }; |
201 | | typedef Scoped<ScopedCloseFileTraits> ScopedCloseFile; |
202 | | |
203 | | #ifndef MOZ_LINKER |
204 | | static void |
205 | | XPCOMGlueUnload() |
206 | 0 | { |
207 | 0 | while (sTop) { |
208 | 0 | CloseLibHandle(sTop->libHandle); |
209 | 0 |
|
210 | 0 | DependentLib* temp = sTop; |
211 | 0 | sTop = sTop->next; |
212 | 0 |
|
213 | 0 | delete temp; |
214 | 0 | } |
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 | | XPCOMGlueLoad(const char* aXPCOMFile) |
240 | 3 | { |
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 | | const char* lastSlash = strrchr(aXPCOMFile, '/'); |
267 | 3 | #endif |
268 | 3 | char* cursor; |
269 | 3 | if (lastSlash) { |
270 | 3 | size_t len = size_t(lastSlash - aXPCOMFile); |
271 | 3 | |
272 | 3 | if (len > MAXPATHLEN - sizeof(XPCOM_FILE_PATH_SEPARATOR |
273 | | #ifdef XP_MACOSX |
274 | | "Resources" |
275 | | XPCOM_FILE_PATH_SEPARATOR |
276 | | #endif |
277 | 3 | XPCOM_DEPENDENT_LIBS_LIST)) { |
278 | 0 | return NS_ERROR_FAILURE; |
279 | 0 | } |
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 | 3 | } else { |
289 | 0 | strcpy(xpcomDir, XPCOM_DEPENDENT_LIBS_LIST); |
290 | 0 | cursor = xpcomDir; |
291 | 0 | } |
292 | 3 | |
293 | 3 | if (getenv("MOZ_RUN_GTEST")) { |
294 | 3 | strcat(xpcomDir, ".gtest"); |
295 | 3 | } |
296 | 3 | |
297 | 3 | ScopedCloseFile flist; |
298 | 3 | flist = TS_tfopen(xpcomDir, READ_TEXTMODE); |
299 | 3 | if (!flist) { |
300 | 0 | return NS_ERROR_FAILURE; |
301 | 0 | } |
302 | 3 | |
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 | 3 | |
313 | 3 | char buffer[MAXPATHLEN]; |
314 | 3 | |
315 | 39 | while (fgets(buffer, sizeof(buffer), flist)) { |
316 | 36 | int l = strlen(buffer); |
317 | 36 | |
318 | 36 | // ignore empty lines and comments |
319 | 36 | if (l == 0 || *buffer == '#') { |
320 | 0 | continue; |
321 | 0 | } |
322 | 36 | |
323 | 36 | // cut the trailing newline, if present |
324 | 36 | if (buffer[l - 1] == '\n') { |
325 | 36 | buffer[l - 1] = '\0'; |
326 | 36 | } |
327 | 36 | |
328 | 36 | if (l + size_t(cursor - xpcomDir) > MAXPATHLEN) { |
329 | 0 | return NS_ERROR_FAILURE; |
330 | 0 | } |
331 | 36 | |
332 | 36 | strcpy(cursor, buffer); |
333 | 36 | if (!ReadDependentCB(xpcomDir)) { |
334 | 0 | XPCOMGlueUnload(); |
335 | 0 | return NS_ERROR_FAILURE; |
336 | 0 | } |
337 | 36 | } |
338 | 3 | #endif |
339 | 3 | return NS_OK; |
340 | 3 | } |
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 | | GSliceInit() { |
352 | | mHadGSlice = bool(getenv("G_SLICE")); |
353 | | 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 | | setenv("G_SLICE", "always-malloc", 1); |
362 | | } |
363 | | } |
364 | | |
365 | | ~GSliceInit() { |
366 | | if (!mHadGSlice) { |
367 | | unsetenv("G_SLICE"); |
368 | | } |
369 | | } |
370 | | |
371 | | private: |
372 | | bool mHadGSlice; |
373 | | }; |
374 | | #endif |
375 | | |
376 | | namespace mozilla { |
377 | | |
378 | | Bootstrap::UniquePtr |
379 | | GetBootstrap(const char* aXPCOMFile) |
380 | 3 | { |
381 | | #ifdef MOZ_GSLICE_INIT |
382 | | GSliceInit gSliceInit; |
383 | | #endif |
384 | | |
385 | 3 | if (!aXPCOMFile) { |
386 | 0 | return nullptr; |
387 | 0 | } |
388 | 3 | |
389 | 3 | char *lastSlash = strrchr(const_cast<char *>(aXPCOMFile), XPCOM_FILE_PATH_SEPARATOR[0]); |
390 | 3 | if (!lastSlash) { |
391 | 0 | return nullptr; |
392 | 0 | } |
393 | 3 | size_t base_len = size_t(lastSlash - aXPCOMFile) + 1; |
394 | 3 | |
395 | 3 | UniqueFreePtr<char> file(reinterpret_cast<char*>(malloc(base_len + sizeof(XPCOM_DLL)))); |
396 | 3 | memcpy(file.get(), aXPCOMFile, base_len); |
397 | 3 | memcpy(file.get() + base_len, XPCOM_DLL, sizeof(XPCOM_DLL)); |
398 | 3 | |
399 | 3 | if (NS_FAILED(XPCOMGlueLoad(file.get()))) { |
400 | 0 | return nullptr; |
401 | 0 | } |
402 | 3 | |
403 | 3 | GetBootstrapType func = (GetBootstrapType)GetSymbol(sTop->libHandle, "XRE_GetBootstrap"); |
404 | 3 | if (!func) { |
405 | 0 | return nullptr; |
406 | 0 | } |
407 | 3 | |
408 | 3 | Bootstrap::UniquePtr b; |
409 | 3 | (*func)(b); |
410 | 3 | |
411 | 3 | return b; |
412 | 3 | } |
413 | | |
414 | | } // namespace mozilla |