Coverage Report

Created: 2018-09-25 14:53

/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