[llvm] f7f0159 - sanmd: refine selection of functions for UAR checking

Dmitry Vyukov via llvm-commits llvm-commits at lists.llvm.org
Sat Jan 21 00:51:20 PST 2023


Author: Dmitry Vyukov
Date: 2023-01-21T09:51:15+01:00
New Revision: f7f01599ece64c04e70fbdb025a33d686fef7d6e

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

LOG: sanmd: refine selection of functions for UAR checking

There are no intrinsic functions that leak arguments.
If the called function does not return, the current function
does not return as well, so no possibility of use-after-return.
Sanitizer function also don't leak or don't return.
It's safe to both pass pointers to local variables to them
and to tail-call them.

Reviewed By: melver

Differential Revision: https://reviews.llvm.org/D142190

Added: 
    

Modified: 
    compiler-rt/test/CMakeLists.txt
    compiler-rt/test/metadata/CMakeLists.txt
    compiler-rt/test/metadata/uar.cpp
    llvm/lib/Transforms/Instrumentation/SanitizerBinaryMetadata.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/test/CMakeLists.txt b/compiler-rt/test/CMakeLists.txt
index 04ff819c6e5af..852a2883ea5e0 100644
--- a/compiler-rt/test/CMakeLists.txt
+++ b/compiler-rt/test/CMakeLists.txt
@@ -78,6 +78,9 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
     # OpenBSD not supporting asan, cannot run the tests
     if(COMPILER_RT_BUILD_LIBFUZZER AND NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD" AND NOT ANDROID)
       compiler_rt_test_runtime(fuzzer)
+
+      # These tests don't need an additional runtime but use asan runtime.
+      add_subdirectory(metadata)
     endif()
 
     foreach(sanitizer ${COMPILER_RT_SANITIZERS_TO_BUILD})
@@ -105,8 +108,6 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
   # ShadowCallStack does not yet provide a runtime with compiler-rt, the tests
   # include their own minimal runtime
   add_subdirectory(shadowcallstack)
-  # These tests are self-contained and don't need an additional runtime.
-  add_subdirectory(metadata)
 endif()
 
 if(COMPILER_RT_STANDALONE_BUILD)

diff  --git a/compiler-rt/test/metadata/CMakeLists.txt b/compiler-rt/test/metadata/CMakeLists.txt
index 3391a8961fbc0..4a17b0e924454 100644
--- a/compiler-rt/test/metadata/CMakeLists.txt
+++ b/compiler-rt/test/metadata/CMakeLists.txt
@@ -4,6 +4,11 @@ if(CAN_TARGET_x86_64)
   set(METADATA_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
   set(METADATA_LIT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
 
+  set(METADATA_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+  if (NOT COMPILER_RT_STANDALONE_BUILD)
+    list(APPEND METADATA_TEST_DEPS asan ubsan)
+  endif()
+
   set(SANITIZER_COMMON_TEST_TARGET_ARCH ${X86_64})
   get_test_cc_for_arch(x86_64 METADATA_TEST_TARGET_CC METADATA_TEST_TARGET_CFLAGS)
   configure_lit_site_cfg(
@@ -12,6 +17,6 @@ if(CAN_TARGET_x86_64)
 
   add_lit_testsuite(check-sanmd "Running the SanitizerBinaryMetadata tests"
     ${CMAKE_CURRENT_BINARY_DIR}
-    DEPENDS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+    DEPENDS ${METADATA_TEST_DEPS})
   set_target_properties(check-sanmd PROPERTIES FOLDER "Compiler-RT Misc")
 endif()

diff  --git a/compiler-rt/test/metadata/uar.cpp b/compiler-rt/test/metadata/uar.cpp
index f4e643069c3ad..ed7f7dd8abe68 100644
--- a/compiler-rt/test/metadata/uar.cpp
+++ b/compiler-rt/test/metadata/uar.cpp
@@ -1,4 +1,5 @@
 // RUN: %clangxx %s -O1 -o %t -fexperimental-sanitize-metadata=covered,uar && %t | FileCheck %s
+// RUN: %clangxx %s -O1 -o %t -fexperimental-sanitize-metadata=covered,uar -fsanitize=address,signed-integer-overflow && %t | FileCheck %s
 
 // CHECK: metadata add version 1
 
@@ -15,6 +16,16 @@ __attribute__((noinline, not_tail_called)) void use(int x) {
 // CHECK: empty: features=0 stack_args=0
 void empty() {}
 
+// CHECK: simple: features=0 stack_args=0
+int simple(int *data, int index) { return data[index + 1]; }
+
+// CHECK: builtins: features=0 stack_args=0
+int builtins() {
+  int x = 0;
+  __builtin_prefetch(&x);
+  return x;
+}
+
 // CHECK: ellipsis: features=0 stack_args=0
 void ellipsis(const char *fmt, ...) {
   int x;
@@ -60,6 +71,11 @@ __attribute__((noinline)) int tail_called(int x) { return x; }
 // CHECK: with_tail_call: features=2
 int with_tail_call(int x) { [[clang::musttail]] return tail_called(x); }
 
+__attribute__((noinline, noreturn)) int noreturn(int x) { __builtin_trap(); }
+
+// CHECK: with_noreturn_tail_call: features=0
+int with_noreturn_tail_call(int x) { return noreturn(x); }
+
 // CHECK: local_array: features=0
 void local_array(int x) {
   int data[10];
@@ -81,6 +97,8 @@ void escaping_alloca(int size, int i) {
 
 #define FUNCTIONS                                                              \
   FN(empty);                                                                   \
+  FN(simple);                                                                  \
+  FN(builtins);                                                                \
   FN(ellipsis);                                                                \
   FN(non_empty_function);                                                      \
   FN(no_stack_args);                                                           \
@@ -88,6 +106,7 @@ void escaping_alloca(int size, int i) {
   FN(more_stack_args);                                                         \
   FN(struct_stack_args);                                                       \
   FN(with_tail_call);                                                          \
+  FN(with_noreturn_tail_call);                                                 \
   FN(local_array);                                                             \
   FN(local_alloca);                                                            \
   FN(escaping_alloca);                                                         \

diff  --git a/llvm/lib/Transforms/Instrumentation/SanitizerBinaryMetadata.cpp b/llvm/lib/Transforms/Instrumentation/SanitizerBinaryMetadata.cpp
index 0a71df96da839..80eab77dbc568 100644
--- a/llvm/lib/Transforms/Instrumentation/SanitizerBinaryMetadata.cpp
+++ b/llvm/lib/Transforms/Instrumentation/SanitizerBinaryMetadata.cpp
@@ -271,11 +271,31 @@ void SanitizerBinaryMetadata::runOn(Function &F, MetadataInfoSet &MIS) {
   }
 }
 
+bool isUARSafeCall(CallInst *CI) {
+  auto *F = CI->getCalledFunction();
+  // There are no intrinsic functions that leak arguments.
+  // If the called function does not return, the current function
+  // does not return as well, so no possibility of use-after-return.
+  // Sanitizer function also don't leak or don't return.
+  // It's safe to both pass pointers to local variables to them
+  // and to tail-call them.
+  return F && (F->isIntrinsic() || F->doesNotReturn() ||
+               F->getName().startswith("__asan_") ||
+               F->getName().startswith("__hwsan_") ||
+               F->getName().startswith("__ubsan_") ||
+               F->getName().startswith("__msan_") ||
+               F->getName().startswith("__tsan_"));
+}
+
 bool hasUseAfterReturnUnsafeUses(Value &V) {
   for (User *U : V.users()) {
     if (auto *I = dyn_cast<Instruction>(U)) {
       if (I->isLifetimeStartOrEnd() || I->isDroppable())
         continue;
+      if (auto *CI = dyn_cast<CallInst>(U)) {
+        if (isUARSafeCall(CI))
+          continue;
+      }
       if (isa<LoadInst>(U))
         continue;
       if (auto *SI = dyn_cast<StoreInst>(U)) {
@@ -303,7 +323,7 @@ bool useAfterReturnUnsafe(Instruction &I) {
   // at runtime because there is no call instruction.
   // So conservatively mark the caller as requiring checking.
   else if (auto *CI = dyn_cast<CallInst>(&I))
-    return CI->isTailCall();
+    return CI->isTailCall() && !isUARSafeCall(CI);
   return false;
 }
 


        


More information about the llvm-commits mailing list