1 /*
2 *
3 * Copyright 2015 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 #include "test/core/util/test_config.h"
20
21 #include <inttypes.h>
22 #include <signal.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <grpc/support/alloc.h>
29 #include <grpc/support/log.h>
30
31 #include "src/core/lib/gpr/env.h"
32 #include "src/core/lib/gpr/string.h"
33 #include "src/core/lib/gpr/useful.h"
34
35 int64_t g_fixture_slowdown_factor = 1;
36 int64_t g_poller_slowdown_factor = 1;
37
38 #if GPR_GETPID_IN_UNISTD_H
39 #include <unistd.h>
seed(void)40 static unsigned seed(void) { return static_cast<unsigned>(getpid()); }
41 #endif
42
43 #if GPR_GETPID_IN_PROCESS_H
44 #include <process.h>
seed(void)45 static unsigned seed(void) { return (unsigned)_getpid(); }
46 #endif
47
48 #if GPR_WINDOWS_CRASH_HANDLER
49 #include <windows.h>
50
51 #include <tchar.h>
52
53 // disable warning 4091 - dbghelp.h is broken for msvc2015
54 #pragma warning(disable : 4091)
55 #define DBGHELP_TRANSLATE_TCHAR
56 #include <dbghelp.h>
57
58 #ifdef _MSC_VER
59 #pragma comment(lib, "dbghelp.lib")
60 #endif
61
print_current_stack()62 static void print_current_stack() {
63 typedef USHORT(WINAPI * CaptureStackBackTraceType)(
64 __in ULONG, __in ULONG, __out PVOID*, __out_opt PULONG);
65 CaptureStackBackTraceType func = (CaptureStackBackTraceType)(GetProcAddress(
66 LoadLibrary(_T("kernel32.dll")), "RtlCaptureStackBackTrace"));
67
68 if (func == NULL) return; // WOE 29.SEP.2010
69
70 // Quote from Microsoft Documentation:
71 // ## Windows Server 2003 and Windows XP:
72 // ## The sum of the FramesToSkip and FramesToCapture parameters must be less
73 // than 63.
74 #define MAX_CALLERS 62
75
76 void* callers_stack[MAX_CALLERS];
77 unsigned short frames;
78 SYMBOL_INFOW* symbol;
79 HANDLE process;
80 process = GetCurrentProcess();
81 SymInitialize(process, NULL, TRUE);
82 frames = (func)(0, MAX_CALLERS, callers_stack, NULL);
83 symbol =
84 (SYMBOL_INFOW*)calloc(sizeof(SYMBOL_INFOW) + 256 * sizeof(wchar_t), 1);
85 symbol->MaxNameLen = 255;
86 symbol->SizeOfStruct = sizeof(SYMBOL_INFOW);
87
88 const unsigned short MAX_CALLERS_SHOWN = 32;
89 frames = frames < MAX_CALLERS_SHOWN ? frames : MAX_CALLERS_SHOWN;
90 for (unsigned int i = 0; i < frames; i++) {
91 SymFromAddrW(process, (DWORD64)(callers_stack[i]), 0, symbol);
92 fwprintf(stderr, L"*** %d: %016I64X %ls - %016I64X\n", i,
93 (DWORD64)callers_stack[i], symbol->Name, (DWORD64)symbol->Address);
94 fflush(stderr);
95 }
96
97 free(symbol);
98 }
99
print_stack_from_context(CONTEXT c)100 static void print_stack_from_context(CONTEXT c) {
101 STACKFRAME s; // in/out stackframe
102 memset(&s, 0, sizeof(s));
103 DWORD imageType;
104 #ifdef _M_IX86
105 // normally, call ImageNtHeader() and use machine info from PE header
106 imageType = IMAGE_FILE_MACHINE_I386;
107 s.AddrPC.Offset = c.Eip;
108 s.AddrPC.Mode = AddrModeFlat;
109 s.AddrFrame.Offset = c.Ebp;
110 s.AddrFrame.Mode = AddrModeFlat;
111 s.AddrStack.Offset = c.Esp;
112 s.AddrStack.Mode = AddrModeFlat;
113 #elif _M_X64
114 imageType = IMAGE_FILE_MACHINE_AMD64;
115 s.AddrPC.Offset = c.Rip;
116 s.AddrPC.Mode = AddrModeFlat;
117 s.AddrFrame.Offset = c.Rsp;
118 s.AddrFrame.Mode = AddrModeFlat;
119 s.AddrStack.Offset = c.Rsp;
120 s.AddrStack.Mode = AddrModeFlat;
121 #elif _M_IA64
122 imageType = IMAGE_FILE_MACHINE_IA64;
123 s.AddrPC.Offset = c.StIIP;
124 s.AddrPC.Mode = AddrModeFlat;
125 s.AddrFrame.Offset = c.IntSp;
126 s.AddrFrame.Mode = AddrModeFlat;
127 s.AddrBStore.Offset = c.RsBSP;
128 s.AddrBStore.Mode = AddrModeFlat;
129 s.AddrStack.Offset = c.IntSp;
130 s.AddrStack.Mode = AddrModeFlat;
131 #else
132 #error "Platform not supported!"
133 #endif
134
135 HANDLE process = GetCurrentProcess();
136 HANDLE thread = GetCurrentThread();
137
138 SYMBOL_INFOW* symbol =
139 (SYMBOL_INFOW*)calloc(sizeof(SYMBOL_INFOW) + 256 * sizeof(wchar_t), 1);
140 symbol->MaxNameLen = 255;
141 symbol->SizeOfStruct = sizeof(SYMBOL_INFOW);
142
143 while (StackWalk(imageType, process, thread, &s, &c, 0,
144 SymFunctionTableAccess, SymGetModuleBase, 0)) {
145 BOOL has_symbol =
146 SymFromAddrW(process, (DWORD64)(s.AddrPC.Offset), 0, symbol);
147 fwprintf(
148 stderr, L"*** %016I64X %ls - %016I64X\n", (DWORD64)(s.AddrPC.Offset),
149 has_symbol ? symbol->Name : L"<<no symbol>>", (DWORD64)symbol->Address);
150 fflush(stderr);
151 }
152
153 free(symbol);
154 }
155
crash_handler(struct _EXCEPTION_POINTERS * ex_info)156 static LONG crash_handler(struct _EXCEPTION_POINTERS* ex_info) {
157 fprintf(stderr, "Exception handler called, dumping information\n");
158 bool try_to_print_stack = true;
159 PEXCEPTION_RECORD exrec = ex_info->ExceptionRecord;
160 while (exrec) {
161 DWORD code = exrec->ExceptionCode;
162 DWORD flgs = exrec->ExceptionFlags;
163 PVOID addr = exrec->ExceptionAddress;
164 if (code == EXCEPTION_STACK_OVERFLOW) try_to_print_stack = false;
165 fprintf(stderr, "code: %x - flags: %d - address: %p\n", code, flgs, addr);
166 exrec = exrec->ExceptionRecord;
167 }
168 if (try_to_print_stack) {
169 print_stack_from_context(*ex_info->ContextRecord);
170 }
171 if (IsDebuggerPresent()) {
172 __debugbreak();
173 } else {
174 _exit(1);
175 }
176 return EXCEPTION_EXECUTE_HANDLER;
177 }
178
abort_handler(int sig)179 static void abort_handler(int sig) {
180 fprintf(stderr, "Abort handler called.\n");
181 print_current_stack();
182 if (IsDebuggerPresent()) {
183 __debugbreak();
184 } else {
185 _exit(1);
186 }
187 }
188
install_crash_handler()189 static void install_crash_handler() {
190 if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) {
191 fprintf(stderr, "SymInitialize failed: %d\n", GetLastError());
192 }
193 SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)crash_handler);
194 _set_abort_behavior(0, _WRITE_ABORT_MSG);
195 _set_abort_behavior(0, _CALL_REPORTFAULT);
196 signal(SIGABRT, abort_handler);
197 }
198 #elif GPR_POSIX_CRASH_HANDLER
199 #include <errno.h>
200 #include <execinfo.h>
201 #include <stdio.h>
202 #include <string.h>
203
204 #define SIGNAL_NAMES_LENGTH 32
205
206 static const char* const signal_names[] = {
207 nullptr, "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP",
208 "SIGABRT", "SIGBUS", "SIGFPE", "SIGKILL", "SIGUSR1", "SIGSEGV",
209 "SIGUSR2", "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", "SIGCHLD",
210 "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN", "SIGTTOU", "SIGURG",
211 "SIGXCPU", "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGIO",
212 "SIGPWR", "SIGSYS"};
213
214 static char g_alt_stack[GPR_MAX(MINSIGSTKSZ, 65536)];
215
216 #define MAX_FRAMES 32
217
218 /* signal safe output */
output_string(const char * string)219 static void output_string(const char* string) {
220 size_t len = strlen(string);
221 ssize_t r;
222
223 do {
224 r = write(STDERR_FILENO, string, len);
225 } while (r == -1 && errno == EINTR);
226 }
227
output_num(long num)228 static void output_num(long num) {
229 char buf[GPR_LTOA_MIN_BUFSIZE];
230 gpr_ltoa(num, buf);
231 output_string(buf);
232 }
233
crash_handler(int signum,siginfo_t * info,void * data)234 static void crash_handler(int signum, siginfo_t* info, void* data) {
235 void* addrlist[MAX_FRAMES + 1];
236 int addrlen;
237
238 output_string("\n\n\n*******************************\nCaught signal ");
239 if (signum > 0 && signum < SIGNAL_NAMES_LENGTH) {
240 output_string(signal_names[signum]);
241 } else {
242 output_num(signum);
243 }
244 output_string("\n");
245
246 addrlen = backtrace(addrlist, GPR_ARRAY_SIZE(addrlist));
247
248 if (addrlen == 0) {
249 output_string(" no backtrace\n");
250 } else {
251 backtrace_symbols_fd(addrlist, addrlen, STDERR_FILENO);
252 }
253
254 /* try to get a core dump for SIGTERM */
255 if (signum == SIGTERM) signum = SIGQUIT;
256 raise(signum);
257 }
258
install_crash_handler()259 static void install_crash_handler() {
260 stack_t ss;
261 struct sigaction sa;
262
263 memset(&ss, 0, sizeof(ss));
264 memset(&sa, 0, sizeof(sa));
265 ss.ss_size = sizeof(g_alt_stack);
266 ss.ss_sp = g_alt_stack;
267 GPR_ASSERT(sigaltstack(&ss, nullptr) == 0);
268 sa.sa_flags = static_cast<int>(SA_SIGINFO | SA_ONSTACK | SA_RESETHAND);
269 sa.sa_sigaction = crash_handler;
270 GPR_ASSERT(sigaction(SIGILL, &sa, nullptr) == 0);
271 GPR_ASSERT(sigaction(SIGABRT, &sa, nullptr) == 0);
272 GPR_ASSERT(sigaction(SIGBUS, &sa, nullptr) == 0);
273 GPR_ASSERT(sigaction(SIGSEGV, &sa, nullptr) == 0);
274 GPR_ASSERT(sigaction(SIGTERM, &sa, nullptr) == 0);
275 GPR_ASSERT(sigaction(SIGQUIT, &sa, nullptr) == 0);
276 }
277 #else
install_crash_handler()278 static void install_crash_handler() {}
279 #endif
280
BuiltUnderValgrind()281 bool BuiltUnderValgrind() {
282 #ifdef RUNNING_ON_VALGRIND
283 return true;
284 #else
285 return false;
286 #endif
287 }
288
BuiltUnderTsan()289 bool BuiltUnderTsan() {
290 #if defined(__has_feature)
291 #if __has_feature(thread_sanitizer)
292 return true;
293 #else
294 return false;
295 #endif
296 #else
297 #ifdef THREAD_SANITIZER
298 return true;
299 #else
300 return false;
301 #endif
302 #endif
303 }
304
BuiltUnderAsan()305 bool BuiltUnderAsan() {
306 #if defined(__has_feature)
307 #if __has_feature(address_sanitizer)
308 return true;
309 #else
310 return false;
311 #endif
312 #else
313 #ifdef ADDRESS_SANITIZER
314 return true;
315 #else
316 return false;
317 #endif
318 #endif
319 }
320
BuiltUnderMsan()321 bool BuiltUnderMsan() {
322 #if defined(__has_feature)
323 #if __has_feature(memory_sanitizer)
324 return true;
325 #else
326 return false;
327 #endif
328 #else
329 #ifdef MEMORY_SANITIZER
330 return true;
331 #else
332 return false;
333 #endif
334 #endif
335 }
336
BuiltUnderUbsan()337 bool BuiltUnderUbsan() {
338 #ifdef GRPC_UBSAN
339 return true;
340 #else
341 return false;
342 #endif
343 }
344
grpc_test_sanitizer_slowdown_factor()345 int64_t grpc_test_sanitizer_slowdown_factor() {
346 int64_t sanitizer_multiplier = 1;
347 if (BuiltUnderValgrind()) {
348 sanitizer_multiplier = 20;
349 } else if (BuiltUnderTsan()) {
350 sanitizer_multiplier = 5;
351 } else if (BuiltUnderAsan()) {
352 sanitizer_multiplier = 3;
353 } else if (BuiltUnderMsan()) {
354 sanitizer_multiplier = 4;
355 } else if (BuiltUnderUbsan()) {
356 sanitizer_multiplier = 5;
357 }
358 return sanitizer_multiplier;
359 }
360
grpc_test_slowdown_factor()361 int64_t grpc_test_slowdown_factor() {
362 return grpc_test_sanitizer_slowdown_factor() * g_fixture_slowdown_factor *
363 g_poller_slowdown_factor;
364 }
365
grpc_timeout_seconds_to_deadline(int64_t time_s)366 gpr_timespec grpc_timeout_seconds_to_deadline(int64_t time_s) {
367 return gpr_time_add(
368 gpr_now(GPR_CLOCK_MONOTONIC),
369 gpr_time_from_millis(
370 grpc_test_slowdown_factor() * static_cast<int64_t>(1e3) * time_s,
371 GPR_TIMESPAN));
372 }
373
grpc_timeout_milliseconds_to_deadline(int64_t time_ms)374 gpr_timespec grpc_timeout_milliseconds_to_deadline(int64_t time_ms) {
375 return gpr_time_add(
376 gpr_now(GPR_CLOCK_MONOTONIC),
377 gpr_time_from_micros(
378 grpc_test_slowdown_factor() * static_cast<int64_t>(1e3) * time_ms,
379 GPR_TIMESPAN));
380 }
381
grpc_test_init(int argc,char ** argv)382 void grpc_test_init(int argc, char** argv) {
383 install_crash_handler();
384 { /* poll-cv poll strategy runs much more slowly than anything else */
385 char* s = gpr_getenv("GRPC_POLL_STRATEGY");
386 if (s != nullptr && 0 == strcmp(s, "poll-cv")) {
387 g_poller_slowdown_factor = 5;
388 }
389 gpr_free(s);
390 }
391 gpr_log(GPR_DEBUG,
392 "test slowdown factor: sanitizer=%" PRId64 ", fixture=%" PRId64
393 ", poller=%" PRId64 ", total=%" PRId64,
394 grpc_test_sanitizer_slowdown_factor(), g_fixture_slowdown_factor,
395 g_poller_slowdown_factor, grpc_test_slowdown_factor());
396 /* seed rng with pid, so we don't end up with the same random numbers as a
397 concurrently running test binary */
398 srand(seed());
399 }
400