1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/debug/stack_trace.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <signal.h>
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/param.h>
16 #include <sys/stat.h>
17 #include <sys/syscall.h>
18 #include <sys/types.h>
19 #include <unistd.h>
20
21 #include <algorithm>
22 #include <map>
23 #include <memory>
24 #include <ostream>
25 #include <string>
26 #include <tuple>
27 #include <vector>
28
29 #include "base/memory/raw_ptr.h"
30 #include "build/build_config.h"
31
32 // Controls whether `dladdr(...)` is used to print the callstack. This is
33 // only used on iOS Official build where `backtrace_symbols(...)` prints
34 // misleading symbols (as the binary is stripped).
35 #if BUILDFLAG(IS_IOS) && defined(OFFICIAL_BUILD)
36 #define HAVE_DLADDR
37 #include <dlfcn.h>
38 #endif
39
40 // Surprisingly, uClibc defines __GLIBC__ in some build configs, but
41 // execinfo.h and backtrace(3) are really only present in glibc and in macOS
42 // libc.
43 #if BUILDFLAG(IS_APPLE) || \
44 (defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(__AIX))
45 #define HAVE_BACKTRACE
46 #include <execinfo.h>
47 #endif
48
49 // Controls whether to include code to demangle C++ symbols.
50 #if !defined(USE_SYMBOLIZE) && defined(HAVE_BACKTRACE) && !defined(HAVE_DLADDR)
51 #define DEMANGLE_SYMBOLS
52 #endif
53
54 #if defined(DEMANGLE_SYMBOLS)
55 #include <cxxabi.h>
56 #endif
57
58 #if BUILDFLAG(IS_APPLE)
59 #include <AvailabilityMacros.h>
60 #endif
61
62 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
63 #include <sys/prctl.h>
64
65 #include "base/debug/proc_maps_linux.h"
66 #endif
67
68 #include "base/cfi_buildflags.h"
69 #include "base/debug/debugger.h"
70 #include "base/debug/stack_trace.h"
71 #include "base/files/scoped_file.h"
72 #include "base/logging.h"
73 #include "base/memory/free_deleter.h"
74 #include "base/memory/singleton.h"
75 #include "base/numerics/safe_conversions.h"
76 #include "base/posix/eintr_wrapper.h"
77 #include "base/strings/string_number_conversions.h"
78 #include "base/strings/string_util.h"
79 #include "build/build_config.h"
80
81 #if defined(USE_SYMBOLIZE)
82 #include "base/third_party/symbolize/symbolize.h"
83
84 #if BUILDFLAG(ENABLE_STACK_TRACE_LINE_NUMBERS)
85 #include "base/debug/dwarf_line_no.h"
86 #endif
87
88 #endif
89
90 namespace base {
91 namespace debug {
92
93 namespace {
94
95 volatile sig_atomic_t in_signal_handler = 0;
96
97 #if !BUILDFLAG(IS_NACL)
98 bool (*try_handle_signal)(int, siginfo_t*, void*) = nullptr;
99 #endif
100
101 #if defined(DEMANGLE_SYMBOLS)
102 // The prefix used for mangled symbols, per the Itanium C++ ABI:
103 // http://www.codesourcery.com/cxx-abi/abi.html#mangling
104 const char kMangledSymbolPrefix[] = "_Z";
105
106 // Characters that can be used for symbols, generated by Ruby:
107 // (('a'..'z').to_a+('A'..'Z').to_a+('0'..'9').to_a + ['_']).join
108 const char kSymbolCharacters[] =
109 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
110
111 // Demangles C++ symbols in the given text. Example:
112 //
113 // "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]"
114 // =>
115 // "out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]"
DemangleSymbols(std::string * text)116 void DemangleSymbols(std::string* text) {
117 // Note: code in this function is NOT async-signal safe (std::string uses
118 // malloc internally).
119
120 std::string::size_type search_from = 0;
121 while (search_from < text->size()) {
122 // Look for the start of a mangled symbol, from search_from.
123 std::string::size_type mangled_start =
124 text->find(kMangledSymbolPrefix, search_from);
125 if (mangled_start == std::string::npos) {
126 break; // Mangled symbol not found.
127 }
128
129 // Look for the end of the mangled symbol.
130 std::string::size_type mangled_end =
131 text->find_first_not_of(kSymbolCharacters, mangled_start);
132 if (mangled_end == std::string::npos) {
133 mangled_end = text->size();
134 }
135 std::string mangled_symbol =
136 text->substr(mangled_start, mangled_end - mangled_start);
137
138 // Try to demangle the mangled symbol candidate.
139 int status = 0;
140 std::unique_ptr<char, base::FreeDeleter> demangled_symbol(
141 abi::__cxa_demangle(mangled_symbol.c_str(), nullptr, 0, &status));
142 if (status == 0) { // Demangling is successful.
143 // Remove the mangled symbol.
144 text->erase(mangled_start, mangled_end - mangled_start);
145 // Insert the demangled symbol.
146 text->insert(mangled_start, demangled_symbol.get());
147 // Next time, we'll start right after the demangled symbol we inserted.
148 search_from = mangled_start + strlen(demangled_symbol.get());
149 } else {
150 // Failed to demangle. Retry after the "_Z" we just found.
151 search_from = mangled_start + 2;
152 }
153 }
154 }
155 #endif // defined(DEMANGLE_SYMBOLS)
156
157 class BacktraceOutputHandler {
158 public:
159 virtual void HandleOutput(const char* output) = 0;
160
161 protected:
162 virtual ~BacktraceOutputHandler() = default;
163 };
164
165 #if defined(HAVE_BACKTRACE)
OutputPointer(const void * pointer,BacktraceOutputHandler * handler)166 void OutputPointer(const void* pointer, BacktraceOutputHandler* handler) {
167 // This should be more than enough to store a 64-bit number in hex:
168 // 16 hex digits + 1 for null-terminator.
169 char buf[17] = { '\0' };
170 handler->HandleOutput("0x");
171 internal::itoa_r(reinterpret_cast<intptr_t>(pointer),
172 buf, sizeof(buf), 16, 12);
173 handler->HandleOutput(buf);
174 }
175
176 #if defined(HAVE_DLADDR) || defined(USE_SYMBOLIZE)
OutputValue(size_t value,BacktraceOutputHandler * handler)177 void OutputValue(size_t value, BacktraceOutputHandler* handler) {
178 // Max unsigned 64-bit number in decimal has 20 digits (18446744073709551615).
179 // Hence, 30 digits should be more than enough to represent it in decimal
180 // (including the null-terminator).
181 char buf[30] = { '\0' };
182 internal::itoa_r(static_cast<intptr_t>(value), buf, sizeof(buf), 10, 1);
183 handler->HandleOutput(buf);
184 }
185 #endif // defined(HAVE_DLADDR) || defined(USE_SYMBOLIZE)
186
187 #if defined(USE_SYMBOLIZE)
OutputFrameId(size_t frame_id,BacktraceOutputHandler * handler)188 void OutputFrameId(size_t frame_id, BacktraceOutputHandler* handler) {
189 handler->HandleOutput("#");
190 OutputValue(frame_id, handler);
191 }
192 #endif // defined(USE_SYMBOLIZE)
193
ProcessBacktrace(const void * const * trace,size_t size,const char * prefix_string,BacktraceOutputHandler * handler)194 void ProcessBacktrace(const void* const* trace,
195 size_t size,
196 const char* prefix_string,
197 BacktraceOutputHandler* handler) {
198 // NOTE: This code MUST be async-signal safe (it's used by in-process
199 // stack dumping signal handler). NO malloc or stdio is allowed here.
200
201 #if defined(USE_SYMBOLIZE)
202 #if BUILDFLAG(ENABLE_STACK_TRACE_LINE_NUMBERS)
203 uint64_t* cu_offsets =
204 static_cast<uint64_t*>(alloca(sizeof(uint64_t) * size));
205 GetDwarfCompileUnitOffsets(trace, cu_offsets, size);
206 #endif
207
208 for (size_t i = 0; i < size; ++i) {
209 if (prefix_string)
210 handler->HandleOutput(prefix_string);
211
212 OutputFrameId(i, handler);
213 handler->HandleOutput(" ");
214 OutputPointer(trace[i], handler);
215 handler->HandleOutput(" ");
216
217 char buf[1024] = {'\0'};
218
219 // Subtract by one as return address of function may be in the next
220 // function when a function is annotated as noreturn.
221 const void* address = static_cast<const char*>(trace[i]) - 1;
222 if (google::Symbolize(const_cast<void*>(address), buf, sizeof(buf))) {
223 handler->HandleOutput(buf);
224 #if BUILDFLAG(ENABLE_STACK_TRACE_LINE_NUMBERS)
225 // Only output the source line number if the offset was found. Otherwise,
226 // it takes far too long in debug mode when there are lots of symbols.
227 if (GetDwarfSourceLineNumber(address, cu_offsets[i], &buf[0],
228 sizeof(buf))) {
229 handler->HandleOutput(" [");
230 handler->HandleOutput(buf);
231 handler->HandleOutput("]");
232 }
233 #endif
234 } else {
235 handler->HandleOutput("<unknown>");
236 }
237
238 handler->HandleOutput("\n");
239 }
240 #else
241 bool printed = false;
242
243 // Below part is async-signal unsafe (uses malloc), so execute it only
244 // when we are not executing the signal handler.
245 if (in_signal_handler == 0 && IsValueInRangeForNumericType<int>(size)) {
246 #if defined(HAVE_DLADDR)
247 Dl_info dl_info;
248 for (size_t i = 0; i < size; ++i) {
249 if (prefix_string) {
250 handler->HandleOutput(prefix_string);
251 }
252
253 OutputValue(i, handler);
254 handler->HandleOutput(" ");
255
256 const bool dl_info_found = dladdr(trace[i], &dl_info) != 0;
257 if (dl_info_found) {
258 const char* last_sep = strrchr(dl_info.dli_fname, '/');
259 const char* basename = last_sep ? last_sep + 1 : dl_info.dli_fname;
260 handler->HandleOutput(basename);
261 } else {
262 handler->HandleOutput("???");
263 }
264 handler->HandleOutput(" ");
265 OutputPointer(trace[i], handler);
266
267 handler->HandleOutput("\n");
268 }
269 printed = true;
270 #else // defined(HAVE_DLADDR)
271 std::unique_ptr<char*, FreeDeleter> trace_symbols(backtrace_symbols(
272 const_cast<void* const*>(trace), static_cast<int>(size)));
273 if (trace_symbols.get()) {
274 for (size_t i = 0; i < size; ++i) {
275 std::string trace_symbol = trace_symbols.get()[i];
276 DemangleSymbols(&trace_symbol);
277 if (prefix_string)
278 handler->HandleOutput(prefix_string);
279 handler->HandleOutput(trace_symbol.c_str());
280 handler->HandleOutput("\n");
281 }
282
283 printed = true;
284 }
285 #endif // defined(HAVE_DLADDR)
286 }
287
288 if (!printed) {
289 for (size_t i = 0; i < size; ++i) {
290 handler->HandleOutput(" [");
291 OutputPointer(trace[i], handler);
292 handler->HandleOutput("]\n");
293 }
294 }
295 #endif // defined(USE_SYMBOLIZE)
296 }
297 #endif // defined(HAVE_BACKTRACE)
298
PrintToStderr(const char * output)299 void PrintToStderr(const char* output) {
300 // NOTE: This code MUST be async-signal safe (it's used by in-process
301 // stack dumping signal handler). NO malloc or stdio is allowed here.
302 std::ignore = HANDLE_EINTR(write(STDERR_FILENO, output, strlen(output)));
303 }
304
305 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
AlarmSignalHandler(int signal,siginfo_t * info,void * void_context)306 void AlarmSignalHandler(int signal, siginfo_t* info, void* void_context) {
307 // We have seen rare cases on AMD linux where the default signal handler
308 // either does not run or a thread (Probably an AMD driver thread) prevents
309 // the termination of the gpu process. We catch this case when the alarm fires
310 // and then call exit_group() to kill all threads of the process. This has
311 // resolved the zombie gpu process issues we have seen on our context lost
312 // test.
313 // Note that many different calls were tried to kill the process when it is in
314 // this state. Only 'exit_group' was found to cause termination and it is
315 // speculated that only this works because only this exit kills all threads in
316 // the process (not simply the current thread).
317 // See: http://crbug.com/1396451.
318 PrintToStderr(
319 "Warning: Default signal handler failed to terminate process.\n");
320 PrintToStderr("Calling exit_group() directly to prevent timeout.\n");
321 // See: https://man7.org/linux/man-pages/man2/exit_group.2.html
322 syscall(SYS_exit_group, EXIT_FAILURE);
323 }
324 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) ||
325 // BUILDFLAG(IS_CHROMEOS)
326
StackDumpSignalHandler(int signal,siginfo_t * info,void * void_context)327 void StackDumpSignalHandler(int signal, siginfo_t* info, void* void_context) {
328 // NOTE: This code MUST be async-signal safe.
329 // NO malloc or stdio is allowed here.
330
331 #if !BUILDFLAG(IS_NACL)
332 // Give a registered callback a chance to recover from this signal
333 //
334 // V8 uses guard regions to guarantee memory safety in WebAssembly. This means
335 // some signals might be expected if they originate from Wasm code while
336 // accessing the guard region. We give V8 the chance to handle and recover
337 // from these signals first.
338 if (try_handle_signal != nullptr &&
339 try_handle_signal(signal, info, void_context)) {
340 // The first chance handler took care of this. The SA_RESETHAND flag
341 // replaced this signal handler upon entry, but we want to stay
342 // installed. Thus, we reinstall ourselves before returning.
343 struct sigaction action;
344 memset(&action, 0, sizeof(action));
345 action.sa_flags = static_cast<int>(SA_RESETHAND | SA_SIGINFO);
346 action.sa_sigaction = &StackDumpSignalHandler;
347 sigemptyset(&action.sa_mask);
348
349 sigaction(signal, &action, nullptr);
350 return;
351 }
352 #endif
353
354 // Do not take the "in signal handler" code path on Mac in a DCHECK-enabled
355 // build, as this prevents seeing a useful (symbolized) stack trace on a crash
356 // or DCHECK() failure. While it may not be fully safe to run the stack symbol
357 // printing code, in practice it's better to provide meaningful stack traces -
358 // and the risk is low given we're likely crashing already.
359 #if !BUILDFLAG(IS_APPLE) || !DCHECK_IS_ON()
360 // Record the fact that we are in the signal handler now, so that the rest
361 // of StackTrace can behave in an async-signal-safe manner.
362 in_signal_handler = 1;
363 #endif
364
365 if (BeingDebugged())
366 BreakDebugger();
367
368 PrintToStderr("Received signal ");
369 char buf[1024] = { 0 };
370 internal::itoa_r(signal, buf, sizeof(buf), 10, 0);
371 PrintToStderr(buf);
372 if (signal == SIGBUS) {
373 if (info->si_code == BUS_ADRALN)
374 PrintToStderr(" BUS_ADRALN ");
375 else if (info->si_code == BUS_ADRERR)
376 PrintToStderr(" BUS_ADRERR ");
377 else if (info->si_code == BUS_OBJERR)
378 PrintToStderr(" BUS_OBJERR ");
379 else
380 PrintToStderr(" <unknown> ");
381 } else if (signal == SIGFPE) {
382 if (info->si_code == FPE_FLTDIV)
383 PrintToStderr(" FPE_FLTDIV ");
384 else if (info->si_code == FPE_FLTINV)
385 PrintToStderr(" FPE_FLTINV ");
386 else if (info->si_code == FPE_FLTOVF)
387 PrintToStderr(" FPE_FLTOVF ");
388 else if (info->si_code == FPE_FLTRES)
389 PrintToStderr(" FPE_FLTRES ");
390 else if (info->si_code == FPE_FLTSUB)
391 PrintToStderr(" FPE_FLTSUB ");
392 else if (info->si_code == FPE_FLTUND)
393 PrintToStderr(" FPE_FLTUND ");
394 else if (info->si_code == FPE_INTDIV)
395 PrintToStderr(" FPE_INTDIV ");
396 else if (info->si_code == FPE_INTOVF)
397 PrintToStderr(" FPE_INTOVF ");
398 else
399 PrintToStderr(" <unknown> ");
400 } else if (signal == SIGILL) {
401 if (info->si_code == ILL_BADSTK)
402 PrintToStderr(" ILL_BADSTK ");
403 else if (info->si_code == ILL_COPROC)
404 PrintToStderr(" ILL_COPROC ");
405 else if (info->si_code == ILL_ILLOPN)
406 PrintToStderr(" ILL_ILLOPN ");
407 else if (info->si_code == ILL_ILLADR)
408 PrintToStderr(" ILL_ILLADR ");
409 else if (info->si_code == ILL_ILLTRP)
410 PrintToStderr(" ILL_ILLTRP ");
411 else if (info->si_code == ILL_PRVOPC)
412 PrintToStderr(" ILL_PRVOPC ");
413 else if (info->si_code == ILL_PRVREG)
414 PrintToStderr(" ILL_PRVREG ");
415 else
416 PrintToStderr(" <unknown> ");
417 } else if (signal == SIGSEGV) {
418 if (info->si_code == SEGV_MAPERR)
419 PrintToStderr(" SEGV_MAPERR ");
420 else if (info->si_code == SEGV_ACCERR)
421 PrintToStderr(" SEGV_ACCERR ");
422 #if defined(ARCH_CPU_X86_64) && \
423 (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS))
424 else if (info->si_code == SI_KERNEL)
425 PrintToStderr(" SI_KERNEL");
426 #endif
427 else
428 PrintToStderr(" <unknown> ");
429 }
430 if (signal == SIGBUS || signal == SIGFPE ||
431 signal == SIGILL || signal == SIGSEGV) {
432 internal::itoa_r(reinterpret_cast<intptr_t>(info->si_addr),
433 buf, sizeof(buf), 16, 12);
434 PrintToStderr(buf);
435 }
436 PrintToStderr("\n");
437
438 #if BUILDFLAG(CFI_ENFORCEMENT_TRAP)
439 if (signal == SIGILL && info->si_code == ILL_ILLOPN) {
440 PrintToStderr(
441 "CFI: Most likely a control flow integrity violation; for more "
442 "information see:\n");
443 PrintToStderr(
444 "https://www.chromium.org/developers/testing/control-flow-integrity\n");
445 }
446 #endif // BUILDFLAG(CFI_ENFORCEMENT_TRAP)
447
448 #if defined(ARCH_CPU_X86_64) && \
449 (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS))
450 if (signal == SIGSEGV && info->si_code == SI_KERNEL) {
451 PrintToStderr(
452 " Possibly a General Protection Fault, can be due to a non-canonical "
453 "address dereference. See \"Intel 64 and IA-32 Architectures Software "
454 "Developer’s Manual\", Volume 1, Section 3.3.7.1.\n");
455 }
456 #endif
457
458 debug::StackTrace().Print();
459
460 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
461 #if ARCH_CPU_X86_FAMILY
462 ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context);
463 const struct {
464 const char* label;
465 greg_t value;
466 } registers[] = {
467 #if ARCH_CPU_32_BITS
468 { " gs: ", context->uc_mcontext.gregs[REG_GS] },
469 { " fs: ", context->uc_mcontext.gregs[REG_FS] },
470 { " es: ", context->uc_mcontext.gregs[REG_ES] },
471 { " ds: ", context->uc_mcontext.gregs[REG_DS] },
472 { " edi: ", context->uc_mcontext.gregs[REG_EDI] },
473 { " esi: ", context->uc_mcontext.gregs[REG_ESI] },
474 { " ebp: ", context->uc_mcontext.gregs[REG_EBP] },
475 { " esp: ", context->uc_mcontext.gregs[REG_ESP] },
476 { " ebx: ", context->uc_mcontext.gregs[REG_EBX] },
477 { " edx: ", context->uc_mcontext.gregs[REG_EDX] },
478 { " ecx: ", context->uc_mcontext.gregs[REG_ECX] },
479 { " eax: ", context->uc_mcontext.gregs[REG_EAX] },
480 { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
481 { " err: ", context->uc_mcontext.gregs[REG_ERR] },
482 { " ip: ", context->uc_mcontext.gregs[REG_EIP] },
483 { " cs: ", context->uc_mcontext.gregs[REG_CS] },
484 { " efl: ", context->uc_mcontext.gregs[REG_EFL] },
485 { " usp: ", context->uc_mcontext.gregs[REG_UESP] },
486 { " ss: ", context->uc_mcontext.gregs[REG_SS] },
487 #elif ARCH_CPU_64_BITS
488 { " r8: ", context->uc_mcontext.gregs[REG_R8] },
489 { " r9: ", context->uc_mcontext.gregs[REG_R9] },
490 { " r10: ", context->uc_mcontext.gregs[REG_R10] },
491 { " r11: ", context->uc_mcontext.gregs[REG_R11] },
492 { " r12: ", context->uc_mcontext.gregs[REG_R12] },
493 { " r13: ", context->uc_mcontext.gregs[REG_R13] },
494 { " r14: ", context->uc_mcontext.gregs[REG_R14] },
495 { " r15: ", context->uc_mcontext.gregs[REG_R15] },
496 { " di: ", context->uc_mcontext.gregs[REG_RDI] },
497 { " si: ", context->uc_mcontext.gregs[REG_RSI] },
498 { " bp: ", context->uc_mcontext.gregs[REG_RBP] },
499 { " bx: ", context->uc_mcontext.gregs[REG_RBX] },
500 { " dx: ", context->uc_mcontext.gregs[REG_RDX] },
501 { " ax: ", context->uc_mcontext.gregs[REG_RAX] },
502 { " cx: ", context->uc_mcontext.gregs[REG_RCX] },
503 { " sp: ", context->uc_mcontext.gregs[REG_RSP] },
504 { " ip: ", context->uc_mcontext.gregs[REG_RIP] },
505 { " efl: ", context->uc_mcontext.gregs[REG_EFL] },
506 { " cgf: ", context->uc_mcontext.gregs[REG_CSGSFS] },
507 { " erf: ", context->uc_mcontext.gregs[REG_ERR] },
508 { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
509 { " msk: ", context->uc_mcontext.gregs[REG_OLDMASK] },
510 { " cr2: ", context->uc_mcontext.gregs[REG_CR2] },
511 #endif // ARCH_CPU_32_BITS
512 };
513
514 #if ARCH_CPU_32_BITS
515 const int kRegisterPadding = 8;
516 #elif ARCH_CPU_64_BITS
517 const int kRegisterPadding = 16;
518 #endif
519
520 for (size_t i = 0; i < std::size(registers); i++) {
521 PrintToStderr(registers[i].label);
522 internal::itoa_r(registers[i].value, buf, sizeof(buf),
523 16, kRegisterPadding);
524 PrintToStderr(buf);
525
526 if ((i + 1) % 4 == 0)
527 PrintToStderr("\n");
528 }
529 PrintToStderr("\n");
530 #endif // ARCH_CPU_X86_FAMILY
531 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
532
533 PrintToStderr("[end of stack trace]\n");
534
535 if (::signal(signal, SIG_DFL) == SIG_ERR) {
536 _exit(EXIT_FAILURE);
537 }
538
539 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
540 // Set an alarm to trigger in case the default handler does not terminate
541 // the process. See 'AlarmSignalHandler' for more details.
542 struct sigaction action;
543 memset(&action, 0, sizeof(action));
544 action.sa_flags = static_cast<int>(SA_RESETHAND);
545 action.sa_sigaction = &AlarmSignalHandler;
546 sigemptyset(&action.sa_mask);
547 sigaction(SIGALRM, &action, nullptr);
548 // 'alarm' function is signal handler safe.
549 // https://man7.org/linux/man-pages/man7/signal-safety.7.html
550 // This delay is set to be long enough for the real signal handler to fire but
551 // shorter than chrome's process watchdog timer.
552 constexpr unsigned int kAlarmSignalDelaySeconds = 5;
553 alarm(kAlarmSignalDelaySeconds);
554
555 // The following is mostly from
556 // third_party/crashpad/crashpad/util/posix/signals.cc as re-raising signals
557 // is complicated.
558
559 // If we can raise a signal with siginfo on this platform, do so. This ensures
560 // that we preserve the siginfo information for asynchronous signals (i.e.
561 // signals that do not re-raise autonomously), such as signals delivered via
562 // kill() and asynchronous hardware faults such as SEGV_MTEAERR, which would
563 // otherwise be lost when re-raising the signal via raise().
564 long retval = syscall(SYS_rt_tgsigqueueinfo, getpid(), syscall(SYS_gettid),
565 info->si_signo, info);
566 if (retval == 0) {
567 return;
568 }
569
570 // Kernels without commit 66dd34ad31e5 ("signal: allow to send any siginfo to
571 // itself"), which was first released in kernel version 3.9, did not permit a
572 // process to send arbitrary signals to itself, and will reject the
573 // rt_tgsigqueueinfo syscall with EPERM. If that happens, follow the non-Linux
574 // code path. Any other errno is unexpected and will cause us to exit.
575 if (errno != EPERM) {
576 _exit(EXIT_FAILURE);
577 }
578 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) ||
579 // BUILDFLAG(IS_CHROMEOS)
580
581 // Explicitly re-raise the signal even if it might have re-raised itself on
582 // return. Because signal handlers normally execute with their signal blocked,
583 // this raise() cannot immediately deliver the signal. Delivery is deferred
584 // until the signal handler returns and the signal becomes unblocked. The
585 // re-raised signal will appear with the same context as where it was
586 // initially triggered.
587 if (raise(signal) != 0) {
588 _exit(EXIT_FAILURE);
589 }
590 }
591
592 class PrintBacktraceOutputHandler : public BacktraceOutputHandler {
593 public:
594 PrintBacktraceOutputHandler() = default;
595
596 PrintBacktraceOutputHandler(const PrintBacktraceOutputHandler&) = delete;
597 PrintBacktraceOutputHandler& operator=(const PrintBacktraceOutputHandler&) =
598 delete;
599
HandleOutput(const char * output)600 void HandleOutput(const char* output) override {
601 // NOTE: This code MUST be async-signal safe (it's used by in-process
602 // stack dumping signal handler). NO malloc or stdio is allowed here.
603 PrintToStderr(output);
604 }
605 };
606
607 class StreamBacktraceOutputHandler : public BacktraceOutputHandler {
608 public:
StreamBacktraceOutputHandler(std::ostream * os)609 explicit StreamBacktraceOutputHandler(std::ostream* os) : os_(os) {
610 }
611
612 StreamBacktraceOutputHandler(const StreamBacktraceOutputHandler&) = delete;
613 StreamBacktraceOutputHandler& operator=(const StreamBacktraceOutputHandler&) =
614 delete;
615
HandleOutput(const char * output)616 void HandleOutput(const char* output) override { (*os_) << output; }
617
618 private:
619 raw_ptr<std::ostream> os_;
620 };
621
WarmUpBacktrace()622 void WarmUpBacktrace() {
623 // Warm up stack trace infrastructure. It turns out that on the first
624 // call glibc initializes some internal data structures using pthread_once,
625 // and even backtrace() can call malloc(), leading to hangs.
626 //
627 // Example stack trace snippet (with tcmalloc):
628 //
629 // #8 0x0000000000a173b5 in tc_malloc
630 // at ./third_party/tcmalloc/chromium/src/debugallocation.cc:1161
631 // #9 0x00007ffff7de7900 in _dl_map_object_deps at dl-deps.c:517
632 // #10 0x00007ffff7ded8a9 in dl_open_worker at dl-open.c:262
633 // #11 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
634 // #12 0x00007ffff7ded31a in _dl_open (file=0x7ffff625e298 "libgcc_s.so.1")
635 // at dl-open.c:639
636 // #13 0x00007ffff6215602 in do_dlopen at dl-libc.c:89
637 // #14 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
638 // #15 0x00007ffff62156c4 in dlerror_run at dl-libc.c:48
639 // #16 __GI___libc_dlopen_mode at dl-libc.c:165
640 // #17 0x00007ffff61ef8f5 in init
641 // at ../sysdeps/x86_64/../ia64/backtrace.c:53
642 // #18 0x00007ffff6aad400 in pthread_once
643 // at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:104
644 // #19 0x00007ffff61efa14 in __GI___backtrace
645 // at ../sysdeps/x86_64/../ia64/backtrace.c:104
646 // #20 0x0000000000752a54 in base::debug::StackTrace::StackTrace
647 // at base/debug/stack_trace_posix.cc:175
648 // #21 0x00000000007a4ae5 in
649 // base::(anonymous namespace)::StackDumpSignalHandler
650 // at base/process_util_posix.cc:172
651 // #22 <signal handler called>
652 StackTrace stack_trace;
653 }
654
655 #if defined(USE_SYMBOLIZE)
656
657 // class SandboxSymbolizeHelper.
658 //
659 // The purpose of this class is to prepare and install a "file open" callback
660 // needed by the stack trace symbolization code
661 // (base/third_party/symbolize/symbolize.h) so that it can function properly
662 // in a sandboxed process. The caveat is that this class must be instantiated
663 // before the sandboxing is enabled so that it can get the chance to open all
664 // the object files that are loaded in the virtual address space of the current
665 // process.
666 class SandboxSymbolizeHelper {
667 public:
668 // Returns the singleton instance.
GetInstance()669 static SandboxSymbolizeHelper* GetInstance() {
670 return Singleton<SandboxSymbolizeHelper,
671 LeakySingletonTraits<SandboxSymbolizeHelper>>::get();
672 }
673
674 SandboxSymbolizeHelper(const SandboxSymbolizeHelper&) = delete;
675 SandboxSymbolizeHelper& operator=(const SandboxSymbolizeHelper&) = delete;
676
677 private:
678 friend struct DefaultSingletonTraits<SandboxSymbolizeHelper>;
679
SandboxSymbolizeHelper()680 SandboxSymbolizeHelper()
681 : is_initialized_(false) {
682 Init();
683 }
684
~SandboxSymbolizeHelper()685 ~SandboxSymbolizeHelper() {
686 UnregisterCallback();
687 CloseObjectFiles();
688 }
689
690 // Returns a O_RDONLY file descriptor for |file_path| if it was opened
691 // successfully during the initialization. The file is repositioned at
692 // offset 0.
693 // IMPORTANT: This function must be async-signal-safe because it can be
694 // called from a signal handler (symbolizing stack frames for a crash).
GetFileDescriptor(const char * file_path)695 int GetFileDescriptor(const char* file_path) {
696 int fd = -1;
697
698 #if !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
699 if (file_path) {
700 // The assumption here is that iterating over std::map<std::string,
701 // base::ScopedFD> does not allocate dynamic memory, hence it is
702 // async-signal-safe.
703 for (const auto& filepath_fd : modules_) {
704 if (strcmp(filepath_fd.first.c_str(), file_path) == 0) {
705 // POSIX.1-2004 requires an implementation to guarantee that dup()
706 // is async-signal-safe.
707 fd = HANDLE_EINTR(dup(filepath_fd.second.get()));
708 break;
709 }
710 }
711 // POSIX.1-2004 requires an implementation to guarantee that lseek()
712 // is async-signal-safe.
713 if (fd >= 0 && lseek(fd, 0, SEEK_SET) < 0) {
714 // Failed to seek.
715 fd = -1;
716 }
717 }
718 #endif // !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
719
720 return fd;
721 }
722
723 // Searches for the object file (from /proc/self/maps) that contains
724 // the specified pc. If found, sets |start_address| to the start address
725 // of where this object file is mapped in memory, sets the module base
726 // address into |base_address|, copies the object file name into
727 // |out_file_name|, and attempts to open the object file. If the object
728 // file is opened successfully, returns the file descriptor. Otherwise,
729 // returns -1. |out_file_name_size| is the size of the file name buffer
730 // (including the null terminator).
731 // IMPORTANT: This function must be async-signal-safe because it can be
732 // called from a signal handler (symbolizing stack frames for a crash).
OpenObjectFileContainingPc(uint64_t pc,uint64_t & start_address,uint64_t & base_address,char * file_path,size_t file_path_size)733 static int OpenObjectFileContainingPc(uint64_t pc,
734 uint64_t& start_address,
735 uint64_t& base_address,
736 char* file_path,
737 size_t file_path_size) {
738 // This method can only be called after the singleton is instantiated.
739 // This is ensured by the following facts:
740 // * This is the only static method in this class, it is private, and
741 // the class has no friends (except for the DefaultSingletonTraits).
742 // The compiler guarantees that it can only be called after the
743 // singleton is instantiated.
744 // * This method is used as a callback for the stack tracing code and
745 // the callback registration is done in the constructor, so logically
746 // it cannot be called before the singleton is created.
747 SandboxSymbolizeHelper* instance = GetInstance();
748
749 // Cannot use STL iterators here, since debug iterators use locks.
750 // NOLINTNEXTLINE(modernize-loop-convert)
751 for (size_t i = 0; i < instance->regions_.size(); ++i) {
752 const MappedMemoryRegion& region = instance->regions_[i];
753 if (region.start <= pc && pc < region.end) {
754 start_address = region.start;
755 base_address = region.base;
756 if (file_path && file_path_size > 0) {
757 strncpy(file_path, region.path.c_str(), file_path_size);
758 // Ensure null termination.
759 file_path[file_path_size - 1] = '\0';
760 }
761 return instance->GetFileDescriptor(region.path.c_str());
762 }
763 }
764 return -1;
765 }
766
767 // This class is copied from
768 // third_party/crashpad/crashpad/util/linux/scoped_pr_set_dumpable.h.
769 // It aims at ensuring the process is dumpable before opening /proc/self/mem.
770 // If the process is already dumpable, this class doesn't do anything.
771 class ScopedPrSetDumpable {
772 public:
773 // Uses `PR_SET_DUMPABLE` to make the current process dumpable.
774 //
775 // Restores the dumpable flag to its original value on destruction. If the
776 // original value couldn't be determined, the destructor attempts to
777 // restore the flag to 0 (non-dumpable).
ScopedPrSetDumpable()778 explicit ScopedPrSetDumpable() {
779 int result = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
780 was_dumpable_ = result > 0;
781
782 if (!was_dumpable_) {
783 std::ignore = prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
784 }
785 }
786
787 ScopedPrSetDumpable(const ScopedPrSetDumpable&) = delete;
788 ScopedPrSetDumpable& operator=(const ScopedPrSetDumpable&) = delete;
789
~ScopedPrSetDumpable()790 ~ScopedPrSetDumpable() {
791 if (!was_dumpable_) {
792 std::ignore = prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
793 }
794 }
795
796 private:
797 bool was_dumpable_;
798 };
799
800 // Set the base address for each memory region by reading ELF headers in
801 // process memory.
SetBaseAddressesForMemoryRegions()802 void SetBaseAddressesForMemoryRegions() {
803 base::ScopedFD mem_fd;
804 {
805 ScopedPrSetDumpable s;
806 mem_fd = base::ScopedFD(
807 HANDLE_EINTR(open("/proc/self/mem", O_RDONLY | O_CLOEXEC)));
808 if (!mem_fd.is_valid()) {
809 return;
810 }
811 }
812
813 auto safe_memcpy = [&mem_fd](void* dst, uintptr_t src, size_t size) {
814 return HANDLE_EINTR(pread(mem_fd.get(), dst, size,
815 static_cast<off_t>(src))) == ssize_t(size);
816 };
817
818 uintptr_t cur_base = 0;
819 for (auto& r : regions_) {
820 ElfW(Ehdr) ehdr;
821 static_assert(SELFMAG <= sizeof(ElfW(Ehdr)), "SELFMAG too large");
822 if ((r.permissions & MappedMemoryRegion::READ) &&
823 safe_memcpy(&ehdr, r.start, sizeof(ElfW(Ehdr))) &&
824 memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) {
825 switch (ehdr.e_type) {
826 case ET_EXEC:
827 cur_base = 0;
828 break;
829 case ET_DYN:
830 // Find the segment containing file offset 0. This will correspond
831 // to the ELF header that we just read. Normally this will have
832 // virtual address 0, but this is not guaranteed. We must subtract
833 // the virtual address from the address where the ELF header was
834 // mapped to get the base address.
835 //
836 // If we fail to find a segment for file offset 0, use the address
837 // of the ELF header as the base address.
838 cur_base = r.start;
839 for (unsigned i = 0; i != ehdr.e_phnum; ++i) {
840 ElfW(Phdr) phdr;
841 if (safe_memcpy(&phdr, r.start + ehdr.e_phoff + i * sizeof(phdr),
842 sizeof(phdr)) &&
843 phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
844 cur_base = r.start - phdr.p_vaddr;
845 break;
846 }
847 }
848 break;
849 default:
850 // ET_REL or ET_CORE. These aren't directly executable, so they
851 // don't affect the base address.
852 break;
853 }
854 }
855
856 r.base = cur_base;
857 }
858 }
859
860 // Parses /proc/self/maps in order to compile a list of all object file names
861 // for the modules that are loaded in the current process.
862 // Returns true on success.
CacheMemoryRegions()863 bool CacheMemoryRegions() {
864 // Reads /proc/self/maps.
865 std::string contents;
866 if (!ReadProcMaps(&contents)) {
867 LOG(ERROR) << "Failed to read /proc/self/maps";
868 return false;
869 }
870
871 // Parses /proc/self/maps.
872 if (!ParseProcMaps(contents, ®ions_)) {
873 LOG(ERROR) << "Failed to parse the contents of /proc/self/maps";
874 return false;
875 }
876
877 SetBaseAddressesForMemoryRegions();
878
879 is_initialized_ = true;
880 return true;
881 }
882
883 // Opens all object files and caches their file descriptors.
OpenSymbolFiles()884 void OpenSymbolFiles() {
885 // Pre-opening and caching the file descriptors of all loaded modules is
886 // not safe for production builds. Hence it is only done in non-official
887 // builds. For more details, take a look at: http://crbug.com/341966.
888 #if !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
889 // Open the object files for all read-only executable regions and cache
890 // their file descriptors.
891 std::vector<MappedMemoryRegion>::const_iterator it;
892 for (it = regions_.begin(); it != regions_.end(); ++it) {
893 const MappedMemoryRegion& region = *it;
894 // Only interesed in read-only executable regions.
895 if ((region.permissions & MappedMemoryRegion::READ) ==
896 MappedMemoryRegion::READ &&
897 (region.permissions & MappedMemoryRegion::WRITE) == 0 &&
898 (region.permissions & MappedMemoryRegion::EXECUTE) ==
899 MappedMemoryRegion::EXECUTE) {
900 if (region.path.empty()) {
901 // Skip regions with empty file names.
902 continue;
903 }
904 if (region.path[0] == '[') {
905 // Skip pseudo-paths, like [stack], [vdso], [heap], etc ...
906 continue;
907 }
908 if (base::EndsWith(region.path, " (deleted)",
909 base::CompareCase::SENSITIVE)) {
910 // Skip deleted files.
911 continue;
912 }
913 // Avoid duplicates.
914 if (modules_.find(region.path) == modules_.end()) {
915 int fd = open(region.path.c_str(), O_RDONLY | O_CLOEXEC);
916 if (fd >= 0) {
917 modules_.emplace(region.path, base::ScopedFD(fd));
918 } else {
919 LOG(WARNING) << "Failed to open file: " << region.path
920 << "\n Error: " << strerror(errno);
921 }
922 }
923 }
924 }
925 #endif // !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
926 }
927
928 // Initializes and installs the symbolization callback.
Init()929 void Init() {
930 if (CacheMemoryRegions()) {
931 OpenSymbolFiles();
932 google::InstallSymbolizeOpenObjectFileCallback(
933 &OpenObjectFileContainingPc);
934 }
935 }
936
937 // Unregister symbolization callback.
UnregisterCallback()938 void UnregisterCallback() {
939 if (is_initialized_) {
940 google::InstallSymbolizeOpenObjectFileCallback(nullptr);
941 is_initialized_ = false;
942 }
943 }
944
945 // Closes all file descriptors owned by this instance.
CloseObjectFiles()946 void CloseObjectFiles() {
947 #if !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
948 modules_.clear();
949 #endif // !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
950 }
951
952 // Set to true upon successful initialization.
953 bool is_initialized_;
954
955 #if !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
956 // Mapping from file name to file descriptor. Includes file descriptors
957 // for all successfully opened object files and the file descriptor for
958 // /proc/self/maps. This code is not safe for production builds.
959 std::map<std::string, base::ScopedFD> modules_;
960 #endif // !defined(OFFICIAL_BUILD) || !defined(NO_UNWIND_TABLES)
961
962 // Cache for the process memory regions. Produced by parsing the contents
963 // of /proc/self/maps cache.
964 std::vector<MappedMemoryRegion> regions_;
965 };
966 #endif // USE_SYMBOLIZE
967
968 } // namespace
969
EnableInProcessStackDumping()970 bool EnableInProcessStackDumping() {
971 #if defined(USE_SYMBOLIZE)
972 SandboxSymbolizeHelper::GetInstance();
973 #endif // USE_SYMBOLIZE
974
975 // When running in an application, our code typically expects SIGPIPE
976 // to be ignored. Therefore, when testing that same code, it should run
977 // with SIGPIPE ignored as well.
978 struct sigaction sigpipe_action;
979 memset(&sigpipe_action, 0, sizeof(sigpipe_action));
980 sigpipe_action.sa_handler = SIG_IGN;
981 sigemptyset(&sigpipe_action.sa_mask);
982 bool success = (sigaction(SIGPIPE, &sigpipe_action, nullptr) == 0);
983
984 // Avoid hangs during backtrace initialization, see above.
985 WarmUpBacktrace();
986
987 struct sigaction action;
988 memset(&action, 0, sizeof(action));
989 action.sa_flags = static_cast<int>(SA_RESETHAND | SA_SIGINFO);
990 action.sa_sigaction = &StackDumpSignalHandler;
991 sigemptyset(&action.sa_mask);
992
993 success &= (sigaction(SIGILL, &action, nullptr) == 0);
994 success &= (sigaction(SIGABRT, &action, nullptr) == 0);
995 success &= (sigaction(SIGFPE, &action, nullptr) == 0);
996 success &= (sigaction(SIGBUS, &action, nullptr) == 0);
997 success &= (sigaction(SIGSEGV, &action, nullptr) == 0);
998 // On Linux, SIGSYS is reserved by the kernel for seccomp-bpf sandboxing.
999 #if !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
1000 success &= (sigaction(SIGSYS, &action, nullptr) == 0);
1001 #endif // !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
1002
1003 return success;
1004 }
1005
1006 #if !BUILDFLAG(IS_NACL)
SetStackDumpFirstChanceCallback(bool (* handler)(int,siginfo_t *,void *))1007 bool SetStackDumpFirstChanceCallback(bool (*handler)(int, siginfo_t*, void*)) {
1008 DCHECK(try_handle_signal == nullptr || handler == nullptr);
1009 try_handle_signal = handler;
1010
1011 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
1012 defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER) || \
1013 defined(UNDEFINED_SANITIZER)
1014 struct sigaction installed_handler;
1015 CHECK_EQ(sigaction(SIGSEGV, NULL, &installed_handler), 0);
1016 // If the installed handler does not point to StackDumpSignalHandler, then
1017 // allow_user_segv_handler is 0.
1018 if (installed_handler.sa_sigaction != StackDumpSignalHandler) {
1019 LOG(WARNING)
1020 << "WARNING: sanitizers are preventing signal handler installation. "
1021 << "WebAssembly trap handlers are disabled.\n";
1022 return false;
1023 }
1024 #endif
1025 return true;
1026 }
1027 #endif
1028
CollectStackTrace(const void ** trace,size_t count)1029 size_t CollectStackTrace(const void** trace, size_t count) {
1030 // NOTE: This code MUST be async-signal safe (it's used by in-process
1031 // stack dumping signal handler). NO malloc or stdio is allowed here.
1032
1033 #if defined(NO_UNWIND_TABLES) && BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
1034 // If we do not have unwind tables, then try tracing using frame pointers.
1035 return base::debug::TraceStackFramePointers(trace, count, 0);
1036 #elif defined(HAVE_BACKTRACE)
1037 // Though the backtrace API man page does not list any possible negative
1038 // return values, we take no chance.
1039 return base::saturated_cast<size_t>(
1040 backtrace(const_cast<void**>(trace), base::saturated_cast<int>(count)));
1041 #else
1042 return 0;
1043 #endif
1044 }
1045
PrintWithPrefix(const char * prefix_string) const1046 void StackTrace::PrintWithPrefix(const char* prefix_string) const {
1047 // NOTE: This code MUST be async-signal safe (it's used by in-process
1048 // stack dumping signal handler). NO malloc or stdio is allowed here.
1049
1050 #if defined(HAVE_BACKTRACE)
1051 PrintBacktraceOutputHandler handler;
1052 ProcessBacktrace(trace_, count_, prefix_string, &handler);
1053 #endif
1054 }
1055
1056 #if defined(HAVE_BACKTRACE)
OutputToStreamWithPrefix(std::ostream * os,const char * prefix_string) const1057 void StackTrace::OutputToStreamWithPrefix(std::ostream* os,
1058 const char* prefix_string) const {
1059 StreamBacktraceOutputHandler handler(os);
1060 ProcessBacktrace(trace_, count_, prefix_string, &handler);
1061 }
1062 #endif
1063
1064 namespace internal {
1065
1066 // NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
itoa_r(intptr_t i,char * buf,size_t sz,int base,size_t padding)1067 char* itoa_r(intptr_t i, char* buf, size_t sz, int base, size_t padding) {
1068 // Make sure we can write at least one NUL byte.
1069 size_t n = 1;
1070 if (n > sz)
1071 return nullptr;
1072
1073 if (base < 2 || base > 16) {
1074 buf[0] = '\000';
1075 return nullptr;
1076 }
1077
1078 char* start = buf;
1079
1080 uintptr_t j = static_cast<uintptr_t>(i);
1081
1082 // Handle negative numbers (only for base 10).
1083 if (i < 0 && base == 10) {
1084 // This does "j = -i" while avoiding integer overflow.
1085 j = static_cast<uintptr_t>(-(i + 1)) + 1;
1086
1087 // Make sure we can write the '-' character.
1088 if (++n > sz) {
1089 buf[0] = '\000';
1090 return nullptr;
1091 }
1092 *start++ = '-';
1093 }
1094
1095 // Loop until we have converted the entire number. Output at least one
1096 // character (i.e. '0').
1097 char* ptr = start;
1098 do {
1099 // Make sure there is still enough space left in our output buffer.
1100 if (++n > sz) {
1101 buf[0] = '\000';
1102 return nullptr;
1103 }
1104
1105 // Output the next digit.
1106 *ptr++ = "0123456789abcdef"[j % static_cast<uintptr_t>(base)];
1107 j /= static_cast<uintptr_t>(base);
1108
1109 if (padding > 0)
1110 padding--;
1111 } while (j > 0 || padding > 0);
1112
1113 // Terminate the output with a NUL character.
1114 *ptr = '\000';
1115
1116 // Conversion to ASCII actually resulted in the digits being in reverse
1117 // order. We can't easily generate them in forward order, as we can't tell
1118 // the number of characters needed until we are done converting.
1119 // So, now, we reverse the string (except for the possible "-" sign).
1120 while (--ptr > start) {
1121 char ch = *ptr;
1122 *ptr = *start;
1123 *start++ = ch;
1124 }
1125 return buf;
1126 }
1127
1128 } // namespace internal
1129
1130 } // namespace debug
1131 } // namespace base
1132