File: fatal_signal_asan_no_sig_test.cc

package info (click to toggle)
pytorch 1.13.1%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 139,252 kB
  • sloc: cpp: 1,100,274; python: 706,454; ansic: 83,052; asm: 7,618; java: 3,273; sh: 2,841; javascript: 612; makefile: 323; xml: 269; ruby: 185; yacc: 144; objc: 68; lex: 44
file content (148 lines) | stat: -rw-r--r-- 4,732 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#include "caffe2/utils/signal_handler.h"
#if defined(C10_SUPPORTS_FATAL_SIGNAL_HANDLERS)
#include <gtest/gtest.h>
#include <pthread.h>
#include <unistd.h>

#include <functional>
#include <iostream>
#include <array>

#include "caffe2/core/common.h"

namespace {
void* dummy_thread(void*) {
  while (1) {
  }
  return nullptr;
}

bool forkAndPipe(
    std::string& stderrBuffer,
    std::function<void(void)> callback) {
  std::array<int, 2> stderrPipe;
  if (pipe(stderrPipe.data()) != 0) {
    perror("STDERR pipe");
    return false;
  }
  pid_t child = fork();
  if (child == 0) {
    // Replace this process' stderr so we can read it.
    if (dup2(stderrPipe[1], STDERR_FILENO) < 0) {
      close(stderrPipe[0]);
      close(stderrPipe[1]);
      perror("dup2 STDERR");
      exit(5);
    }

    // This is for the parent to work with.
    close(stderrPipe[0]);
    close(stderrPipe[1]);

    callback();
    exit(7);
  } else if (child > 0) {
    const int bufferSize = 128;
    std::array<char, bufferSize> buffer;

    // We want to close the writing end of the pipe right away so our
    // read actually gets an EOF.
    close(stderrPipe[1]);

    // wait for child to finish crashing.
    int statloc;
    if (wait(&statloc) < 0) {
      close(stderrPipe[0]);
      perror("wait");
      return false;
    }

    ssize_t bytesRead;
    while ((bytesRead = read(stderrPipe[0], buffer.data(), bufferSize)) > 0) {
      const std::string tmp(buffer.data(), bytesRead);
      std::cout << tmp;
      stderrBuffer += tmp;
    }

    // The child should have exited due to signal.
    if (!WIFSIGNALED(statloc)) {
      fprintf(stderr, "Child didn't exit because it received a signal\n");
      if (WIFEXITED(statloc)) {
        fprintf(stderr, "Exited with code: %d\n", WEXITSTATUS(statloc) & 0xff);
      }
      return false;
    }

    if (bytesRead < 0) {
      perror("read");
      return false;
    }

    close(stderrPipe[0]);
    return true;
  } else {
    perror("fork");
    return false;
  }
}
} // namespace

#define _TEST_FATAL_SIGNAL(signum, name, threadCount, print, expected)       \
  do {                                                                       \
    std::string stderrBuffer;                                                \
    ASSERT_TRUE(forkAndPipe(stderrBuffer, [=]() {                            \
      caffe2::setPrintStackTracesOnFatalSignal(print);                       \
      pthread_t pt;                                                          \
      for (int i = 0; i < threadCount; i++) {                                \
        if (pthread_create(&pt, nullptr, ::dummy_thread, nullptr)) {         \
          perror("pthread_create");                                          \
        }                                                                    \
      }                                                                      \
      raise(signum);                                                         \
    }));                                                                     \
    int keyPhraseCount = 0;                                                  \
    std::string keyPhrase =                                                  \
        std::string(name) + "(" + c10::to_string(signum) + ")";              \
    size_t loc = 0;                                                          \
    while ((loc = stderrBuffer.find(keyPhrase, loc)) != std::string::npos) { \
      keyPhraseCount += 1;                                                   \
      loc += 1;                                                              \
    }                                                                        \
    EXPECT_GE(keyPhraseCount, expected);                                     \
  } while (0)

#define TEST_FATAL_SIGNAL(signum, name, threadCount) \
  _TEST_FATAL_SIGNAL(signum, name, threadCount, true, threadCount + 1)

#define TEST_FATAL_SIGNAL_NO_PRINT(signum, name, threadCount) \
  _TEST_FATAL_SIGNAL(signum, name, threadCount, false, 0)

TEST(fatalSignalTest, SIGABRT8) {
  TEST_FATAL_SIGNAL(SIGABRT, "SIGABRT", 8);
}

TEST(fatalSignalTest, SIGINT8) {
  TEST_FATAL_SIGNAL(SIGINT, "SIGINT", 8);
}

TEST(fatalSignalTest, SIGILL8) {
  TEST_FATAL_SIGNAL(SIGILL, "SIGILL", 8);
}

TEST(fatalSignalTest, SIGFPE8) {
  TEST_FATAL_SIGNAL(SIGFPE, "SIGFPE", 8);
}

TEST(fatalSignalTest, SIGBUS8) {
  TEST_FATAL_SIGNAL(SIGBUS, "SIGBUS", 8);
}

TEST(fatalSignalTest, SIGSEGV8) {
  TEST_FATAL_SIGNAL(SIGSEGV, "SIGSEGV", 8);
}

// Test that if we don't enable printing stack traces then we don't get any.
TEST(fatalSignalTest, SIGABRT8_NOPRINT) {
  TEST_FATAL_SIGNAL_NO_PRINT(SIGABRT, "SIGABRT", 8);
}
#endif // defined(C10_SUPPORTS_FATAL_SIGNAL_HANDLERS)