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