signalhandler.cc
Go to the documentation of this file.
1 // Copyright (c) 2008, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Satoru Takabayashi
31 //
32 // Implementation of InstallFailureSignalHandler().
33 
34 #include "utilities.h"
35 #include "stacktrace.h"
36 #include "symbolize.h"
37 #include <glog/logging.h>
38 
39 #include <csignal>
40 #include <ctime>
41 #ifdef HAVE_UCONTEXT_H
42 # include <ucontext.h>
43 #endif
44 #ifdef HAVE_SYS_UCONTEXT_H
45 # include <sys/ucontext.h>
46 #endif
47 #include <algorithm>
48 
50 
51 namespace {
52 
53 // We'll install the failure signal handler for these signals. We could
54 // use strsignal() to get signal names, but we don't use it to avoid
55 // introducing yet another #ifdef complication.
56 //
57 // The list should be synced with the comment in signalhandler.h.
58 const struct {
59  int number;
60  const char *name;
61 } kFailureSignals[] = {
62  { SIGSEGV, "SIGSEGV" },
63  { SIGILL, "SIGILL" },
64  { SIGFPE, "SIGFPE" },
65  { SIGABRT, "SIGABRT" },
66 #if !defined(GLOG_OS_WINDOWS)
67  { SIGBUS, "SIGBUS" },
68 #endif
69  { SIGTERM, "SIGTERM" },
70 };
71 
72 static bool kFailureSignalHandlerInstalled = false;
73 
74 #if !defined(GLOG_OS_WINDOWS)
75 // Returns the program counter from signal context, NULL if unknown.
76 void* GetPC(void* ucontext_in_void) {
77 #if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
78  if (ucontext_in_void != NULL) {
79  ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void);
80  return (void*)context->PC_FROM_UCONTEXT;
81  }
82 #else
83  (void)ucontext_in_void;
84 #endif
85  return NULL;
86 }
87 #endif
88 
89 // The class is used for formatting error messages. We don't use printf()
90 // as it's not async signal safe.
92  public:
93  MinimalFormatter(char *buffer, size_t size)
94  : buffer_(buffer),
95  cursor_(buffer),
96  end_(buffer + size) {
97  }
98 
99  // Returns the number of bytes written in the buffer.
100  std::size_t num_bytes_written() const { return static_cast<std::size_t>(cursor_ - buffer_); }
101 
102  // Appends string from "str" and updates the internal cursor.
103  void AppendString(const char* str) {
104  ptrdiff_t i = 0;
105  while (str[i] != '\0' && cursor_ + i < end_) {
106  cursor_[i] = str[i];
107  ++i;
108  }
109  cursor_ += i;
110  }
111 
112  // Formats "number" in "radix" and updates the internal cursor.
113  // Lowercase letters are used for 'a' - 'z'.
114  void AppendUint64(uint64 number, unsigned radix) {
115  unsigned i = 0;
116  while (cursor_ + i < end_) {
117  const uint64 tmp = number % radix;
118  number /= radix;
119  cursor_[i] = static_cast<char>(tmp < 10 ? '0' + tmp : 'a' + tmp - 10);
120  ++i;
121  if (number == 0) {
122  break;
123  }
124  }
125  // Reverse the bytes written.
126  std::reverse(cursor_, cursor_ + i);
127  cursor_ += i;
128  }
129 
130  // Formats "number" as hexadecimal number, and updates the internal
131  // cursor. Padding will be added in front if needed.
133  char* start = cursor_;
134  AppendString("0x");
135  AppendUint64(number, 16);
136  // Move to right and add padding in front if needed.
137  if (cursor_ < start + width) {
138  const int64 delta = start + width - cursor_;
139  std::copy(start, cursor_, start + delta);
140  std::fill(start, start + delta, ' ');
141  cursor_ = start + width;
142  }
143  }
144 
145  private:
146  char *buffer_;
147  char *cursor_;
148  const char * const end_;
149 };
150 
151 // Writes the given data with the size to the standard error.
152 void WriteToStderr(const char* data, size_t size) {
153  if (write(STDERR_FILENO, data, size) < 0) {
154  // Ignore errors.
155  }
156 }
157 
158 // The writer function can be changed by InstallFailureWriter().
159 void (*g_failure_writer)(const char* data, size_t size) = WriteToStderr;
160 
161 // Dumps time information. We don't dump human-readable time information
162 // as localtime() is not guaranteed to be async signal safe.
163 void DumpTimeInfo() {
164  time_t time_in_sec = time(NULL);
165  char buf[256]; // Big enough for time info.
166  MinimalFormatter formatter(buf, sizeof(buf));
167  formatter.AppendString("*** Aborted at ");
168  formatter.AppendUint64(static_cast<uint64>(time_in_sec), 10);
169  formatter.AppendString(" (unix time)");
170  formatter.AppendString(" try \"date -d @");
171  formatter.AppendUint64(static_cast<uint64>(time_in_sec), 10);
172  formatter.AppendString("\" if you are using GNU date ***\n");
173  g_failure_writer(buf, formatter.num_bytes_written());
174 }
175 
176 // TODO(hamaji): Use signal instead of sigaction?
177 #ifdef HAVE_SIGACTION
178 
179 // Dumps information about the signal to STDERR.
180 void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
181  // Get the signal name.
182  const char* signal_name = NULL;
183  for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
184  if (signal_number == kFailureSignals[i].number) {
185  signal_name = kFailureSignals[i].name;
186  }
187  }
188 
189  char buf[256]; // Big enough for signal info.
190  MinimalFormatter formatter(buf, sizeof(buf));
191 
192  formatter.AppendString("*** ");
193  if (signal_name) {
194  formatter.AppendString(signal_name);
195  } else {
196  // Use the signal number if the name is unknown. The signal name
197  // should be known, but just in case.
198  formatter.AppendString("Signal ");
199  formatter.AppendUint64(static_cast<uint64>(signal_number), 10);
200  }
201  formatter.AppendString(" (@0x");
202  formatter.AppendUint64(reinterpret_cast<uintptr_t>(siginfo->si_addr), 16);
203  formatter.AppendString(")");
204  formatter.AppendString(" received by PID ");
205  formatter.AppendUint64(static_cast<uint64>(getpid()), 10);
206  formatter.AppendString(" (TID 0x");
207  // We assume pthread_t is an integral number or a pointer, rather
208  // than a complex struct. In some environments, pthread_self()
209  // returns an uint64 but in some other environments pthread_self()
210  // returns a pointer.
211  pthread_t id = pthread_self();
212  formatter.AppendUint64(
213  reinterpret_cast<uint64>(reinterpret_cast<const char*>(id)), 16);
214  formatter.AppendString(") ");
215  // Only linux has the PID of the signal sender in si_pid.
216 #ifdef GLOG_OS_LINUX
217  formatter.AppendString("from PID ");
218  formatter.AppendUint64(static_cast<uint64>(siginfo->si_pid), 10);
219  formatter.AppendString("; ");
220 #endif
221  formatter.AppendString("stack trace: ***\n");
222  g_failure_writer(buf, formatter.num_bytes_written());
223 }
224 
225 #endif // HAVE_SIGACTION
226 
227 // Dumps information about the stack frame to STDERR.
228 void DumpStackFrameInfo(const char* prefix, void* pc) {
229  // Get the symbol name.
230  const char *symbol = "(unknown)";
231  char symbolized[1024]; // Big enough for a sane symbol.
232  // Symbolizes the previous address of pc because pc may be in the
233  // next function.
234  if (Symbolize(reinterpret_cast<char *>(pc) - 1,
235  symbolized, sizeof(symbolized))) {
236  symbol = symbolized;
237  }
238 
239  char buf[1024]; // Big enough for stack frame info.
240  MinimalFormatter formatter(buf, sizeof(buf));
241 
242  formatter.AppendString(prefix);
243  formatter.AppendString("@ ");
244  const int width = 2 * sizeof(void*) + 2; // + 2 for "0x".
245  formatter.AppendHexWithPadding(reinterpret_cast<uintptr_t>(pc), width);
246  formatter.AppendString(" ");
247  formatter.AppendString(symbol);
248  formatter.AppendString("\n");
249  g_failure_writer(buf, formatter.num_bytes_written());
250 }
251 
252 // Invoke the default signal handler.
253 void InvokeDefaultSignalHandler(int signal_number) {
254 #ifdef HAVE_SIGACTION
255  struct sigaction sig_action;
256  memset(&sig_action, 0, sizeof(sig_action));
257  sigemptyset(&sig_action.sa_mask);
258  sig_action.sa_handler = SIG_DFL;
259  sigaction(signal_number, &sig_action, NULL);
260  kill(getpid(), signal_number);
261 #elif defined(GLOG_OS_WINDOWS)
262  signal(signal_number, SIG_DFL);
263  raise(signal_number);
264 #endif
265 }
266 
267 // This variable is used for protecting FailureSignalHandler() from
268 // dumping stuff while another thread is doing it. Our policy is to let
269 // the first thread dump stuff and let other threads wait.
270 // See also comments in FailureSignalHandler().
271 static pthread_t* g_entered_thread_id_pointer = NULL;
272 
273 // Dumps signal and stack frame information, and invokes the default
274 // signal handler once our job is done.
275 #if defined(GLOG_OS_WINDOWS)
276 void FailureSignalHandler(int signal_number)
277 #else
278 void FailureSignalHandler(int signal_number,
279  siginfo_t *signal_info,
280  void *ucontext)
281 #endif
282 {
283  // First check if we've already entered the function. We use an atomic
284  // compare and swap operation for platforms that support it. For other
285  // platforms, we use a naive method that could lead to a subtle race.
286 
287  // We assume pthread_self() is async signal safe, though it's not
288  // officially guaranteed.
289  pthread_t my_thread_id = pthread_self();
290  // NOTE: We could simply use pthread_t rather than pthread_t* for this,
291  // if pthread_self() is guaranteed to return non-zero value for thread
292  // ids, but there is no such guarantee. We need to distinguish if the
293  // old value (value returned from __sync_val_compare_and_swap) is
294  // different from the original value (in this case NULL).
295  pthread_t* old_thread_id_pointer =
298  static_cast<pthread_t*>(NULL),
299  &my_thread_id);
300  if (old_thread_id_pointer != NULL) {
301  // We've already entered the signal handler. What should we do?
302  if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
303  // It looks the current thread is reentering the signal handler.
304  // Something must be going wrong (maybe we are reentering by another
305  // type of signal?). Kill ourself by the default signal handler.
306  InvokeDefaultSignalHandler(signal_number);
307  }
308  // Another thread is dumping stuff. Let's wait until that thread
309  // finishes the job and kills the process.
310  while (true) {
311  sleep(1);
312  }
313  }
314  // This is the first time we enter the signal handler. We are going to
315  // do some interesting stuff from here.
316  // TODO(satorux): We might want to set timeout here using alarm(), but
317  // mixing alarm() and sleep() can be a bad idea.
318 
319  // First dump time info.
320  DumpTimeInfo();
321 
322 #if !defined(GLOG_OS_WINDOWS)
323  // Get the program counter from ucontext.
324  void *pc = GetPC(ucontext);
325  DumpStackFrameInfo("PC: ", pc);
326 #endif
327 
328 #ifdef HAVE_STACKTRACE
329  // Get the stack traces.
330  void *stack[32];
331  // +1 to exclude this function.
332  const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
333 # ifdef HAVE_SIGACTION
334  DumpSignalInfo(signal_number, signal_info);
335 # endif
336  // Dump the stack traces.
337  for (int i = 0; i < depth; ++i) {
338  DumpStackFrameInfo(" ", stack[i]);
339  }
340 #endif
341 
342  // *** TRANSITION ***
343  //
344  // BEFORE this point, all code must be async-termination-safe!
345  // (See WARNING above.)
346  //
347  // AFTER this point, we do unsafe things, like using LOG()!
348  // The process could be terminated or hung at any time. We try to
349  // do more useful things first and riskier things later.
350 
351  // Flush the logs before we do anything in case 'anything'
352  // causes problems.
354 
355  // Kill ourself by the default signal handler.
356  InvokeDefaultSignalHandler(signal_number);
357 }
358 
359 } // namespace
360 
361 namespace glog_internal_namespace_ {
362 
364 #ifdef HAVE_SIGACTION
365  // TODO(andschwa): Return kFailureSignalHandlerInstalled?
366  struct sigaction sig_action;
367  memset(&sig_action, 0, sizeof(sig_action));
368  sigemptyset(&sig_action.sa_mask);
369  sigaction(SIGABRT, NULL, &sig_action);
370  if (sig_action.sa_sigaction == &FailureSignalHandler) {
371  return true;
372  }
373 #elif defined(GLOG_OS_WINDOWS)
375 #endif // HAVE_SIGACTION
376  return false;
377 }
378 
379 } // namespace glog_internal_namespace_
380 
382 #ifdef HAVE_SIGACTION
383  // Build the sigaction struct.
384  struct sigaction sig_action;
385  memset(&sig_action, 0, sizeof(sig_action));
386  sigemptyset(&sig_action.sa_mask);
387  sig_action.sa_flags |= SA_SIGINFO;
388  sig_action.sa_sigaction = &FailureSignalHandler;
389 
390  for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
391  CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL));
392  }
394 #elif defined(GLOG_OS_WINDOWS)
395  for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
397  SIG_ERR);
398  }
400 #endif // HAVE_SIGACTION
401 }
402 
403 void InstallFailureWriter(void (*writer)(const char* data, size_t size)) {
404 #if defined(HAVE_SIGACTION) || defined(GLOG_OS_WINDOWS)
405  g_failure_writer = writer;
406 #endif // HAVE_SIGACTION
407 }
408 
409 _END_GOOGLE_NAMESPACE_
_START_GOOGLE_NAMESPACE_::GetPC
void * GetPC(void *ucontext_in_void)
Definition: signalhandler.cc:76
_START_GOOGLE_NAMESPACE_::MinimalFormatter::end_
const char *const end_
Definition: signalhandler.cc:148
_START_GOOGLE_NAMESPACE_::MinimalFormatter::MinimalFormatter
MinimalFormatter(char *buffer, size_t size)
Definition: signalhandler.cc:93
symbolize.h
NULL
NULL
Definition: test_security_zap.cpp:405
google::protobuf::int64
int64_t int64
Definition: protobuf/src/google/protobuf/stubs/port.h:151
_START_GOOGLE_NAMESPACE_::MinimalFormatter::num_bytes_written
std::size_t num_bytes_written() const
Definition: signalhandler.cc:100
_START_GOOGLE_NAMESPACE_::g_failure_writer
void(* g_failure_writer)(const char *data, size_t size)
Definition: signalhandler.cc:159
Symbolize
_START_GOOGLE_NAMESPACE_ bool Symbolize(void *, char *, size_t)
Definition: symbolize.cc:948
ARRAYSIZE
#define ARRAYSIZE(a)
Definition: utilities.h:128
FlushLogFilesUnsafe
void FlushLogFilesUnsafe(LogSeverity min_severity)
Definition: logging.cc:2063
_START_GOOGLE_NAMESPACE_::kFailureSignalHandlerInstalled
static bool kFailureSignalHandlerInstalled
Definition: signalhandler.cc:72
CHECK_NE
#define CHECK_NE(a, b)
Definition: check.h:66
glog_internal_namespace_
Definition: logging_custom_prefix_unittest.cc:1003
GetStackTrace
_START_GOOGLE_NAMESPACE_ GLOG_EXPORT int GetStackTrace(void **result, int max_depth, int skip_count)
Definition: stacktrace_generic-inl.h:41
_START_GOOGLE_NAMESPACE_::MinimalFormatter::AppendUint64
void AppendUint64(uint64 number, unsigned radix)
Definition: signalhandler.cc:114
InstallFailureWriter
void InstallFailureWriter(void(*writer)(const char *data, size_t size))
Definition: signalhandler.cc:403
glog_internal_namespace_::IsFailureSignalHandlerInstalled
bool IsFailureSignalHandlerInstalled()
Definition: signalhandler.cc:363
_START_GOOGLE_NAMESPACE_::g_entered_thread_id_pointer
static pthread_t * g_entered_thread_id_pointer
Definition: signalhandler.cc:271
prefix
static const char prefix[]
Definition: test_pair_ipc.cpp:26
start
GLuint start
Definition: glcorearb.h:2858
_START_GOOGLE_NAMESPACE_::FailureSignalHandler
void FailureSignalHandler(int signal_number, siginfo_t *signal_info, void *ucontext)
Definition: signalhandler.cc:278
update_failure_list.str
str
Definition: update_failure_list.py:41
InstallFailureSignalHandler
void InstallFailureSignalHandler()
Definition: signalhandler.cc:381
_START_GOOGLE_NAMESPACE_::MinimalFormatter::cursor_
char * cursor_
Definition: signalhandler.cc:147
google::protobuf::uint64
uint64_t uint64
Definition: protobuf/src/google/protobuf/stubs/port.h:156
size
#define size
Definition: glcorearb.h:2944
_START_GOOGLE_NAMESPACE_::MinimalFormatter
Definition: signalhandler.cc:91
buffer
Definition: buffer_processor.h:43
buf
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:4175
_START_GOOGLE_NAMESPACE_::DumpTimeInfo
void DumpTimeInfo()
Definition: signalhandler.cc:163
depth
GLint GLint GLsizei GLsizei GLsizei depth
Definition: glcorearb.h:2859
WriteToStderr
static void WriteToStderr(const char *message, size_t len)
Definition: logging.cc:803
utilities.h
_START_GOOGLE_NAMESPACE_::kFailureSignals
const struct _START_GOOGLE_NAMESPACE_::@18 kFailureSignals[]
void
typedef void(APIENTRY *GLDEBUGPROCARB)(GLenum source
i
int i
Definition: gmock-matchers_test.cc:764
_START_GOOGLE_NAMESPACE_
Definition: signalhandler.cc:51
_START_GOOGLE_NAMESPACE_::DumpStackFrameInfo
void DumpStackFrameInfo(const char *prefix, void *pc)
Definition: signalhandler.cc:228
_START_GOOGLE_NAMESPACE_::number
int number
Definition: signalhandler.cc:59
size
GLsizeiptr size
Definition: glcorearb.h:2943
_START_GOOGLE_NAMESPACE_::name
const char * name
Definition: signalhandler.cc:60
stacktrace.h
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: glcorearb.h:2879
_START_GOOGLE_NAMESPACE_::MinimalFormatter::buffer_
char * buffer_
Definition: signalhandler.cc:146
_START_GOOGLE_NAMESPACE_::MinimalFormatter::AppendHexWithPadding
void AppendHexWithPadding(uint64 number, int width)
Definition: signalhandler.cc:132
buffer_
static uint8 buffer_[kBufferSize]
Definition: coded_stream_unittest.cc:136
_START_GOOGLE_NAMESPACE_::MinimalFormatter::AppendString
void AppendString(const char *str)
Definition: signalhandler.cc:103
_START_GOOGLE_NAMESPACE_::InvokeDefaultSignalHandler
void InvokeDefaultSignalHandler(int signal_number)
Definition: signalhandler.cc:253
glog_internal_namespace_::sync_val_compare_and_swap
T sync_val_compare_and_swap(T *ptr, T oldval, T newval)
Definition: utilities.h:168
width
GLint GLsizei width
Definition: glcorearb.h:2768


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:58