/src/mozilla-central/memory/mozalloc/mozalloc_abort.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | | * vim: sw=4 ts=4 et : |
3 | | */ |
4 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
5 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
6 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
7 | | |
8 | | #include "mozilla/mozalloc_abort.h" |
9 | | |
10 | | #ifdef ANDROID |
11 | | # include <android/log.h> |
12 | | #endif |
13 | | #ifdef MOZ_WIDGET_ANDROID |
14 | | # include "APKOpen.h" |
15 | | # include "dlfcn.h" |
16 | | #endif |
17 | | #include <stdio.h> |
18 | | #include <string.h> |
19 | | |
20 | | #include "mozilla/Assertions.h" |
21 | | #include "mozilla/Sprintf.h" |
22 | | |
23 | | void |
24 | | mozalloc_abort(const char* const msg) |
25 | 0 | { |
26 | 0 | #ifndef ANDROID |
27 | 0 | fputs(msg, stderr); |
28 | 0 | fputs("\n", stderr); |
29 | | #else |
30 | | __android_log_print(ANDROID_LOG_ERROR, "Gecko", "mozalloc_abort: %s", msg); |
31 | | #endif |
32 | | #ifdef MOZ_WIDGET_ANDROID |
33 | | abortThroughJava(msg); |
34 | | #endif |
35 | 0 | MOZ_CRASH(); |
36 | 0 | } |
37 | | |
38 | | #ifdef MOZ_WIDGET_ANDROID |
39 | | template <size_t N> |
40 | | void fillAbortMessage(char (&msg)[N], uintptr_t retAddress) { |
41 | | /* |
42 | | * On Android, we often don't have reliable backtrace when crashing inside |
43 | | * abort(). Therefore, we try to find out who is calling abort() and add |
44 | | * that to the message. |
45 | | */ |
46 | | Dl_info info = {}; |
47 | | dladdr(reinterpret_cast<void*>(retAddress), &info); |
48 | | |
49 | | const char* const module = info.dli_fname ? info.dli_fname : ""; |
50 | | const char* const base_module = strrchr(module, '/'); |
51 | | const void* const module_offset = |
52 | | reinterpret_cast<void*>(retAddress - uintptr_t(info.dli_fbase)); |
53 | | const char* const sym = info.dli_sname ? info.dli_sname : ""; |
54 | | |
55 | | SprintfLiteral(msg, "abort() called from %s:%p (%s)", |
56 | | base_module ? base_module + 1 : module, module_offset, sym); |
57 | | } |
58 | | #endif |
59 | | |
60 | | #if defined(XP_UNIX) && !defined(MOZ_ASAN) |
61 | | // Define abort() here, so that it is used instead of the system abort(). This |
62 | | // lets us control the behavior when aborting, in order to get better results |
63 | | // on *NIX platforms. See mozalloc_abort for details. |
64 | | // |
65 | | // For AddressSanitizer, we must not redefine system abort because the ASan |
66 | | // option "abort_on_error=1" calls abort() and therefore causes the following |
67 | | // call chain with our redefined abort: |
68 | | // |
69 | | // ASan -> abort() -> moz_abort() -> MOZ_CRASH() -> Segmentation fault |
70 | | // |
71 | | // That segmentation fault will be interpreted as another bug by ASan and as a |
72 | | // result, ASan will just exit(1) instead of aborting. |
73 | | extern "C" void abort(void) |
74 | 0 | { |
75 | | #ifdef MOZ_WIDGET_ANDROID |
76 | | char msg[64] = {}; |
77 | | fillAbortMessage(msg, uintptr_t(__builtin_return_address(0))); |
78 | | #else |
79 | | const char* const msg = "Redirecting call to abort() to mozalloc_abort\n"; |
80 | 0 | #endif |
81 | 0 |
|
82 | 0 | mozalloc_abort(msg); |
83 | 0 |
|
84 | 0 | // We won't reach here because mozalloc_abort() is MOZ_NORETURN. But that |
85 | 0 | // annotation isn't used on ARM (see mozalloc_abort.h for why) so we add a |
86 | 0 | // redundant MOZ_CRASH() here to avoid a "'noreturn' function does return" |
87 | 0 | // warning. |
88 | 0 | MOZ_CRASH(); |
89 | 0 | } |
90 | | #endif |
91 | | |