[compiler-rt] 1b60193 - [rtsan][compiler-rt] Introduce __rtsan_notify_blocking_call (#109529)

via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 21 09:08:21 PDT 2024


Author: Chris Apple
Date: 2024-09-21T10:08:18-06:00
New Revision: 1b6019388c17657c1c07f1e3123a7b4000f94490

URL: https://github.com/llvm/llvm-project/commit/1b6019388c17657c1c07f1e3123a7b4000f94490
DIFF: https://github.com/llvm/llvm-project/commit/1b6019388c17657c1c07f1e3123a7b4000f94490.diff

LOG: [rtsan][compiler-rt] Introduce __rtsan_notify_blocking_call (#109529)

# Why?

In llvm, we need to add a call to `__rtsan_notify_blocking_call()` when
a function is marked `[[clang::blocking]]`. This will produce a
different error message than a call to an unsafe malloc etc

Added: 
    compiler-rt/test/rtsan/blocking_call.cpp

Modified: 
    compiler-rt/lib/rtsan/rtsan.cpp
    compiler-rt/lib/rtsan/rtsan.h
    compiler-rt/lib/rtsan/rtsan_assertions.cpp
    compiler-rt/lib/rtsan/rtsan_assertions.h
    compiler-rt/lib/rtsan/rtsan_diagnostics.cpp
    compiler-rt/lib/rtsan/rtsan_diagnostics.h
    compiler-rt/lib/rtsan/tests/rtsan_test_assertions.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/rtsan/rtsan.cpp b/compiler-rt/lib/rtsan/rtsan.cpp
index fe7247ec8e7bbc..936f0b5b8cee39 100644
--- a/compiler-rt/lib/rtsan/rtsan.cpp
+++ b/compiler-rt/lib/rtsan/rtsan.cpp
@@ -16,6 +16,7 @@
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
 
 using namespace __rtsan;
 using namespace __sanitizer;
@@ -75,6 +76,20 @@ SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_enable() {
 SANITIZER_INTERFACE_ATTRIBUTE void
 __rtsan_notify_intercepted_call(const char *intercepted_function_name) {
   __rtsan_ensure_initialized();
-  ExpectNotRealtime(GetContextForThisThread(), intercepted_function_name);
+
+  GET_CALLER_PC_BP;
+  DiagnosticsInfo info = {InterceptedCallInfo{intercepted_function_name}, pc,
+                          bp};
+  ExpectNotRealtime(GetContextForThisThread(), info);
 }
+
+SANITIZER_INTERFACE_ATTRIBUTE void
+__rtsan_notify_blocking_call(const char *blocking_function_name) {
+  __rtsan_ensure_initialized();
+
+  GET_CALLER_PC_BP;
+  DiagnosticsInfo info = {BlockingCallInfo{blocking_function_name}, pc, bp};
+  ExpectNotRealtime(GetContextForThisThread(), info);
+}
+
 } // extern "C"

diff  --git a/compiler-rt/lib/rtsan/rtsan.h b/compiler-rt/lib/rtsan/rtsan.h
index b690f734e10327..37628ae2731f6d 100644
--- a/compiler-rt/lib/rtsan/rtsan.h
+++ b/compiler-rt/lib/rtsan/rtsan.h
@@ -45,4 +45,6 @@ SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_enable();
 SANITIZER_INTERFACE_ATTRIBUTE void
 __rtsan_notify_intercepted_call(const char *intercepted_function_name);
 
+SANITIZER_INTERFACE_ATTRIBUTE void
+__rtsan_notify_blocking_call(const char *blocking_function_name);
 } // extern "C"

diff  --git a/compiler-rt/lib/rtsan/rtsan_assertions.cpp b/compiler-rt/lib/rtsan/rtsan_assertions.cpp
index ef996c92dc1e82..4aae85de5c52f1 100644
--- a/compiler-rt/lib/rtsan/rtsan_assertions.cpp
+++ b/compiler-rt/lib/rtsan/rtsan_assertions.cpp
@@ -14,18 +14,14 @@
 #include "rtsan/rtsan.h"
 #include "rtsan/rtsan_diagnostics.h"
 
-#include "sanitizer_common/sanitizer_stacktrace.h"
-
 using namespace __sanitizer;
 
-void __rtsan::ExpectNotRealtime(Context &context,
-                                const char *intercepted_function_name) {
+void __rtsan::ExpectNotRealtime(Context &context, const DiagnosticsInfo &info) {
   CHECK(__rtsan_is_initialized());
   if (context.InRealtimeContext() && !context.IsBypassed()) {
     context.BypassPush();
 
-    GET_CALLER_PC_BP;
-    PrintDiagnostics(intercepted_function_name, pc, bp);
+    PrintDiagnostics(info);
     Die();
     context.BypassPop();
   }

diff  --git a/compiler-rt/lib/rtsan/rtsan_assertions.h b/compiler-rt/lib/rtsan/rtsan_assertions.h
index bc38a0f116eec2..bc1235363669df 100644
--- a/compiler-rt/lib/rtsan/rtsan_assertions.h
+++ b/compiler-rt/lib/rtsan/rtsan_assertions.h
@@ -13,7 +13,9 @@
 #pragma once
 
 #include "rtsan/rtsan_context.h"
+#include "rtsan/rtsan_diagnostics.h"
 
 namespace __rtsan {
-void ExpectNotRealtime(Context &context, const char *intercepted_function_name);
+
+void ExpectNotRealtime(Context &context, const DiagnosticsInfo &info);
 } // namespace __rtsan

diff  --git a/compiler-rt/lib/rtsan/rtsan_diagnostics.cpp b/compiler-rt/lib/rtsan/rtsan_diagnostics.cpp
index d4c656606f3653..ac13b0743be069 100644
--- a/compiler-rt/lib/rtsan/rtsan_diagnostics.cpp
+++ b/compiler-rt/lib/rtsan/rtsan_diagnostics.cpp
@@ -34,9 +34,15 @@ namespace {
 class Decorator : public __sanitizer::SanitizerCommonDecorator {
 public:
   Decorator() : SanitizerCommonDecorator() {}
-  const char *FunctionName() { return Green(); }
-  const char *Reason() { return Blue(); }
+  const char *FunctionName() const { return Green(); }
+  const char *Reason() const { return Blue(); }
 };
+
+template <class... Ts> struct Overloaded : Ts... {
+  using Ts::operator()...;
+};
+// TODO: Remove below when c++20
+template <class... Ts> Overloaded(Ts...) -> Overloaded<Ts...>;
 } // namespace
 
 static void PrintStackTrace(uptr pc, uptr bp) {
@@ -46,18 +52,46 @@ static void PrintStackTrace(uptr pc, uptr bp) {
   stack.Print();
 }
 
-void __rtsan::PrintDiagnostics(const char *intercepted_function_name, uptr pc,
-                               uptr bp) {
+static void PrintError(const Decorator &decorator,
+                       const DiagnosticsCallerInfo &info) {
+  const char *violation_type = std::visit(
+      Overloaded{
+          [](const InterceptedCallInfo &) { return "unsafe-library-call"; },
+          [](const BlockingCallInfo &) { return "blocking-call"; }},
+      info);
+
+  Printf("%s", decorator.Error());
+  Report("ERROR: RealtimeSanitizer: %s\n", violation_type);
+}
+
+static void PrintReason(const Decorator &decorator,
+                        const DiagnosticsCallerInfo &info) {
+  Printf("%s", decorator.Reason());
+
+  std::visit(
+      Overloaded{[decorator](const InterceptedCallInfo &call) {
+                   Printf("Intercepted call to real-time unsafe function "
+                          "`%s%s%s` in real-time context!",
+                          decorator.FunctionName(),
+                          call.intercepted_function_name_, decorator.Reason());
+                 },
+                 [decorator](const BlockingCallInfo &arg) {
+                   Printf("Call to blocking function "
+                          "`%s%s%s` in real-time context!",
+                          decorator.FunctionName(), arg.blocking_function_name_,
+                          decorator.Reason());
+                 }},
+      info);
+
+  Printf("\n");
+}
+
+void __rtsan::PrintDiagnostics(const DiagnosticsInfo &info) {
   ScopedErrorReportLock l;
 
   Decorator d;
-  Printf("%s", d.Error());
-  Report("ERROR: RealtimeSanitizer: unsafe-library-call\n");
-  Printf("%s", d.Reason());
-  Printf("Intercepted call to real-time unsafe function "
-         "`%s%s%s` in real-time context!\n",
-         d.FunctionName(), intercepted_function_name, d.Reason());
-
+  PrintError(d, info.call_info);
+  PrintReason(d, info.call_info);
   Printf("%s", d.Default());
-  PrintStackTrace(pc, bp);
+  PrintStackTrace(info.pc, info.bp);
 }

diff  --git a/compiler-rt/lib/rtsan/rtsan_diagnostics.h b/compiler-rt/lib/rtsan/rtsan_diagnostics.h
index 1d6c3ccb7bc7eb..8aec512584b309 100644
--- a/compiler-rt/lib/rtsan/rtsan_diagnostics.h
+++ b/compiler-rt/lib/rtsan/rtsan_diagnostics.h
@@ -12,9 +12,31 @@
 
 #pragma once
 
+#include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 
+#include <variant>
+
 namespace __rtsan {
-void PrintDiagnostics(const char *intercepted_function_name,
-                      __sanitizer::uptr pc, __sanitizer::uptr bp);
+
+struct InterceptedCallInfo {
+  const char *intercepted_function_name_;
+};
+
+struct BlockingCallInfo {
+public:
+  const char *blocking_function_name_;
+};
+
+using DiagnosticsCallerInfo =
+    std::variant<InterceptedCallInfo, BlockingCallInfo>;
+
+struct DiagnosticsInfo {
+  DiagnosticsCallerInfo call_info;
+
+  __sanitizer::uptr pc;
+  __sanitizer::uptr bp;
+};
+
+void PrintDiagnostics(const DiagnosticsInfo &info);
 } // namespace __rtsan

diff  --git a/compiler-rt/lib/rtsan/tests/rtsan_test_assertions.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_assertions.cpp
index cdf2ac32170043..b6999eeb7746a2 100644
--- a/compiler-rt/lib/rtsan/tests/rtsan_test_assertions.cpp
+++ b/compiler-rt/lib/rtsan/tests/rtsan_test_assertions.cpp
@@ -13,30 +13,41 @@
 #include "rtsan_test_utilities.h"
 
 #include "rtsan/rtsan_assertions.h"
+#include "rtsan/rtsan_diagnostics.h"
 
 #include <gtest/gtest.h>
 
+using namespace __rtsan;
+
 class TestRtsanAssertions : public ::testing::Test {
 protected:
   void SetUp() override { __rtsan_ensure_initialized(); }
 };
 
+DiagnosticsInfo FakeDiagnosticsInfo() {
+  DiagnosticsInfo info;
+  info.pc = 0;
+  info.bp = 0;
+  info.call_info = InterceptedCallInfo{"fake_function_name"};
+  return info;
+}
+
 TEST_F(TestRtsanAssertions, ExpectNotRealtimeDoesNotDieIfNotInRealtimeContext) {
   __rtsan::Context context{};
   ASSERT_FALSE(context.InRealtimeContext());
-  ExpectNotRealtime(context, "fake_function_name");
+  ExpectNotRealtime(context, FakeDiagnosticsInfo());
 }
 
 TEST_F(TestRtsanAssertions, ExpectNotRealtimeDiesIfInRealtimeContext) {
   __rtsan::Context context{};
   context.RealtimePush();
   ASSERT_TRUE(context.InRealtimeContext());
-  EXPECT_DEATH(ExpectNotRealtime(context, "fake_function_name"), "");
+  EXPECT_DEATH(ExpectNotRealtime(context, FakeDiagnosticsInfo()), "");
 }
 
 TEST_F(TestRtsanAssertions, ExpectNotRealtimeDoesNotDieIfRealtimeButBypassed) {
   __rtsan::Context context{};
   context.RealtimePush();
   context.BypassPush();
-  ExpectNotRealtime(context, "fake_function_name");
+  ExpectNotRealtime(context, FakeDiagnosticsInfo());
 }

diff  --git a/compiler-rt/test/rtsan/blocking_call.cpp b/compiler-rt/test/rtsan/blocking_call.cpp
new file mode 100644
index 00000000000000..47ce3d5544cbd6
--- /dev/null
+++ b/compiler-rt/test/rtsan/blocking_call.cpp
@@ -0,0 +1,34 @@
+// RUN: %clangxx -fsanitize=realtime %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// UNSUPPORTED: ios
+
+// Intent: Check that a function marked with [[clang::nonblocking]] cannot call a function that is blocking.
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// TODO: Remove when [[blocking]] is implemented.
+extern "C" void __rtsan_notify_blocking_call(const char *function_name);
+
+void custom_blocking_function() {
+  // TODO: When [[blocking]] is implemented, don't call this directly.
+  __rtsan_notify_blocking_call(__func__);
+}
+
+void safe_call() {
+  // TODO: When [[blocking]] is implemented, don't call this directly.
+  __rtsan_notify_blocking_call(__func__);
+}
+
+void process() [[clang::nonblocking]] { custom_blocking_function(); }
+
+int main() {
+  safe_call(); // This shouldn't die, because it isn't in nonblocking context.
+  process();
+  return 0;
+  // CHECK-NOT: {{.*safe_call*}}
+  // CHECK: ==ERROR: RealtimeSanitizer: blocking-call
+  // CHECK-NEXT: Call to blocking function `custom_blocking_function` in real-time context!
+  // CHECK-NEXT: {{.*custom_blocking_function*}}
+  // CHECK-NEXT: {{.*process*}}
+}


        


More information about the llvm-commits mailing list