1 //===--- rtsan_context.cpp - Realtime Sanitizer -----------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 //===----------------------------------------------------------------------===// 10 11 #include <rtsan/rtsan_context.h> 12 13 #include <rtsan/rtsan_stack.h> 14 15 #include <sanitizer_common/sanitizer_allocator_internal.h> 16 #include <sanitizer_common/sanitizer_stacktrace.h> 17 18 #include <new> 19 #include <pthread.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 23 static pthread_key_t context_key; 24 static pthread_once_t key_once = PTHREAD_ONCE_INIT; 25 26 // InternalFree cannot be passed directly to pthread_key_create 27 // because it expects a signature with only one arg 28 static void InternalFreeWrapper(void *ptr) { __sanitizer::InternalFree(ptr); } 29 30 static __rtsan::Context &GetContextForThisThreadImpl() { 31 auto make_thread_local_context_key = []() { 32 CHECK_EQ(pthread_key_create(&context_key, InternalFreeWrapper), 0); 33 }; 34 35 pthread_once(&key_once, make_thread_local_context_key); 36 __rtsan::Context *current_thread_context = 37 static_cast<__rtsan::Context *>(pthread_getspecific(context_key)); 38 if (current_thread_context == nullptr) { 39 current_thread_context = static_cast<__rtsan::Context *>( 40 __sanitizer::InternalAlloc(sizeof(__rtsan::Context))); 41 new (current_thread_context) __rtsan::Context(); 42 pthread_setspecific(context_key, current_thread_context); 43 } 44 45 return *current_thread_context; 46 } 47 48 /* 49 This is a placeholder stub for a future feature that will allow 50 a user to configure RTSan's behaviour when a real-time safety 51 violation is detected. The RTSan developers intend for the 52 following choices to be made available, via a RTSAN_OPTIONS 53 environment variable, in a future PR: 54 55 i) exit, 56 ii) continue, or 57 iii) wait for user input from stdin. 58 59 Until then, and to keep the first PRs small, only the exit mode 60 is available. 61 */ 62 static void InvokeViolationDetectedAction() { exit(EXIT_FAILURE); } 63 64 __rtsan::Context::Context() = default; 65 66 void __rtsan::Context::RealtimePush() { realtime_depth++; } 67 68 void __rtsan::Context::RealtimePop() { realtime_depth--; } 69 70 void __rtsan::Context::BypassPush() { bypass_depth++; } 71 72 void __rtsan::Context::BypassPop() { bypass_depth--; } 73 74 void __rtsan::Context::ExpectNotRealtime( 75 const char *intercepted_function_name) { 76 if (InRealtimeContext() && !IsBypassed()) { 77 BypassPush(); 78 PrintDiagnostics(intercepted_function_name); 79 InvokeViolationDetectedAction(); 80 BypassPop(); 81 } 82 } 83 84 bool __rtsan::Context::InRealtimeContext() const { return realtime_depth > 0; } 85 86 bool __rtsan::Context::IsBypassed() const { return bypass_depth > 0; } 87 88 void __rtsan::Context::PrintDiagnostics(const char *intercepted_function_name) { 89 fprintf(stderr, 90 "Real-time violation: intercepted call to real-time unsafe function " 91 "`%s` in real-time context! Stack trace:\n", 92 intercepted_function_name); 93 __rtsan::PrintStackTrace(); 94 } 95 96 __rtsan::Context &__rtsan::GetContextForThisThread() { 97 return GetContextForThisThreadImpl(); 98 } 99