proxygen
SignalHandler.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2013-present Facebook, Inc.
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  * http://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 // This is heavily inspired by the signal handler from google-glog
18 
20 
21 #include <signal.h>
22 #include <sys/types.h>
23 
24 #include <algorithm>
25 #include <atomic>
26 #include <cerrno>
27 #include <ctime>
28 #include <mutex>
29 #include <vector>
30 
31 #include <glog/logging.h>
32 
33 #include <folly/Conv.h>
34 #include <folly/ScopeGuard.h>
39 
40 namespace folly {
41 namespace symbolizer {
42 
43 namespace {
44 
48 class FatalSignalCallbackRegistry {
49  public:
50  FatalSignalCallbackRegistry();
51 
52  void add(SignalCallback func);
53  void markInstalled();
54  void run();
55 
56  private:
57  std::atomic<bool> installed_;
59  std::vector<SignalCallback> handlers_;
60 };
61 
62 FatalSignalCallbackRegistry::FatalSignalCallbackRegistry()
63  : installed_(false) {}
64 
66  std::lock_guard<std::mutex> lock(mutex_);
67  CHECK(!installed_) << "FatalSignalCallbackRegistry::add may not be used "
68  "after installing the signal handlers.";
69  handlers_.push_back(func);
70 }
71 
72 void FatalSignalCallbackRegistry::markInstalled() {
73  std::lock_guard<std::mutex> lock(mutex_);
74  CHECK(!installed_.exchange(true))
75  << "FatalSignalCallbackRegistry::markInstalled must be called "
76  << "at most once";
77 }
78 
80  if (!installed_) {
81  return;
82  }
83 
84  for (auto& fn : handlers_) {
85  fn();
86  }
87 }
88 
89 // Leak it so we don't have to worry about destruction order
90 FatalSignalCallbackRegistry* gFatalSignalCallbackRegistry =
91  new FatalSignalCallbackRegistry;
92 
93 struct {
94  int number;
95  const char* name;
96  struct sigaction oldAction;
97 } kFatalSignals[] = {
98  {SIGSEGV, "SIGSEGV", {}},
99  {SIGILL, "SIGILL", {}},
100  {SIGFPE, "SIGFPE", {}},
101  {SIGABRT, "SIGABRT", {}},
102  {SIGBUS, "SIGBUS", {}},
103  {SIGTERM, "SIGTERM", {}},
104  {SIGQUIT, "SIGQUIT", {}},
105  {0, nullptr, {}},
106 };
107 
108 void callPreviousSignalHandler(int signum) {
109  // Restore disposition to old disposition, then kill ourselves with the same
110  // signal. The signal will be blocked until we return from our handler,
111  // then it will invoke the default handler and abort.
112  for (auto p = kFatalSignals; p->name; ++p) {
113  if (p->number == signum) {
114  sigaction(signum, &p->oldAction, nullptr);
115  raise(signum);
116  return;
117  }
118  }
119 
120  // Not one of the signals we know about. Oh well. Reset to default.
121  struct sigaction sa;
122  memset(&sa, 0, sizeof(sa));
123  sa.sa_handler = SIG_DFL;
124  sigaction(signum, &sa, nullptr);
125  raise(signum);
126 }
127 
128 // Note: not thread-safe, but that's okay, as we only let one thread
129 // in our signal handler at a time.
130 //
131 // Leak it so we don't have to worry about destruction order
132 //
133 // Initialized by installFatalSignalHandler
134 SafeStackTracePrinter* gStackTracePrinter;
135 
136 void printDec(uint64_t val) {
137  char buf[20];
138  uint32_t n = uint64ToBufferUnsafe(val, buf);
139  gStackTracePrinter->print(StringPiece(buf, n));
140 }
141 
142 const char kHexChars[] = "0123456789abcdef";
143 void printHex(uint64_t val) {
144  // TODO(tudorb): Add this to folly/Conv.h
145  char buf[2 + 2 * sizeof(uint64_t)]; // "0x" prefix, 2 digits for each byte
146 
147  char* end = buf + sizeof(buf);
148  char* p = end;
149  do {
150  *--p = kHexChars[val & 0x0f];
151  val >>= 4;
152  } while (val != 0);
153  *--p = 'x';
154  *--p = '0';
155 
156  gStackTracePrinter->print(StringPiece(p, end));
157 }
158 
159 void print(StringPiece sp) {
160  gStackTracePrinter->print(sp);
161 }
162 
163 void flush() {
164  gStackTracePrinter->flush();
165 }
166 
167 void dumpTimeInfo() {
168  SCOPE_EXIT {
169  flush();
170  };
171  time_t now = time(nullptr);
172  print("*** Aborted at ");
173  printDec(now);
174  print(" (Unix time, try 'date -d @");
175  printDec(now);
176  print("') ***\n");
177 }
178 
179 const char* sigill_reason(int si_code) {
180  switch (si_code) {
181  case ILL_ILLOPC:
182  return "illegal opcode";
183  case ILL_ILLOPN:
184  return "illegal operand";
185  case ILL_ILLADR:
186  return "illegal addressing mode";
187  case ILL_ILLTRP:
188  return "illegal trap";
189  case ILL_PRVOPC:
190  return "privileged opcode";
191  case ILL_PRVREG:
192  return "privileged register";
193  case ILL_COPROC:
194  return "coprocessor error";
195  case ILL_BADSTK:
196  return "internal stack error";
197 
198  default:
199  return nullptr;
200  }
201 }
202 
203 const char* sigfpe_reason(int si_code) {
204  switch (si_code) {
205  case FPE_INTDIV:
206  return "integer divide by zero";
207  case FPE_INTOVF:
208  return "integer overflow";
209  case FPE_FLTDIV:
210  return "floating-point divide by zero";
211  case FPE_FLTOVF:
212  return "floating-point overflow";
213  case FPE_FLTUND:
214  return "floating-point underflow";
215  case FPE_FLTRES:
216  return "floating-point inexact result";
217  case FPE_FLTINV:
218  return "floating-point invalid operation";
219  case FPE_FLTSUB:
220  return "subscript out of range";
221 
222  default:
223  return nullptr;
224  }
225 }
226 
227 const char* sigsegv_reason(int si_code) {
228  switch (si_code) {
229  case SEGV_MAPERR:
230  return "address not mapped to object";
231  case SEGV_ACCERR:
232  return "invalid permissions for mapped object";
233 
234  default:
235  return nullptr;
236  }
237 }
238 
239 const char* sigbus_reason(int si_code) {
240  switch (si_code) {
241  case BUS_ADRALN:
242  return "invalid address alignment";
243  case BUS_ADRERR:
244  return "nonexistent physical address";
245  case BUS_OBJERR:
246  return "object-specific hardware error";
247 
248  // MCEERR_AR and MCEERR_AO: in sigaction(2) but not in headers.
249 
250  default:
251  return nullptr;
252  }
253 }
254 
255 const char* sigtrap_reason(int si_code) {
256  switch (si_code) {
257  case TRAP_BRKPT:
258  return "process breakpoint";
259  case TRAP_TRACE:
260  return "process trace trap";
261 
262  // TRAP_BRANCH and TRAP_HWBKPT: in sigaction(2) but not in headers.
263 
264  default:
265  return nullptr;
266  }
267 }
268 
269 const char* sigchld_reason(int si_code) {
270  switch (si_code) {
271  case CLD_EXITED:
272  return "child has exited";
273  case CLD_KILLED:
274  return "child was killed";
275  case CLD_DUMPED:
276  return "child terminated abnormally";
277  case CLD_TRAPPED:
278  return "traced child has trapped";
279  case CLD_STOPPED:
280  return "child has stopped";
281  case CLD_CONTINUED:
282  return "stopped child has continued";
283 
284  default:
285  return nullptr;
286  }
287 }
288 
289 const char* sigio_reason(int si_code) {
290  switch (si_code) {
291  case POLL_IN:
292  return "data input available";
293  case POLL_OUT:
294  return "output buffers available";
295  case POLL_MSG:
296  return "input message available";
297  case POLL_ERR:
298  return "I/O error";
299  case POLL_PRI:
300  return "high priority input available";
301  case POLL_HUP:
302  return "device disconnected";
303 
304  default:
305  return nullptr;
306  }
307 }
308 
309 const char* signal_reason(int signum, int si_code) {
310  switch (signum) {
311  case SIGILL:
312  return sigill_reason(si_code);
313  case SIGFPE:
314  return sigfpe_reason(si_code);
315  case SIGSEGV:
316  return sigsegv_reason(si_code);
317  case SIGBUS:
318  return sigbus_reason(si_code);
319  case SIGTRAP:
320  return sigtrap_reason(si_code);
321  case SIGCHLD:
322  return sigchld_reason(si_code);
323  case SIGIO:
324  return sigio_reason(si_code); // aka SIGPOLL
325 
326  default:
327  return nullptr;
328  }
329 }
330 
331 void dumpSignalInfo(int signum, siginfo_t* siginfo) {
332  SCOPE_EXIT {
333  flush();
334  };
335  // Get the signal name, if possible.
336  const char* name = nullptr;
337  for (auto p = kFatalSignals; p->name; ++p) {
338  if (p->number == signum) {
339  name = p->name;
340  break;
341  }
342  }
343 
344  print("*** Signal ");
345  printDec(signum);
346  if (name) {
347  print(" (");
348  print(name);
349  print(")");
350  }
351 
352  print(" (");
353  printHex(reinterpret_cast<uint64_t>(siginfo->si_addr));
354  print(") received by PID ");
355  printDec(getpid());
356  print(" (pthread TID ");
357  printHex((uint64_t)pthread_self());
358  print(") (linux TID ");
359  printDec(syscall(__NR_gettid));
360 
361  // Kernel-sourced signals don't give us useful info for pid/uid.
362  if (siginfo->si_code != SI_KERNEL) {
363  print(") (maybe from PID ");
364  printDec(siginfo->si_pid);
365  print(", UID ");
366  printDec(siginfo->si_uid);
367  }
368 
369  auto reason = signal_reason(signum, siginfo->si_code);
370 
371  if (reason != nullptr) {
372  print(") (code: ");
373  print(reason);
374  }
375 
376  print("), stack trace: ***\n");
377 }
378 
379 // On Linux, pthread_t is a pointer, so 0 is an invalid value, which we
380 // take to indicate "no thread in the signal handler".
381 //
382 // POSIX defines PTHREAD_NULL for this purpose, but that's not available.
383 constexpr pthread_t kInvalidThreadId = 0;
384 
385 std::atomic<pthread_t> gSignalThread(kInvalidThreadId);
386 std::atomic<bool> gInRecursiveSignalHandler(false);
387 
388 // Here be dragons.
389 void innerSignalHandler(int signum, siginfo_t* info, void* /* uctx */) {
390  // First, let's only let one thread in here at a time.
391  pthread_t myId = pthread_self();
392 
393  pthread_t prevSignalThread = kInvalidThreadId;
394  while (!gSignalThread.compare_exchange_strong(prevSignalThread, myId)) {
395  if (pthread_equal(prevSignalThread, myId)) {
396  // First time here. Try to dump the stack trace without symbolization.
397  // If we still fail, well, we're mightily screwed, so we do nothing the
398  // next time around.
399  if (!gInRecursiveSignalHandler.exchange(true)) {
400  print("Entered fatal signal handler recursively. We're in trouble.\n");
401  gStackTracePrinter->printStackTrace(false); // no symbolization
402  }
403  return;
404  }
405 
406  // Wait a while, try again.
407  timespec ts;
408  ts.tv_sec = 0;
409  ts.tv_nsec = 100L * 1000 * 1000; // 100ms
410  nanosleep(&ts, nullptr);
411 
412  prevSignalThread = kInvalidThreadId;
413  }
414 
415  dumpTimeInfo();
416  dumpSignalInfo(signum, info);
417  gStackTracePrinter->printStackTrace(true); // with symbolization
418 
419  // Run user callbacks
420  gFatalSignalCallbackRegistry->run();
421 }
422 
423 void signalHandler(int signum, siginfo_t* info, void* uctx) {
424  int savedErrno = errno;
425  SCOPE_EXIT {
426  flush();
427  errno = savedErrno;
428  };
429  innerSignalHandler(signum, info, uctx);
430 
431  gSignalThread = kInvalidThreadId;
432  // Kill ourselves with the previous handler.
433  callPreviousSignalHandler(signum);
434 }
435 
436 } // namespace
437 
439  gFatalSignalCallbackRegistry->add(cb);
440 }
441 
443  gFatalSignalCallbackRegistry->markInstalled();
444 }
445 
446 namespace {
447 
448 std::atomic<bool> gAlreadyInstalled;
449 
450 // Small sigaltstack size threshold.
451 // 8931 is known to cause the signal handler to stack overflow during
452 // symbolization even for a simple one-liner "kill(getpid(), SIGTERM)".
453 const size_t kSmallSigAltStackSize = 8931;
454 
455 bool isSmallSigAltStackEnabled() {
456  stack_t ss;
457  if (sigaltstack(nullptr, &ss) != 0) {
458  return false;
459  }
460  if ((ss.ss_flags & SS_DISABLE) != 0) {
461  return false;
462  }
463  return ss.ss_size <= kSmallSigAltStackSize;
464 }
465 
466 } // namespace
467 
469  if (gAlreadyInstalled.exchange(true)) {
470  // Already done.
471  return;
472  }
473 
474  // If a small sigaltstack is enabled (ex. Rust stdlib might use sigaltstack
475  // to set a small stack), the default SafeStackTracePrinter would likely
476  // stack overflow. Replace it with the unsafe self-allocate printer.
477  bool useUnsafePrinter = isSmallSigAltStackEnabled();
478  if (useUnsafePrinter) {
479  gStackTracePrinter = new UnsafeSelfAllocateStackTracePrinter();
480  } else {
481  gStackTracePrinter = new SafeStackTracePrinter();
482  }
483 
484  struct sigaction sa;
485  memset(&sa, 0, sizeof(sa));
486  if (useUnsafePrinter) {
487  // The signal handler is not async-signal-safe. Block all signals to
488  // make it safer. But it's still unsafe.
489  sigfillset(&sa.sa_mask);
490  } else {
491  sigemptyset(&sa.sa_mask);
492  }
493  // By default signal handlers are run on the signaled thread's stack.
494  // In case of stack overflow running the SIGSEGV signal handler on
495  // the same stack leads to another SIGSEGV and crashes the program.
496  // Use SA_ONSTACK, so alternate stack is used (only if configured via
497  // sigaltstack).
498  // Golang also requires SA_ONSTACK. See:
499  // https://golang.org/pkg/os/signal/#hdr-Go_programs_that_use_cgo_or_SWIG
500  sa.sa_flags |= SA_SIGINFO | SA_ONSTACK;
501  sa.sa_sigaction = &signalHandler;
502 
503  for (auto p = kFatalSignals; p->name; ++p) {
504  CHECK_ERR(sigaction(p->number, &sa, &p->oldAction));
505  }
506 }
507 } // namespace symbolizer
508 } // namespace folly
def info()
Definition: deadlock.py:447
void addFatalSignalCallback(SignalCallback cb)
uint32_t uint64ToBufferUnsafe(uint64_t v, char *const buffer)
Definition: Conv.h:383
auto add
Definition: BaseTest.cpp:70
void(* SignalCallback)()
Definition: SignalHandler.h:43
void installFatalSignalCallbacks()
std::chrono::steady_clock::time_point now()
int number
double val
Definition: String.cpp:273
std::vector< SignalCallback > handlers_
#define SCOPE_EXIT
Definition: ScopeGuard.h:274
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
std::mutex mutex_
std::atomic< bool > installed_
static void run(EventBaseManager *ebm, EventBase *eb, folly::Baton<> *stop, const StringPiece &name)
auto lock(SynchronizedLocker...lockersIn) -> std::tuple< typename SynchronizedLocker::LockedPtr... >
Definition: Synchronized.h:871
const char * name
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
std::mutex mutex
struct sigaction oldAction
void installFatalSignalHandler()
Range< const char * > StringPiece
std::chrono::nanoseconds time()