abseil-cpp/absl/debugging/failure_signal_handler.cc
Go to the documentation of this file.
1 //
2 // Copyright 2018 The Abseil Authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // https://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "absl/debugging/failure_signal_handler.h"
18 
19 #include "absl/base/config.h"
20 
21 #ifdef _WIN32
22 #include <windows.h>
23 #else
24 #include <sched.h>
25 #include <unistd.h>
26 #endif
27 
28 #ifdef __APPLE__
29 #include <TargetConditionals.h>
30 #endif
31 
32 #ifdef ABSL_HAVE_MMAP
33 #include <sys/mman.h>
34 #endif
35 
36 #include <algorithm>
37 #include <atomic>
38 #include <cerrno>
39 #include <csignal>
40 #include <cstdio>
41 #include <cstring>
42 #include <ctime>
43 
44 #include "absl/base/attributes.h"
45 #include "absl/base/internal/raw_logging.h"
46 #include "absl/base/internal/sysinfo.h"
47 #include "absl/debugging/internal/examine_stack.h"
48 #include "absl/debugging/stacktrace.h"
49 
50 #ifndef _WIN32
51 #define ABSL_HAVE_SIGACTION
52 // Apple WatchOS and TVOS don't allow sigaltstack
53 #if !(defined(TARGET_OS_WATCH) && TARGET_OS_WATCH) && \
54  !(defined(TARGET_OS_TV) && TARGET_OS_TV) && !defined(__QNX__)
55 #define ABSL_HAVE_SIGALTSTACK
56 #endif
57 #endif
58 
59 namespace absl {
61 
63 
64 // Resets the signal handler for signo to the default action for that
65 // signal, then raises the signal.
66 static void RaiseToDefaultHandler(int signo) {
67  signal(signo, SIG_DFL);
68  raise(signo);
69 }
70 
72  const int signo;
73  const char* const as_string;
74 #ifdef ABSL_HAVE_SIGACTION
75  struct sigaction previous_action;
76  // StructSigaction is used to silence -Wmissing-field-initializers.
77  using StructSigaction = struct sigaction;
78  #define FSD_PREVIOUS_INIT FailureSignalData::StructSigaction()
79 #else
80  void (*previous_handler)(int);
81  #define FSD_PREVIOUS_INIT SIG_DFL
82 #endif
83 };
84 
86  {SIGSEGV, "SIGSEGV", FSD_PREVIOUS_INIT},
87  {SIGILL, "SIGILL", FSD_PREVIOUS_INIT},
88  {SIGFPE, "SIGFPE", FSD_PREVIOUS_INIT},
89  {SIGABRT, "SIGABRT", FSD_PREVIOUS_INIT},
90  {SIGTERM, "SIGTERM", FSD_PREVIOUS_INIT},
91 #ifndef _WIN32
92  {SIGBUS, "SIGBUS", FSD_PREVIOUS_INIT},
93  {SIGTRAP, "SIGTRAP", FSD_PREVIOUS_INIT},
94 #endif
95 };
96 
97 #undef FSD_PREVIOUS_INIT
98 
99 static void RaiseToPreviousHandler(int signo) {
100  // Search for the previous handler.
101  for (const auto& it : failure_signal_data) {
102  if (it.signo == signo) {
103 #ifdef ABSL_HAVE_SIGACTION
104  sigaction(signo, &it.previous_action, nullptr);
105 #else
106  signal(signo, it.previous_handler);
107 #endif
108  raise(signo);
109  return;
110  }
111  }
112 
113  // Not found, use the default handler.
114  RaiseToDefaultHandler(signo);
115 }
116 
117 namespace debugging_internal {
118 
119 const char* FailureSignalToString(int signo) {
120  for (const auto& it : failure_signal_data) {
121  if (it.signo == signo) {
122  return it.as_string;
123  }
124  }
125  return "";
126 }
127 
128 } // namespace debugging_internal
129 
130 #ifdef ABSL_HAVE_SIGALTSTACK
131 
132 static bool SetupAlternateStackOnce() {
133 #if defined(__wasm__) || defined (__asjms__)
134  const size_t page_mask = getpagesize() - 1;
135 #else
136  const size_t page_mask = sysconf(_SC_PAGESIZE) - 1;
137 #endif
138  size_t stack_size =
139  (std::max<size_t>(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
140 #if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
141  defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER)
142  // Account for sanitizer instrumentation requiring additional stack space.
143  stack_size *= 5;
144 #endif
145 
146  stack_t sigstk;
147  memset(&sigstk, 0, sizeof(sigstk));
148  sigstk.ss_size = stack_size;
149 
150 #ifdef ABSL_HAVE_MMAP
151 #ifndef MAP_STACK
152 #define MAP_STACK 0
153 #endif
154 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
155 #define MAP_ANONYMOUS MAP_ANON
156 #endif
157  sigstk.ss_sp = mmap(nullptr, sigstk.ss_size, PROT_READ | PROT_WRITE,
158  MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
159  if (sigstk.ss_sp == MAP_FAILED) {
160  ABSL_RAW_LOG(FATAL, "mmap() for alternate signal stack failed");
161  }
162 #else
163  sigstk.ss_sp = malloc(sigstk.ss_size);
164  if (sigstk.ss_sp == nullptr) {
165  ABSL_RAW_LOG(FATAL, "malloc() for alternate signal stack failed");
166  }
167 #endif
168 
169  if (sigaltstack(&sigstk, nullptr) != 0) {
170  ABSL_RAW_LOG(FATAL, "sigaltstack() failed with errno=%d", errno);
171  }
172  return true;
173 }
174 
175 #endif
176 
177 #ifdef ABSL_HAVE_SIGACTION
178 
179 // Sets up an alternate stack for signal handlers once.
180 // Returns the appropriate flag for sig_action.sa_flags
181 // if the system supports using an alternate stack.
183 #ifdef ABSL_HAVE_SIGALTSTACK
184  ABSL_ATTRIBUTE_UNUSED static const bool kOnce = SetupAlternateStackOnce();
185  return SA_ONSTACK;
186 #else
187  return 0;
188 #endif
189 }
190 
192  void (*handler)(int, siginfo_t*, void*)) {
193  struct sigaction act;
194  memset(&act, 0, sizeof(act));
195  sigemptyset(&act.sa_mask);
196  act.sa_flags |= SA_SIGINFO;
197  // SA_NODEFER is required to handle SIGABRT from
198  // ImmediateAbortSignalHandler().
199  act.sa_flags |= SA_NODEFER;
201  act.sa_flags |= MaybeSetupAlternateStack();
202  }
203  act.sa_sigaction = handler;
204  ABSL_RAW_CHECK(sigaction(data->signo, &act, &data->previous_action) == 0,
205  "sigaction() failed");
206 }
207 
208 #else
209 
210 static void InstallOneFailureHandler(FailureSignalData* data,
211  void (*handler)(int)) {
212  data->previous_handler = signal(data->signo, handler);
213  ABSL_RAW_CHECK(data->previous_handler != SIG_ERR, "signal() failed");
214 }
215 
216 #endif
217 
218 static void WriteToStderr(const char* data) {
220 }
221 
222 static void WriteSignalMessage(int signo, int cpu,
223  void (*writerfn)(const char*)) {
224  char buf[96];
225  char on_cpu[32] = {0};
226  if (cpu != -1) {
227  snprintf(on_cpu, sizeof(on_cpu), " on cpu %d", cpu);
228  }
229  const char* const signal_string =
231  if (signal_string != nullptr && signal_string[0] != '\0') {
232  snprintf(buf, sizeof(buf), "*** %s received at time=%ld%s ***\n",
233  signal_string,
234  static_cast<long>(time(nullptr)), // NOLINT(runtime/int)
235  on_cpu);
236  } else {
237  snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld%s ***\n",
238  signo, static_cast<long>(time(nullptr)), // NOLINT(runtime/int)
239  on_cpu);
240  }
241  writerfn(buf);
242 }
243 
244 // `void*` might not be big enough to store `void(*)(const char*)`.
246  void (*writerfn)(const char*);
247 };
248 
249 // Many of the absl::debugging_internal::Dump* functions in
250 // examine_stack.h take a writer function pointer that has a void* arg
251 // for historical reasons. failure_signal_handler_writer only takes a
252 // data pointer. This function converts between these types.
253 static void WriterFnWrapper(const char* data, void* arg) {
254  static_cast<WriterFnStruct*>(arg)->writerfn(data);
255 }
256 
257 // Convenient wrapper around DumpPCAndFrameSizesAndStackTrace() for signal
258 // handlers. "noinline" so that GetStackFrames() skips the top-most stack
259 // frame for this function.
261  void* ucontext, bool symbolize_stacktrace,
262  void (*writerfn)(const char*, void*), void* writerfn_arg) {
263  constexpr int kNumStackFrames = 32;
264  void* stack[kNumStackFrames];
265  int frame_sizes[kNumStackFrames];
266  int min_dropped_frames;
268  stack, frame_sizes, kNumStackFrames,
269  1, // Do not include this function in stack trace.
270  ucontext, &min_dropped_frames);
272  absl::debugging_internal::GetProgramCounter(ucontext), stack, frame_sizes,
273  depth, min_dropped_frames, symbolize_stacktrace, writerfn, writerfn_arg);
274 }
275 
276 // Called by AbslFailureSignalHandler() to write the failure info. It is
277 // called once with writerfn set to WriteToStderr() and then possibly
278 // with writerfn set to the user provided function.
279 static void WriteFailureInfo(int signo, void* ucontext, int cpu,
280  void (*writerfn)(const char*)) {
281  WriterFnStruct writerfn_struct{writerfn};
282  WriteSignalMessage(signo, cpu, writerfn);
284  &writerfn_struct);
285 }
286 
287 // absl::SleepFor() can't be used here since AbslInternalSleepFor()
288 // may be overridden to do something that isn't async-signal-safe on
289 // some platforms.
291 #ifdef _WIN32
292  Sleep(seconds * 1000);
293 #else
294  struct timespec sleep_time;
295  sleep_time.tv_sec = seconds;
296  sleep_time.tv_nsec = 0;
297  while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {}
298 #endif
299 }
300 
301 #ifdef ABSL_HAVE_ALARM
302 // AbslFailureSignalHandler() installs this as a signal handler for
303 // SIGALRM, then sets an alarm to be delivered to the program after a
304 // set amount of time. If AbslFailureSignalHandler() hangs for more than
305 // the alarm timeout, ImmediateAbortSignalHandler() will abort the
306 // program.
307 static void ImmediateAbortSignalHandler(int) {
308  RaiseToDefaultHandler(SIGABRT);
309 }
310 #endif
311 
312 // absl::base_internal::GetTID() returns pid_t on most platforms, but
313 // returns absl::base_internal::pid_t on Windows.
315 ABSL_CONST_INIT static std::atomic<GetTidType> failed_tid(0);
316 
317 #ifndef ABSL_HAVE_SIGACTION
318 static void AbslFailureSignalHandler(int signo) {
319  void* ucontext = nullptr;
320 #else
321 static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) {
322 #endif
323 
324  const GetTidType this_tid = absl::base_internal::GetTID();
325  GetTidType previous_failed_tid = 0;
326  if (!failed_tid.compare_exchange_strong(
327  previous_failed_tid, static_cast<intptr_t>(this_tid),
328  std::memory_order_acq_rel, std::memory_order_relaxed)) {
329  ABSL_RAW_LOG(
330  ERROR,
331  "Signal %d raised at PC=%p while already in AbslFailureSignalHandler()",
333  if (this_tid != previous_failed_tid) {
334  // Another thread is already in AbslFailureSignalHandler(), so wait
335  // a bit for it to finish. If the other thread doesn't kill us,
336  // we do so after sleeping.
338  RaiseToDefaultHandler(signo);
339  // The recursively raised signal may be blocked until we return.
340  return;
341  }
342  }
343 
344  // Increase the chance that the CPU we report was the same CPU on which the
345  // signal was received by doing this as early as possible, i.e. after
346  // verifying that this is not a recursive signal handler invocation.
347  int my_cpu = -1;
348 #ifdef ABSL_HAVE_SCHED_GETCPU
349  my_cpu = sched_getcpu();
350 #endif
351 
352 #ifdef ABSL_HAVE_ALARM
353  // Set an alarm to abort the program in case this code hangs or deadlocks.
355  alarm(0); // Cancel any existing alarms.
356  signal(SIGALRM, ImmediateAbortSignalHandler);
358  }
359 #endif
360 
361  // First write to stderr.
362  WriteFailureInfo(signo, ucontext, my_cpu, WriteToStderr);
363 
364  // Riskier code (because it is less likely to be async-signal-safe)
365  // goes after this point.
366  if (fsh_options.writerfn != nullptr) {
367  WriteFailureInfo(signo, ucontext, my_cpu, fsh_options.writerfn);
368  fsh_options.writerfn(nullptr);
369  }
370 
372  RaiseToPreviousHandler(signo);
373  } else {
374  RaiseToDefaultHandler(signo);
375  }
376 }
377 
380  for (auto& it : failure_signal_data) {
382  }
383 }
384 
386 } // namespace absl
ABSL_RAW_CHECK
#define ABSL_RAW_CHECK(condition, message)
Definition: abseil-cpp/absl/base/internal/raw_logging.h:59
absl::time_internal::cctz::seconds
std::chrono::duration< std::int_fast64_t > seconds
Definition: abseil-cpp/absl/time/internal/cctz/include/cctz/time_zone.h:40
regen-readme.it
it
Definition: regen-readme.py:15
absl::FailureSignalHandlerOptions::symbolize_stacktrace
bool symbolize_stacktrace
Definition: abseil-cpp/absl/debugging/failure_signal_handler.h:60
ABSL_CONST_INIT
#define ABSL_CONST_INIT
Definition: abseil-cpp/absl/base/attributes.h:716
absl::raw_logging_internal::AsyncSignalSafeWriteToStderr
void AsyncSignalSafeWriteToStderr(const char *s, size_t len)
Definition: abseil-cpp/absl/base/internal/raw_logging.cc:200
memset
return memset(p, 0, total)
absl::WriteToStderr
static void WriteToStderr(const char *data)
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:218
absl::FailureSignalHandlerOptions::writerfn
void(* writerfn)(const char *)
Definition: abseil-cpp/absl/debugging/failure_signal_handler.h:100
ABSL_ATTRIBUTE_UNUSED
#define ABSL_ATTRIBUTE_UNUSED
Definition: abseil-cpp/absl/base/attributes.h:550
absl::FailureSignalData::as_string
const char *const as_string
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:73
options
double_dict options[]
Definition: capstone_test.c:55
absl::FailureSignalHandlerOptions
Definition: abseil-cpp/absl/debugging/failure_signal_handler.h:56
buf
voidpf void * buf
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
absl::RaiseToPreviousHandler
static void RaiseToPreviousHandler(int signo)
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:99
nanosleep
int nanosleep(const struct timespec *req, struct timespec *rem)
Definition: os390-syscalls.c:385
absl::FailureSignalData::previous_action
struct sigaction previous_action
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:75
absl::FailureSignalHandlerOptions::alarm_on_failure_secs
int alarm_on_failure_secs
Definition: abseil-cpp/absl/debugging/failure_signal_handler.h:74
absl::WriteFailureInfo
static void WriteFailureInfo(int signo, void *ucontext, int cpu, void(*writerfn)(const char *))
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:279
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
ABSL_ATTRIBUTE_NOINLINE
#define ABSL_ATTRIBUTE_NOINLINE
Definition: abseil-cpp/absl/base/attributes.h:112
absl::WriteStackTrace
static ABSL_ATTRIBUTE_NOINLINE void WriteStackTrace(void *ucontext, bool symbolize_stacktrace, void(*writerfn)(const char *, void *), void *writerfn_arg)
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:260
absl::debugging_internal::GetProgramCounter
void * GetProgramCounter(void *const vuc)
Definition: third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc:154
absl::FailureSignalHandlerOptions::call_previous_handler
bool call_previous_handler
Definition: abseil-cpp/absl/debugging/failure_signal_handler.h:88
absl::failed_tid
static ABSL_CONST_INIT std::atomic< GetTidType > failed_tid(0)
absl::FailureSignalData::StructSigaction
struct sigaction StructSigaction
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:77
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
xds_interop_client.int
int
Definition: xds_interop_client.py:113
absl::InstallOneFailureHandler
static void InstallOneFailureHandler(FailureSignalData *data, void(*handler)(int, siginfo_t *, void *))
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:191
signal
static void signal(notification *n)
Definition: alts_tsi_handshaker_test.cc:107
absl::base_internal::GetTID
pid_t GetTID()
Definition: abseil-cpp/absl/base/internal/sysinfo.cc:453
absl::WriterFnWrapper
static void WriterFnWrapper(const char *data, void *arg)
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:253
absl::AbslFailureSignalHandler
static void AbslFailureSignalHandler(int signo, siginfo_t *, void *ucontext)
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:321
absl::InstallFailureSignalHandler
void InstallFailureSignalHandler(const FailureSignalHandlerOptions &options)
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:378
absl::SetupAlternateStackOnce
static bool SetupAlternateStackOnce()
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:132
arg
Definition: cmdline.cc:40
intptr_t
_W64 signed int intptr_t
Definition: stdint-msvc2008.h:118
stack
NodeStack stack
Definition: cord_rep_btree.cc:356
absl::WriterFnStruct
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:245
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
absl::RaiseToDefaultHandler
static void RaiseToDefaultHandler(int signo)
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:66
absl::GetTidType
decltype(absl::base_internal::GetTID()) GetTidType
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:314
absl::FailureSignalHandlerOptions::use_alternate_stack
bool use_alternate_stack
Definition: abseil-cpp/absl/debugging/failure_signal_handler.h:68
google::protobuf::ERROR
static const LogLevel ERROR
Definition: bloaty/third_party/protobuf/src/google/protobuf/testing/googletest.h:70
FATAL
#define FATAL(msg)
Definition: task.h:88
absl::PortableSleepForSeconds
static void PortableSleepForSeconds(int seconds)
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:290
client.handler
handler
Definition: examples/python/multiprocessing/client.py:87
absl::WriterFnStruct::writerfn
void(* writerfn)(const char *)
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:246
absl::WriteSignalMessage
static void WriteSignalMessage(int signo, int cpu, void(*writerfn)(const char *))
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:222
arg
struct arg arg
FSD_PREVIOUS_INIT
#define FSD_PREVIOUS_INIT
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:78
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::FailureSignalData
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:71
absl::debugging_internal::DumpPCAndFrameSizesAndStackTrace
void DumpPCAndFrameSizesAndStackTrace(void *const pc, void *const stack[], int frame_sizes[], int depth, int min_dropped_frames, bool symbolize_stacktrace, OutputWriter *writer, void *writer_arg)
Definition: third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc:236
absl::failure_signal_data
static ABSL_CONST_INIT FailureSignalData failure_signal_data[]
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:85
absl::fsh_options
ABSL_NAMESPACE_BEGIN static ABSL_CONST_INIT FailureSignalHandlerOptions fsh_options
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:62
mkowners.depth
depth
Definition: mkowners.py:114
ABSL_RAW_LOG
#define ABSL_RAW_LOG(severity,...)
Definition: abseil-cpp/absl/base/internal/raw_logging.h:44
absl::MaybeSetupAlternateStack
static int MaybeSetupAlternateStack()
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:182
absl::debugging_internal::FailureSignalToString
const char * FailureSignalToString(int signo)
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:119
absl::GetStackFramesWithContext
ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackFramesWithContext(void **result, int *sizes, int max_depth, int skip_count, const void *uc, int *min_dropped_frames)
Definition: abseil-cpp/absl/debugging/stacktrace.cc:94
absl::FailureSignalData::signo
const int signo
Definition: abseil-cpp/absl/debugging/failure_signal_handler.cc:72


grpc
Author(s):
autogenerated on Fri May 16 2025 02:58:21