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