blob: ee1035f31950e0753e0e13d3e2994f47f4b8ceb0 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2019 The Chromium Authors
Daniel Chenged0471b2019-05-10 11:43:362// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_IMMEDIATE_CRASH_H_
6#define BASE_IMMEDIATE_CRASH_H_
7
Adrian Taylorab8f3572023-12-01 20:57:188#include "base/fuzzing_buildflags.h"
Daniel Chenged0471b2019-05-10 11:43:369#include "build/build_config.h"
10
Brendon Tiszka254cb732024-09-27 15:17:0811#if !(defined(OFFICIAL_BUILD) || BUILDFLAG(IS_WIN))
Adrian Taylorab8f3572023-12-01 20:57:1812#include <stdlib.h>
Brendon Tiszka254cb732024-09-27 15:17:0813#endif
Adrian Taylorc54d1972023-12-05 22:10:0214
Brendon Tiszka254cb732024-09-27 15:17:0815#if BUILDFLAG(USE_FUZZING_ENGINE) && BUILDFLAG(IS_LINUX)
Adrian Taylorc54d1972023-12-05 22:10:0216// The fuzzing coverage display wants to record coverage even
17// for failure cases. It's Linux-only. So on Linux, dump coverage
18// before we immediately exit. We provide a weak symbol so that
19// this causes no link problems on configurations that don't involve
Brendon Tiszka254cb732024-09-27 15:17:0820// coverage. (This wouldn't work on Windows due to limitations of
21// weak symbol linkage.)
Paul Semel5ad5f1642023-12-12 11:15:5822extern "C" int __attribute__((weak)) __llvm_profile_write_file(void);
Brendon Tiszka254cb732024-09-27 15:17:0823#endif // BUILDFLAG(USE_FUZZING_ENGINE) && BUILDFLAG(IS_LINUX)
Adrian Taylorab8f3572023-12-01 20:57:1824
Daniel Chenged0471b2019-05-10 11:43:3625// Crashes in the fastest possible way with no attempt at logging.
Daniel Cheng69359e92019-06-20 23:43:0226// There are several constraints; see http://crbug.com/664209 for more context.
27//
28// - TRAP_SEQUENCE_() must be fatal. It should not be possible to ignore the
29// resulting exception or simply hit 'continue' to skip over it in a debugger.
30// - Different instances of TRAP_SEQUENCE_() must not be folded together, to
31// ensure crash reports are debuggable. Unlike __builtin_trap(), asm volatile
32// blocks will not be folded together.
33// Note: TRAP_SEQUENCE_() previously required an instruction with a unique
34// nonce since unlike clang, GCC folds together identical asm volatile
35// blocks.
36// - TRAP_SEQUENCE_() must produce a signal that is distinct from an invalid
37// memory access.
38// - TRAP_SEQUENCE_() must be treated as a set of noreturn instructions.
39// __builtin_unreachable() is used to provide that hint here. clang also uses
40// this as a heuristic to pack the instructions in the function epilogue to
41// improve code density.
André Kempe3566cc52023-03-30 14:10:1742// - base::ImmediateCrash() is used in allocation hooks. To prevent recursions,
43// TRAP_SEQUENCE_() must not allocate.
Daniel Cheng69359e92019-06-20 23:43:0244//
45// Additional properties that are nice to have:
46// - TRAP_SEQUENCE_() should be as compact as possible.
47// - The first instruction of TRAP_SEQUENCE_() should not change, to avoid
48// shifting crash reporting clusters. As a consequence of this, explicit
49// assembly is preferred over intrinsics.
50// Note: this last bullet point may no longer be true, and may be removed in
51// the future.
52
Reid Klecknerc55cd142019-07-23 00:38:1753// Note: TRAP_SEQUENCE Is currently split into two macro helpers due to the fact
54// that clang emits an actual instruction for __builtin_unreachable() on certain
55// platforms (see https://crbug.com/958675). In addition, the int3/bkpt/brk will
56// be removed in followups, so splitting it up like this now makes it easy to
57// land the followups.
Daniel Cheng69359e92019-06-20 23:43:0258
Daniel Chenged0471b2019-05-10 11:43:3659#if defined(COMPILER_GCC)
60
Xiaohan Wang38e4ebb2022-01-19 06:57:4361#if BUILDFLAG(IS_NACL)
Daniel Chenged0471b2019-05-10 11:43:3662
Daniel Cheng69359e92019-06-20 23:43:0263// Crash report accuracy is not guaranteed on NaCl.
Reid Klecknerc55cd142019-07-23 00:38:1764#define TRAP_SEQUENCE1_() __builtin_trap()
65#define TRAP_SEQUENCE2_() asm volatile("")
Daniel Cheng69359e92019-06-20 23:43:0266
67#elif defined(ARCH_CPU_X86_FAMILY)
68
Alison Galed965ba02024-04-26 21:50:5469// TODO(crbug.com/40625592): In theory, it should be possible to use just
Reid Klecknerc55cd142019-07-23 00:38:1770// int3. However, there are a number of crashes with SIGILL as the exception
71// code, so it seems likely that there's a signal handler that allows execution
72// to continue after SIGTRAP.
73#define TRAP_SEQUENCE1_() asm volatile("int3")
Daniel Cheng69359e92019-06-20 23:43:0274
Xiaohan Wang38e4ebb2022-01-19 06:57:4375#if BUILDFLAG(IS_APPLE)
Daniel Cheng69359e92019-06-20 23:43:0276// Intentionally empty: __builtin_unreachable() is always part of the sequence
77// (see IMMEDIATE_CRASH below) and already emits a ud2 on Mac.
78#define TRAP_SEQUENCE2_() asm volatile("")
79#else
80#define TRAP_SEQUENCE2_() asm volatile("ud2")
Xiaohan Wang38e4ebb2022-01-19 06:57:4381#endif // BUILDFLAG(IS_APPLE)
Daniel Cheng69359e92019-06-20 23:43:0282
83#elif defined(ARCH_CPU_ARMEL)
84
Daniel Chenged0471b2019-05-10 11:43:3685// bkpt will generate a SIGBUS when running on armv7 and a SIGTRAP when running
86// as a 32 bit userspace app on arm64. There doesn't seem to be any way to
87// cause a SIGTRAP from userspace without using a syscall (which would be a
88// problem for sandboxing).
Alison Galed965ba02024-04-26 21:50:5489// TODO(crbug.com/40625592): Remove bkpt from this sequence.
Reid Klecknerc55cd142019-07-23 00:38:1790#define TRAP_SEQUENCE1_() asm volatile("bkpt #0")
Daniel Cheng69359e92019-06-20 23:43:0291#define TRAP_SEQUENCE2_() asm volatile("udf #0")
Daniel Chenged0471b2019-05-10 11:43:3692
Daniel Cheng69359e92019-06-20 23:43:0293#elif defined(ARCH_CPU_ARM64)
94
Daniel Chenged0471b2019-05-10 11:43:3695// This will always generate a SIGTRAP on arm64.
Alison Galed965ba02024-04-26 21:50:5496// TODO(crbug.com/40625592): Remove brk from this sequence.
Reid Klecknerc55cd142019-07-23 00:38:1797#define TRAP_SEQUENCE1_() asm volatile("brk #0")
Daniel Cheng69359e92019-06-20 23:43:0298#define TRAP_SEQUENCE2_() asm volatile("hlt #0")
Daniel Chenged0471b2019-05-10 11:43:3699
100#else
Daniel Cheng69359e92019-06-20 23:43:02101
Daniel Chenged0471b2019-05-10 11:43:36102// Crash report accuracy will not be guaranteed on other architectures, but at
103// least this will crash as expected.
Reid Klecknerc55cd142019-07-23 00:38:17104#define TRAP_SEQUENCE1_() __builtin_trap()
105#define TRAP_SEQUENCE2_() asm volatile("")
Daniel Cheng69359e92019-06-20 23:43:02106
Daniel Chenged0471b2019-05-10 11:43:36107#endif // ARCH_CPU_*
108
109#elif defined(COMPILER_MSVC)
110
Daniel Chenged0471b2019-05-10 11:43:36111#if !defined(__clang__)
Daniel Cheng69359e92019-06-20 23:43:02112
113// MSVC x64 doesn't support inline asm, so use the MSVC intrinsic.
Reid Klecknerc55cd142019-07-23 00:38:17114#define TRAP_SEQUENCE1_() __debugbreak()
115#define TRAP_SEQUENCE2_()
Daniel Cheng69359e92019-06-20 23:43:02116
Daniel Chenged0471b2019-05-10 11:43:36117#elif defined(ARCH_CPU_ARM64)
Daniel Cheng69359e92019-06-20 23:43:02118
Tom Tan9fc93d82019-10-30 09:01:25119// Windows ARM64 uses "BRK #F000" as its breakpoint instruction, and
120// __debugbreak() generates that in both VC++ and clang.
121#define TRAP_SEQUENCE1_() __debugbreak()
Daniel Cheng69359e92019-06-20 23:43:02122// Intentionally empty: __builtin_unreachable() is always part of the sequence
Nico Weber8b833cd2019-09-16 11:47:40123// (see IMMEDIATE_CRASH below) and already emits a ud2 on Win64,
124// https://crbug.com/958373
Daniel Cheng69359e92019-06-20 23:43:02125#define TRAP_SEQUENCE2_() __asm volatile("")
126
Daniel Chenged0471b2019-05-10 11:43:36127#else
Daniel Cheng69359e92019-06-20 23:43:02128
Reid Klecknerc55cd142019-07-23 00:38:17129#define TRAP_SEQUENCE1_() asm volatile("int3")
Daniel Cheng69359e92019-06-20 23:43:02130#define TRAP_SEQUENCE2_() asm volatile("ud2")
Daniel Cheng69359e92019-06-20 23:43:02131
Daniel Chenged0471b2019-05-10 11:43:36132#endif // __clang__
133
134#else
Daniel Cheng69359e92019-06-20 23:43:02135
136#error No supported trap sequence!
137
Daniel Chenged0471b2019-05-10 11:43:36138#endif // COMPILER_GCC
139
Daniel Cheng69359e92019-06-20 23:43:02140#define TRAP_SEQUENCE_() \
141 do { \
Reid Klecknerc55cd142019-07-23 00:38:17142 TRAP_SEQUENCE1_(); \
Daniel Cheng69359e92019-06-20 23:43:02143 TRAP_SEQUENCE2_(); \
144 } while (false)
145
Peter Boströmb30544d2022-10-21 00:17:58146// This version of ALWAYS_INLINE inlines even in is_debug=true.
147// TODO(pbos): See if NDEBUG can be dropped from ALWAYS_INLINE as well, and if
148// so merge. Otherwise document why it cannot inline in debug in
149// base/compiler_specific.h.
150#if defined(COMPILER_GCC)
151#define IMMEDIATE_CRASH_ALWAYS_INLINE inline __attribute__((__always_inline__))
152#elif defined(COMPILER_MSVC)
153#define IMMEDIATE_CRASH_ALWAYS_INLINE __forceinline
Hiroki Nakagawacd01d122022-10-20 02:44:20154#else
Peter Boströmb30544d2022-10-21 00:17:58155#define IMMEDIATE_CRASH_ALWAYS_INLINE inline
156#endif
Hiroki Nakagawacd01d122022-10-20 02:44:20157
Peter Boströmb30544d2022-10-21 00:17:58158namespace base {
Hiroki Nakagawacd01d122022-10-20 02:44:20159
Peter Boströmb30544d2022-10-21 00:17:58160[[noreturn]] IMMEDIATE_CRASH_ALWAYS_INLINE void ImmediateCrash() {
Brendon Tiszka254cb732024-09-27 15:17:08161#if BUILDFLAG(USE_FUZZING_ENGINE) && BUILDFLAG(IS_LINUX)
162 // A fuzzer run will often handle many successful cases then
163 // find one which crashes and dies. It's important that the
164 // coverage of those successful cases is represented when we're
165 // considering fuzzing coverage. At the moment fuzzing coverage
166 // is only measured on Linux, which is why this is Linux-
167 // specific.
168 // exit() arranges to write out coverage information because
169 // an atexit handler is registered to do so, but there is no
170 // such action in the std::abort case. Instead, manually write
171 // out such coverage.
172 // We could extend this step to all coverage builds, but
173 // at present failing tests don't get coverage reported,
174 // so we're retaining that behavior.
175 // TODO(crbug.com/40948553): consider doing this for all coverage builds
Paul Semeldf26c852023-12-18 20:36:58176 if (__llvm_profile_write_file) {
177 __llvm_profile_write_file();
178 }
Brendon Tiszka254cb732024-09-27 15:17:08179#endif // BUILDFLAG(USE_FUZZING_ENGINE) && BUILDFLAG(IS_LINUX)
180
181#if defined(OFFICIAL_BUILD) || BUILDFLAG(IS_WIN)
182 // We can't use abort() on Windows because it results in the
183 // abort/retry/ignore dialog which disrupts automated tests.
184 // TODO(crbug.com/40948553): investigate if such dialogs can
185 // be suppressed
Peter Boströmb30544d2022-10-21 00:17:58186 TRAP_SEQUENCE_();
Daniel Chenged0471b2019-05-10 11:43:36187#if defined(__clang__) || defined(COMPILER_GCC)
Peter Boströmb30544d2022-10-21 00:17:58188 __builtin_unreachable();
Daniel Cheng69359e92019-06-20 23:43:02189#endif // defined(__clang__) || defined(COMPILER_GCC)
Brendon Tiszka254cb732024-09-27 15:17:08190#else // defined(OFFICIAL_BUILD) || BUILDFLAG(IS_WIN)
191 abort();
192#endif // defined(OFFICIAL_BUILD)
Peter Boströmb30544d2022-10-21 00:17:58193}
194
195} // namespace base
196
Daniel Chenged0471b2019-05-10 11:43:36197#endif // BASE_IMMEDIATE_CRASH_H_