blob: 87ed94f594ebb609112214164335393454edd03d [file] [log] [blame]
Austin Schuh906616c2019-01-21 20:25:11 -08001// 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 <signal.h>
40#include <time.h>
41#ifdef HAVE_UCONTEXT_H
42# include <ucontext.h>
43#endif
44#ifdef HAVE_SYS_UCONTEXT_H
45# include <sys/ucontext.h>
46#endif
Ravago Jones37f3fbd2020-10-03 17:45:26 -070047#include <dirent.h>
Austin Schuh906616c2019-01-21 20:25:11 -080048#include <algorithm>
49
50_START_GOOGLE_NAMESPACE_
51
52namespace {
53
54// We'll install the failure signal handler for these signals. We could
55// use strsignal() to get signal names, but we don't use it to avoid
56// introducing yet another #ifdef complication.
57//
58// The list should be synced with the comment in signalhandler.h.
59const struct {
60 int number;
61 const char *name;
62} kFailureSignals[] = {
63 { SIGSEGV, "SIGSEGV" },
64 { SIGILL, "SIGILL" },
65 { SIGFPE, "SIGFPE" },
66 { SIGABRT, "SIGABRT" },
67#if !defined(OS_WINDOWS)
68 { SIGBUS, "SIGBUS" },
69#endif
70 { SIGTERM, "SIGTERM" },
71};
72
73static bool kFailureSignalHandlerInstalled = false;
74
75// Returns the program counter from signal context, NULL if unknown.
76void* 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 }
Austin Schuh10358f22019-01-21 20:25:11 -080082#else
83 (void)ucontext_in_void;
Austin Schuh906616c2019-01-21 20:25:11 -080084#endif
85 return NULL;
86}
87
88// The class is used for formatting error messages. We don't use printf()
89// as it's not async signal safe.
90class MinimalFormatter {
91 public:
92 MinimalFormatter(char *buffer, int size)
93 : buffer_(buffer),
94 cursor_(buffer),
95 end_(buffer + size) {
96 }
97
98 // Returns the number of bytes written in the buffer.
99 int num_bytes_written() const { return (int) (cursor_ - buffer_); }
100
101 // Appends string from "str" and updates the internal cursor.
102 void AppendString(const char* str) {
103 int i = 0;
104 while (str[i] != '\0' && cursor_ + i < end_) {
105 cursor_[i] = str[i];
106 ++i;
107 }
108 cursor_ += i;
109 }
110
111 // Formats "number" in "radix" and updates the internal cursor.
112 // Lowercase letters are used for 'a' - 'z'.
113 void AppendUint64(uint64 number, int radix) {
114 int i = 0;
115 while (cursor_ + i < end_) {
116 const int tmp = number % radix;
117 number /= radix;
118 cursor_[i] = (tmp < 10 ? '0' + tmp : 'a' + tmp - 10);
119 ++i;
120 if (number == 0) {
121 break;
122 }
123 }
124 // Reverse the bytes written.
125 std::reverse(cursor_, cursor_ + i);
126 cursor_ += i;
127 }
128
129 // Formats "number" as hexadecimal number, and updates the internal
130 // cursor. Padding will be added in front if needed.
131 void AppendHexWithPadding(uint64 number, int width) {
132 char* start = cursor_;
133 AppendString("0x");
134 AppendUint64(number, 16);
135 // Move to right and add padding in front if needed.
136 if (cursor_ < start + width) {
137 const int64 delta = start + width - cursor_;
138 std::copy(start, cursor_, start + delta);
139 std::fill(start, start + delta, ' ');
140 cursor_ = start + width;
141 }
142 }
143
144 private:
145 char *buffer_;
146 char *cursor_;
147 const char * const end_;
148};
149
150// Writes the given data with the size to the standard error.
151void WriteToStderr(const char* data, int size) {
152 if (write(STDERR_FILENO, data, size) < 0) {
153 // Ignore errors.
154 }
155}
156
157// The writer function can be changed by InstallFailureWriter().
158void (*g_failure_writer)(const char* data, int size) = WriteToStderr;
159
160// Dumps time information. We don't dump human-readable time information
161// as localtime() is not guaranteed to be async signal safe.
162void DumpTimeInfo() {
163 time_t time_in_sec = time(NULL);
164 char buf[256]; // Big enough for time info.
165 MinimalFormatter formatter(buf, sizeof(buf));
166 formatter.AppendString("*** Aborted at ");
167 formatter.AppendUint64(time_in_sec, 10);
168 formatter.AppendString(" (unix time)");
169 formatter.AppendString(" try \"date -d @");
170 formatter.AppendUint64(time_in_sec, 10);
171 formatter.AppendString("\" if you are using GNU date ***\n");
172 g_failure_writer(buf, formatter.num_bytes_written());
173}
174
175// TOOD(hamaji): Use signal instead of sigaction?
176#ifdef HAVE_SIGACTION
177
178// Dumps information about the signal to STDERR.
179void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
180 // Get the signal name.
181 const char* signal_name = NULL;
182 for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
183 if (signal_number == kFailureSignals[i].number) {
184 signal_name = kFailureSignals[i].name;
185 }
186 }
187
188 char buf[256]; // Big enough for signal info.
189 MinimalFormatter formatter(buf, sizeof(buf));
190
191 formatter.AppendString("*** ");
192 if (signal_name) {
193 formatter.AppendString(signal_name);
194 } else {
195 // Use the signal number if the name is unknown. The signal name
196 // should be known, but just in case.
197 formatter.AppendString("Signal ");
198 formatter.AppendUint64(signal_number, 10);
199 }
200 formatter.AppendString(" (@0x");
201 formatter.AppendUint64(reinterpret_cast<uintptr_t>(siginfo->si_addr), 16);
202 formatter.AppendString(")");
203 formatter.AppendString(" received by PID ");
204 formatter.AppendUint64(getpid(), 10);
205 formatter.AppendString(" (TID 0x");
206 // We assume pthread_t is an integral number or a pointer, rather
207 // than a complex struct. In some environments, pthread_self()
208 // returns an uint64 but in some other environments pthread_self()
209 // returns a pointer. Hence we use C-style cast here, rather than
210 // reinterpret/static_cast, to support both types of environments.
211 formatter.AppendUint64((uintptr_t)pthread_self(), 16);
212 formatter.AppendString(") ");
213 // Only linux has the PID of the signal sender in si_pid.
214#ifdef OS_LINUX
215 formatter.AppendString("from PID ");
216 formatter.AppendUint64(siginfo->si_pid, 10);
217 formatter.AppendString("; ");
218#endif
219 formatter.AppendString("stack trace: ***\n");
220 g_failure_writer(buf, formatter.num_bytes_written());
221}
222
223#endif // HAVE_SIGACTION
224
225// Dumps information about the stack frame to STDERR.
226void DumpStackFrameInfo(const char* prefix, void* pc) {
227 // Get the symbol name.
228 const char *symbol = "(unknown)";
229 char symbolized[1024]; // Big enough for a sane symbol.
230 // Symbolizes the previous address of pc because pc may be in the
231 // next function.
232 if (Symbolize(reinterpret_cast<char *>(pc) - 1,
233 symbolized, sizeof(symbolized))) {
234 symbol = symbolized;
235 }
236
237 char buf[1024]; // Big enough for stack frame info.
238 MinimalFormatter formatter(buf, sizeof(buf));
239
240 formatter.AppendString(prefix);
241 formatter.AppendString("@ ");
242 const int width = 2 * sizeof(void*) + 2; // + 2 for "0x".
243 formatter.AppendHexWithPadding(reinterpret_cast<uintptr_t>(pc), width);
244 formatter.AppendString(" ");
245 formatter.AppendString(symbol);
246 formatter.AppendString("\n");
247 g_failure_writer(buf, formatter.num_bytes_written());
248}
249
250// Invoke the default signal handler.
251void InvokeDefaultSignalHandler(int signal_number) {
252#ifdef HAVE_SIGACTION
253 struct sigaction sig_action;
254 memset(&sig_action, 0, sizeof(sig_action));
255 sigemptyset(&sig_action.sa_mask);
256 sig_action.sa_handler = SIG_DFL;
257 sigaction(signal_number, &sig_action, NULL);
258 kill(getpid(), signal_number);
259#elif defined(OS_WINDOWS)
260 signal(signal_number, SIG_DFL);
261 raise(signal_number);
262#endif
263}
264
265// This variable is used for protecting FailureSignalHandler() from
266// dumping stuff while another thread is doing it. Our policy is to let
267// the first thread dump stuff and let other threads wait.
268// See also comments in FailureSignalHandler().
269static pthread_t* g_entered_thread_id_pointer = NULL;
270
271// Dumps signal and stack frame information, and invokes the default
272// signal handler once our job is done.
273#if defined(OS_WINDOWS)
274void FailureSignalHandler(int signal_number)
275#else
276void FailureSignalHandler(int signal_number,
277 siginfo_t *signal_info,
278 void *ucontext)
279#endif
280{
281 // First check if we've already entered the function. We use an atomic
282 // compare and swap operation for platforms that support it. For other
283 // platforms, we use a naive method that could lead to a subtle race.
284
285 // We assume pthread_self() is async signal safe, though it's not
286 // officially guaranteed.
287 pthread_t my_thread_id = pthread_self();
288 // NOTE: We could simply use pthread_t rather than pthread_t* for this,
289 // if pthread_self() is guaranteed to return non-zero value for thread
290 // ids, but there is no such guarantee. We need to distinguish if the
291 // old value (value returned from __sync_val_compare_and_swap) is
292 // different from the original value (in this case NULL).
293 pthread_t* old_thread_id_pointer =
294 glog_internal_namespace_::sync_val_compare_and_swap(
295 &g_entered_thread_id_pointer,
296 static_cast<pthread_t*>(NULL),
297 &my_thread_id);
298 if (old_thread_id_pointer != NULL) {
299 // We've already entered the signal handler. What should we do?
300 if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
301 // It looks the current thread is reentering the signal handler.
302 // Something must be going wrong (maybe we are reentering by another
303 // type of signal?). Kill ourself by the default signal handler.
304 InvokeDefaultSignalHandler(signal_number);
305 }
306 // Another thread is dumping stuff. Let's wait until that thread
307 // finishes the job and kills the process.
308 while (true) {
309 sleep(1);
310 }
311 }
Austin Schuha8faf282020-03-08 14:49:53 -0700312
313 {
314 // Put this back on SCHED_OTHER by default.
Ravago Jones37f3fbd2020-10-03 17:45:26 -0700315 DIR *dirp = opendir("/proc/self/task");
316 if (dirp) {
317 struct dirent *directory_entry;
318 while ((directory_entry = readdir(dirp)) != NULL) {
319 int thread_id = std::atoi(directory_entry->d_name);
320
321 // ignore . and .. which are zeroes for some reason
322 if (thread_id != 0) {
323 struct sched_param param;
324 param.sched_priority = 20;
325 sched_setscheduler(thread_id, SCHED_OTHER, &param);
326 }
327 }
328 closedir(dirp);
329 } else {
330 // Can't get other threads; just lower own priority.
331 struct sched_param param;
332 param.sched_priority = 20;
333 sched_setscheduler(0, SCHED_OTHER, &param);
334 }
Austin Schuha8faf282020-03-08 14:49:53 -0700335 }
336
Austin Schuh906616c2019-01-21 20:25:11 -0800337 // This is the first time we enter the signal handler. We are going to
338 // do some interesting stuff from here.
339 // TODO(satorux): We might want to set timeout here using alarm(), but
340 // mixing alarm() and sleep() can be a bad idea.
341
342 // First dump time info.
343 DumpTimeInfo();
344
345#if !defined(OS_WINDOWS)
346 // Get the program counter from ucontext.
347 void *pc = GetPC(ucontext);
348 DumpStackFrameInfo("PC: ", pc);
Austin Schuh10358f22019-01-21 20:25:11 -0800349#else
350 (void)ucontext;
Austin Schuh906616c2019-01-21 20:25:11 -0800351#endif
352
353#ifdef HAVE_STACKTRACE
354 // Get the stack traces.
355 void *stack[32];
356 // +1 to exclude this function.
357 const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
358# ifdef HAVE_SIGACTION
359 DumpSignalInfo(signal_number, signal_info);
Austin Schuh10358f22019-01-21 20:25:11 -0800360# else
361 (void)signal_info;
Austin Schuh906616c2019-01-21 20:25:11 -0800362# endif
363 // Dump the stack traces.
364 for (int i = 0; i < depth; ++i) {
365 DumpStackFrameInfo(" ", stack[i]);
366 }
Austin Schuh10358f22019-01-21 20:25:11 -0800367#else
368 (void)signal_info;
Austin Schuh906616c2019-01-21 20:25:11 -0800369#endif
370
371 // *** TRANSITION ***
372 //
373 // BEFORE this point, all code must be async-termination-safe!
374 // (See WARNING above.)
375 //
376 // AFTER this point, we do unsafe things, like using LOG()!
377 // The process could be terminated or hung at any time. We try to
378 // do more useful things first and riskier things later.
379
380 // Flush the logs before we do anything in case 'anything'
381 // causes problems.
382 FlushLogFilesUnsafe(0);
383
384 // Kill ourself by the default signal handler.
385 InvokeDefaultSignalHandler(signal_number);
386}
387
388} // namespace
389
390namespace glog_internal_namespace_ {
391
392bool IsFailureSignalHandlerInstalled() {
393#ifdef HAVE_SIGACTION
394 // TODO(andschwa): Return kFailureSignalHandlerInstalled?
395 struct sigaction sig_action;
396 memset(&sig_action, 0, sizeof(sig_action));
397 sigemptyset(&sig_action.sa_mask);
398 sigaction(SIGABRT, NULL, &sig_action);
399 if (sig_action.sa_sigaction == &FailureSignalHandler)
400 return true;
401#elif defined(OS_WINDOWS)
402 return kFailureSignalHandlerInstalled;
403#endif // HAVE_SIGACTION
404 return false;
405}
406
407} // namespace glog_internal_namespace_
408
409void InstallFailureSignalHandler() {
410#ifdef HAVE_SIGACTION
411 // Build the sigaction struct.
412 struct sigaction sig_action;
413 memset(&sig_action, 0, sizeof(sig_action));
414 sigemptyset(&sig_action.sa_mask);
415 sig_action.sa_flags |= SA_SIGINFO;
416 sig_action.sa_sigaction = &FailureSignalHandler;
417
418 for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
419 CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL));
420 }
421 kFailureSignalHandlerInstalled = true;
422#elif defined(OS_WINDOWS)
423 for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
424 CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler),
425 SIG_ERR);
426 }
427 kFailureSignalHandlerInstalled = true;
428#endif // HAVE_SIGACTION
429}
430
431void InstallFailureWriter(void (*writer)(const char* data, int size)) {
432#if defined(HAVE_SIGACTION) || defined(OS_WINDOWS)
433 g_failure_writer = writer;
434#endif // HAVE_SIGACTION
435}
436
437_END_GOOGLE_NAMESPACE_