• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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