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 
18 
19 #include "absl/base/config.h"
20 
21 #ifdef _WIN32
22 #include <windows.h>
23 #else
24 #include <unistd.h>
25 #endif
26 
27 #ifdef ABSL_HAVE_MMAP
28 #include <sys/mman.h>
29 #endif
30 
31 #include <algorithm>
32 #include <atomic>
33 #include <cerrno>
34 #include <csignal>
35 #include <cstdio>
36 #include <cstring>
37 #include <ctime>
38 
39 #include "absl/base/attributes.h"
44 
45 #ifndef _WIN32
46 #define ABSL_HAVE_SIGACTION
47 #endif
48 
49 namespace absl {
50 
52 
53 // Resets the signal handler for signo to the default action for that
54 // signal, then raises the signal.
55 static void RaiseToDefaultHandler(int signo) {
56  signal(signo, SIG_DFL);
57  raise(signo);
58 }
59 
61  const int signo;
62  const char* const as_string;
63 #ifdef ABSL_HAVE_SIGACTION
64  struct sigaction previous_action;
65  // StructSigaction is used to silence -Wmissing-field-initializers.
66  using StructSigaction = struct sigaction;
67  #define FSD_PREVIOUS_INIT FailureSignalData::StructSigaction()
68 #else
69  void (*previous_handler)(int);
70  #define FSD_PREVIOUS_INIT SIG_DFL
71 #endif
72 };
73 
75  {SIGSEGV, "SIGSEGV", FSD_PREVIOUS_INIT},
76  {SIGILL, "SIGILL", FSD_PREVIOUS_INIT},
77  {SIGFPE, "SIGFPE", FSD_PREVIOUS_INIT},
78  {SIGABRT, "SIGABRT", FSD_PREVIOUS_INIT},
79  {SIGTERM, "SIGTERM", FSD_PREVIOUS_INIT},
80 #ifndef _WIN32
81  {SIGBUS, "SIGBUS", FSD_PREVIOUS_INIT},
82  {SIGTRAP, "SIGTRAP", FSD_PREVIOUS_INIT},
83 #endif
84 };
85 
86 #undef FSD_PREVIOUS_INIT
87 
88 static void RaiseToPreviousHandler(int signo) {
89  // Search for the previous handler.
90  for (const auto& it : failure_signal_data) {
91  if (it.signo == signo) {
92 #ifdef ABSL_HAVE_SIGACTION
93  sigaction(signo, &it.previous_action, nullptr);
94 #else
95  signal(signo, it.previous_handler);
96 #endif
97  raise(signo);
98  return;
99  }
100  }
101 
102  // Not found, use the default handler.
103  RaiseToDefaultHandler(signo);
104 }
105 
106 namespace debugging_internal {
107 
108 const char* FailureSignalToString(int signo) {
109  for (const auto& it : failure_signal_data) {
110  if (it.signo == signo) {
111  return it.as_string;
112  }
113  }
114  return "";
115 }
116 
117 } // namespace debugging_internal
118 
119 #ifndef _WIN32
120 
121 static bool SetupAlternateStackOnce() {
122 #if defined(__wasm__) || defined (__asjms__)
123  const size_t page_mask = getpagesize() - 1;
124 #else
125  const size_t page_mask = sysconf(_SC_PAGESIZE) - 1;
126 #endif
127  size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
128 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
129  defined(THREAD_SANITIZER)
130  // Account for sanitizer instrumentation requiring additional stack space.
131  stack_size *= 5;
132 #endif
133 
134  stack_t sigstk;
135  memset(&sigstk, 0, sizeof(sigstk));
136  sigstk.ss_size = stack_size;
137 
138 #ifdef ABSL_HAVE_MMAP
139 #ifndef MAP_STACK
140 #define MAP_STACK 0
141 #endif
142 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
143 #define MAP_ANONYMOUS MAP_ANON
144 #endif
145  sigstk.ss_sp = mmap(nullptr, sigstk.ss_size, PROT_READ | PROT_WRITE,
146  MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
147  if (sigstk.ss_sp == MAP_FAILED) {
148  ABSL_RAW_LOG(FATAL, "mmap() for alternate signal stack failed");
149  }
150 #else
151  sigstk.ss_sp = malloc(sigstk.ss_size);
152  if (sigstk.ss_sp == nullptr) {
153  ABSL_RAW_LOG(FATAL, "malloc() for alternate signal stack failed");
154  }
155 #endif
156 
157  if (sigaltstack(&sigstk, nullptr) != 0) {
158  ABSL_RAW_LOG(FATAL, "sigaltstack() failed with errno=%d", errno);
159  }
160  return true;
161 }
162 
163 #endif
164 
165 #ifdef ABSL_HAVE_SIGACTION
166 
167 // Sets up an alternate stack for signal handlers once.
168 // Returns the appropriate flag for sig_action.sa_flags
169 // if the system supports using an alternate stack.
171 #ifndef _WIN32
172  ABSL_ATTRIBUTE_UNUSED static const bool kOnce = SetupAlternateStackOnce();
173  return SA_ONSTACK;
174 #else
175  return 0;
176 #endif
177 }
178 
180  void (*handler)(int, siginfo_t*, void*)) {
181  struct sigaction act;
182  memset(&act, 0, sizeof(act));
183  sigemptyset(&act.sa_mask);
184  act.sa_flags |= SA_SIGINFO;
185  // SA_NODEFER is required to handle SIGABRT from
186  // ImmediateAbortSignalHandler().
187  act.sa_flags |= SA_NODEFER;
188  if (fsh_options.use_alternate_stack) {
189  act.sa_flags |= MaybeSetupAlternateStack();
190  }
191  act.sa_sigaction = handler;
192  ABSL_RAW_CHECK(sigaction(data->signo, &act, &data->previous_action) == 0,
193  "sigaction() failed");
194 }
195 
196 #else
197 
199  void (*handler)(int)) {
200  data->previous_handler = signal(data->signo, handler);
201  ABSL_RAW_CHECK(data->previous_handler != SIG_ERR, "signal() failed");
202 }
203 
204 #endif
205 
206 static void WriteToStderr(const char* data) {
207  int old_errno = errno;
209  errno = old_errno;
210 }
211 
212 static void WriteSignalMessage(int signo, void (*writerfn)(const char*)) {
213  char buf[64];
214  const char* const signal_string =
216  if (signal_string != nullptr && signal_string[0] != '\0') {
217  snprintf(buf, sizeof(buf), "*** %s received at time=%ld ***\n",
218  signal_string,
219  static_cast<long>(time(nullptr))); // NOLINT(runtime/int)
220  } else {
221  snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld ***\n",
222  signo, static_cast<long>(time(nullptr))); // NOLINT(runtime/int)
223  }
224  writerfn(buf);
225 }
226 
227 // `void*` might not be big enough to store `void(*)(const char*)`.
229  void (*writerfn)(const char*);
230 };
231 
232 // Many of the absl::debugging_internal::Dump* functions in
233 // examine_stack.h take a writer function pointer that has a void* arg
234 // for historical reasons. failure_signal_handler_writer only takes a
235 // data pointer. This function converts between these types.
236 static void WriterFnWrapper(const char* data, void* arg) {
237  static_cast<WriterFnStruct*>(arg)->writerfn(data);
238 }
239 
240 // Convenient wrapper around DumpPCAndFrameSizesAndStackTrace() for signal
241 // handlers. "noinline" so that GetStackFrames() skips the top-most stack
242 // frame for this function.
244  void* ucontext, bool symbolize_stacktrace,
245  void (*writerfn)(const char*, void*), void* writerfn_arg) {
246  constexpr int kNumStackFrames = 32;
247  void* stack[kNumStackFrames];
248  int frame_sizes[kNumStackFrames];
249  int min_dropped_frames;
251  stack, frame_sizes, kNumStackFrames,
252  1, // Do not include this function in stack trace.
253  ucontext, &min_dropped_frames);
255  absl::debugging_internal::GetProgramCounter(ucontext), stack, frame_sizes,
256  depth, min_dropped_frames, symbolize_stacktrace, writerfn, writerfn_arg);
257 }
258 
259 // Called by AbslFailureSignalHandler() to write the failure info. It is
260 // called once with writerfn set to WriteToStderr() and then possibly
261 // with writerfn set to the user provided function.
262 static void WriteFailureInfo(int signo, void* ucontext,
263  void (*writerfn)(const char*)) {
264  WriterFnStruct writerfn_struct{writerfn};
265  WriteSignalMessage(signo, writerfn);
266  WriteStackTrace(ucontext, fsh_options.symbolize_stacktrace, WriterFnWrapper,
267  &writerfn_struct);
268 }
269 
270 // absl::SleepFor() can't be used here since AbslInternalSleepFor()
271 // may be overridden to do something that isn't async-signal-safe on
272 // some platforms.
274 #ifdef _WIN32
275  Sleep(seconds * 1000);
276 #else
277  struct timespec sleep_time;
278  sleep_time.tv_sec = seconds;
279  sleep_time.tv_nsec = 0;
280  while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {}
281 #endif
282 }
283 
284 #ifdef ABSL_HAVE_ALARM
285 // AbslFailureSignalHandler() installs this as a signal handler for
286 // SIGALRM, then sets an alarm to be delivered to the program after a
287 // set amount of time. If AbslFailureSignalHandler() hangs for more than
288 // the alarm timeout, ImmediateAbortSignalHandler() will abort the
289 // program.
290 static void ImmediateAbortSignalHandler(int) {
291  RaiseToDefaultHandler(SIGABRT);
292 }
293 #endif
294 
295 // absl::base_internal::GetTID() returns pid_t on most platforms, but
296 // returns absl::base_internal::pid_t on Windows.
298 ABSL_CONST_INIT static std::atomic<GetTidType> failed_tid(0);
299 
300 #ifndef ABSL_HAVE_SIGACTION
301 static void AbslFailureSignalHandler(int signo) {
302  void* ucontext = nullptr;
303 #else
304 static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) {
305 #endif
306 
307  const GetTidType this_tid = absl::base_internal::GetTID();
308  GetTidType previous_failed_tid = 0;
309  if (!failed_tid.compare_exchange_strong(
310  previous_failed_tid, static_cast<intptr_t>(this_tid),
311  std::memory_order_acq_rel, std::memory_order_relaxed)) {
312  ABSL_RAW_LOG(
313  ERROR,
314  "Signal %d raised at PC=%p while already in AbslFailureSignalHandler()",
316  if (this_tid != previous_failed_tid) {
317  // Another thread is already in AbslFailureSignalHandler(), so wait
318  // a bit for it to finish. If the other thread doesn't kill us,
319  // we do so after sleeping.
321  RaiseToDefaultHandler(signo);
322  // The recursively raised signal may be blocked until we return.
323  return;
324  }
325  }
326 
327 #ifdef ABSL_HAVE_ALARM
328  // Set an alarm to abort the program in case this code hangs or deadlocks.
329  if (fsh_options.alarm_on_failure_secs > 0) {
330  alarm(0); // Cancel any existing alarms.
331  signal(SIGALRM, ImmediateAbortSignalHandler);
332  alarm(fsh_options.alarm_on_failure_secs);
333  }
334 #endif
335 
336  // First write to stderr.
337  WriteFailureInfo(signo, ucontext, WriteToStderr);
338 
339  // Riskier code (because it is less likely to be async-signal-safe)
340  // goes after this point.
341  if (fsh_options.writerfn != nullptr) {
342  WriteFailureInfo(signo, ucontext, fsh_options.writerfn);
343  }
344 
345  if (fsh_options.call_previous_handler) {
346  RaiseToPreviousHandler(signo);
347  } else {
348  RaiseToDefaultHandler(signo);
349  }
350 }
351 
353  fsh_options = options;
354  for (auto& it : failure_signal_data) {
356  }
357 }
358 
359 } // namespace absl
void SafeWriteToStderr(const char *s, size_t len)
Definition: raw_logging.cc:186
#define ABSL_ATTRIBUTE_UNUSED
Definition: attributes.h:549
const char * FailureSignalToString(int signo)
static void WriteFailureInfo(int signo, void *ucontext, void(*writerfn)(const char *))
static ABSL_CONST_INIT std::atomic< GetTidType > failed_tid(0)
#define ABSL_CONST_INIT
Definition: attributes.h:605
#define ABSL_RAW_LOG(severity,...)
Definition: raw_logging.h:42
static ABSL_ATTRIBUTE_NOINLINE void WriteStackTrace(void *ucontext, bool symbolize_stacktrace, void(*writerfn)(const char *, void *), void *writerfn_arg)
static void RaiseToPreviousHandler(int signo)
static void AbslFailureSignalHandler(int signo, siginfo_t *, void *ucontext)
#define FSD_PREVIOUS_INIT
char buf[N]
std::chrono::duration< std::int_fast64_t > seconds
Definition: time_zone.h:37
Definition: algorithm.h:29
static void WriterFnWrapper(const char *data, void *arg)
static void InstallOneFailureHandler(FailureSignalData *data, void(*handler)(int, siginfo_t *, void *))
#define ABSL_RAW_CHECK(condition, message)
Definition: raw_logging.h:57
static bool SetupAlternateStackOnce()
decltype(absl::base_internal::GetTID()) GetTidType
static ABSL_CONST_INIT FailureSignalHandlerOptions fsh_options
static char data[kDataSize]
Definition: city_test.cc:31
static void RaiseToDefaultHandler(int signo)
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: stacktrace.cc:91
void * stack[40]
Definition: graphcycles.cc:286
static void PortableSleepForSeconds(int seconds)
#define ABSL_ATTRIBUTE_NOINLINE
Definition: attributes.h:136
void * arg
Definition: mutex.cc:292
void InstallFailureSignalHandler(const FailureSignalHandlerOptions &options)
void DumpPCAndFrameSizesAndStackTrace(void *pc, void *const stack[], int frame_sizes[], int depth, int min_dropped_frames, bool symbolize_stacktrace, void(*writerfn)(const char *, void *), void *writerfn_arg)
void * GetProgramCounter(void *vuc)
static void WriteSignalMessage(int signo, void(*writerfn)(const char *))
static ABSL_CONST_INIT FailureSignalData failure_signal_data[]
static int MaybeSetupAlternateStack()
static void WriteToStderr(const char *data)


abseil_cpp
Author(s):
autogenerated on Mon Feb 28 2022 21:31:18