Home | History | Annotate | Download | only in platform
      1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 you may not use this file except in compliance with the License.
      5 You may obtain a copy of the License at
      6 
      7     http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 Unless required by applicable law or agreed to in writing, software
     10 distributed under the License is distributed on an "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 See the License for the specific language governing permissions and
     13 limitations under the License.
     14 ==============================================================================*/
     15 
     16 #include "tensorflow/core/platform/platform.h"
     17 
     18 #if !defined(PLATFORM_GOOGLE) && !defined(IS_MOBILE_PLATFORM) && \
     19     defined(PLATFORM_POSIX) && (defined(__clang__) || defined(__GNUC__))
     20 #define TF_GENERATE_STACKTRACE
     21 #endif
     22 
     23 #if defined(TF_GENERATE_STACKTRACE)
     24 #include <errno.h>
     25 #include <signal.h>
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 #include <string.h>
     29 #include <sys/time.h>
     30 #include <unistd.h>
     31 #include <string>
     32 
     33 #include "tensorflow/core/platform/abi.h"
     34 #include "tensorflow/core/platform/stacktrace.h"
     35 
     36 #endif  // defined(TF_GENERATE_STACKTRACE)
     37 
     38 namespace tensorflow {
     39 namespace testing {
     40 
     41 #if defined(TF_GENERATE_STACKTRACE)
     42 // This function will print stacktrace to STDERR.
     43 // It avoids using malloc, so it makes sure to dump the stack even when the heap
     44 // is corrupted. However, it can dump mangled symbols.
     45 inline void SafePrintStackTrace() {
     46   static const char begin_msg[] = "*** BEGIN MANGLED STACK TRACE ***\n";
     47   (void)write(STDERR_FILENO, begin_msg, strlen(begin_msg));
     48 
     49   int buffer_size = 128;
     50   void *trace[128];
     51   // Run backtrace to get the size of the stacktrace
     52   buffer_size = backtrace(trace, buffer_size);
     53 
     54   // Print a mangled stacktrace to STDERR as safely as possible.
     55   backtrace_symbols_fd(trace, buffer_size, STDERR_FILENO);
     56 
     57   static const char end_msg[] = "*** END MANGLED STACK TRACE ***\n\n";
     58   (void)write(STDERR_FILENO, end_msg, strlen(end_msg));
     59 }
     60 
     61 static void StacktraceHandler(int sig, siginfo_t *si, void *v) {
     62   // Make sure our handler does not deadlock. And this should be the last thing
     63   // our program does. Therefore, set a timer to kill the program in 60
     64   // seconds.
     65   struct itimerval timer;
     66   timer.it_value.tv_sec = 60;
     67   timer.it_value.tv_usec = 0;
     68   timer.it_interval.tv_sec = 0;
     69   timer.it_interval.tv_usec = 0;
     70   setitimer(ITIMER_REAL, &timer, 0);
     71 
     72   struct sigaction sa_timeout;
     73   memset(&sa_timeout, 0, sizeof(sa_timeout));
     74   sa_timeout.sa_handler = SIG_DFL;
     75   sigaction(SIGALRM, &sa_timeout, 0);
     76 
     77   char buf[128];
     78 
     79   snprintf(buf, sizeof(buf), "*** Received signal %d ***\n", sig);
     80   (void)write(STDERR_FILENO, buf, strlen(buf));
     81 
     82   // Print "a" stack trace, as safely as possible.
     83   SafePrintStackTrace();
     84 
     85   // Up until this line, we made sure not to allocate memory, to be able to dump
     86   // a stack trace even in the event of heap corruption. After this line, we
     87   // will try to print more human readable things to the terminal.
     88   // But these have a higher probability to fail.
     89   std::string stacktrace = CurrentStackTrace();
     90   (void)write(STDERR_FILENO, stacktrace.c_str(), stacktrace.length());
     91 
     92   // Abort the program.
     93   struct sigaction sa;
     94   sigemptyset(&sa.sa_mask);
     95   sa.sa_flags = 0;
     96   sa.sa_handler = SIG_DFL;
     97   sigaction(SIGABRT, &sa, NULL);
     98   abort();
     99 }
    100 
    101 void InstallStacktraceHandler() {
    102   int handled_signals[] = {SIGSEGV, SIGABRT, SIGBUS, SIGILL, SIGFPE};
    103 
    104   for (int i = 0; i < sizeof(handled_signals) / sizeof(int); i++) {
    105     int sig = handled_signals[i];
    106     struct sigaction sa;
    107     struct sigaction osa;
    108 
    109     sigemptyset(&sa.sa_mask);
    110     sa.sa_flags = SA_SIGINFO | SA_RESETHAND;
    111     sa.sa_sigaction = &StacktraceHandler;
    112     if (sigaction(sig, &sa, &osa) != 0) {
    113       char buf[128];
    114       snprintf(buf, sizeof(buf),
    115                "Warning, can't install backtrace signal handler for signal %d, "
    116                "errno:%d \n",
    117                sig, errno);
    118       (void)write(STDERR_FILENO, buf, strlen(buf));
    119     } else if (osa.sa_handler != SIG_DFL) {
    120       char buf[128];
    121       snprintf(buf, sizeof(buf),
    122                "Warning, backtrace signal handler for signal %d overwrote "
    123                "previous handler.\n",
    124                sig);
    125       (void)write(STDERR_FILENO, buf, strlen(buf));
    126     }
    127   }
    128 }
    129 
    130 #else
    131 void InstallStacktraceHandler() {}
    132 #endif  // defined(TF_GENERATE_STACKTRACE)
    133 
    134 }  // namespace testing
    135 }  // namespace tensorflow
    136