Author: Andrew Lazarev
Date: 2025-08-06T11:21:49-07:00
New Revision: a1209d868632b8aea10450cd2323848ab0b6776a

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

LOG: [ubsan_minimal] Allow UBSan handler from Minimal runtime to accept 
arguments (#152192)

+ Changed type_mismatch minimal handler to accept and print pointer.
This will allow to distinguish null pointer use, misallignment and
incorrect object size.

The change increases binary size by ~1% and has almost no performance
impact.

Fixes #149943

Added: 
    compiler-rt/test/ubsan_minimal/TestCases/misalignment.cpp
    compiler-rt/test/ubsan_minimal/TestCases/null.cpp

Modified: 
    clang/lib/CodeGen/CGExpr.cpp
    compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 5a3d4e447b229..ed35a055d8a7f 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3789,33 +3789,50 @@ void CodeGenFunction::EmitCheck(
   Branch->setMetadata(llvm::LLVMContext::MD_prof, Node);
   EmitBlock(Handlers);
 
+  // Clear arguments for the MinimalRuntime handler.
+  if (CGM.getCodeGenOpts().SanitizeMinimalRuntime) {
+    switch (CheckHandler) {
+    case SanitizerHandler::TypeMismatch:
+      // Pass value pointer only. It adds minimal overhead.
+      StaticArgs = {};
+      assert(DynamicArgs.size() == 1);
+      break;
+    default:
+      // No arguments for other checks.
+      StaticArgs = {};
+      DynamicArgs = {};
+      break;
+    }
+  }
+
   // Handler functions take an i8* pointing to the (handler-specific) static
   // information block, followed by a sequence of intptr_t arguments
   // representing operand values.
   SmallVector<llvm::Value *, 4> Args;
   SmallVector<llvm::Type *, 4> ArgTypes;
-  if (!CGM.getCodeGenOpts().SanitizeMinimalRuntime) {
-    Args.reserve(DynamicArgs.size() + 1);
-    ArgTypes.reserve(DynamicArgs.size() + 1);
-
-    // Emit handler arguments and create handler function type.
-    if (!StaticArgs.empty()) {
-      llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
-      auto *InfoPtr = new llvm::GlobalVariable(
-          CGM.getModule(), Info->getType(), false,
-          llvm::GlobalVariable::PrivateLinkage, Info, "", nullptr,
-          llvm::GlobalVariable::NotThreadLocal,
-          CGM.getDataLayout().getDefaultGlobalsAddressSpace());
-      InfoPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
-      CGM.getSanitizerMetadata()->disableSanitizerForGlobal(InfoPtr);
-      Args.push_back(InfoPtr);
-      ArgTypes.push_back(Args.back()->getType());
-    }
 
-    for (llvm::Value *DynamicArg : DynamicArgs) {
-      Args.push_back(EmitCheckValue(DynamicArg));
-      ArgTypes.push_back(IntPtrTy);
-    }
+  Args.reserve(DynamicArgs.size() + 1);
+  ArgTypes.reserve(DynamicArgs.size() + 1);
+
+  // Emit handler arguments and create handler function type.
+  if (!StaticArgs.empty()) {
+    llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
+    auto *InfoPtr = new llvm::GlobalVariable(
+        CGM.getModule(), Info->getType(),
+        // Non-constant global is used in a handler to deduplicate reports.
+        // TODO: change deduplication logic and make it constant.
+        /*isConstant=*/false, llvm::GlobalVariable::PrivateLinkage, Info, "",
+        nullptr, llvm::GlobalVariable::NotThreadLocal,
+        CGM.getDataLayout().getDefaultGlobalsAddressSpace());
+    InfoPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
+    CGM.getSanitizerMetadata()->disableSanitizerForGlobal(InfoPtr);
+    Args.push_back(InfoPtr);
+    ArgTypes.push_back(Args.back()->getType());
+  }
+
+  for (llvm::Value *DynamicArg : DynamicArgs) {
+    Args.push_back(EmitCheckValue(DynamicArg));
+    ArgTypes.push_back(IntPtrTy);
   }
 
   llvm::FunctionType *FnType =

diff  --git a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp 
b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp
index ebc36a8583e05..b1f4eab26de0e 100644
--- a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp
+++ b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp
@@ -34,12 +34,16 @@ static char *append_hex(uintptr_t d, char *buf, const char 
*end) {
   return buf;
 }
 
-static void format_msg(const char *kind, uintptr_t caller, char *buf,
-                       const char *end) {
+static void format_msg(const char *kind, uintptr_t caller,
+                       const uintptr_t *address, char *buf, const char *end) {
   buf = append_str("ubsan: ", buf, end);
   buf = append_str(kind, buf, end);
   buf = append_str(" by 0x", buf, end);
   buf = append_hex(caller, buf, end);
+  if (address) {
+    buf = append_str(" address 0x", buf, end);
+    buf = append_hex(*address, buf, end);
+  }
   buf = append_str("\n", buf, end);
   if (buf == end)
     --buf; // Make sure we don't cause a buffer overflow.
@@ -47,7 +51,7 @@ static void format_msg(const char *kind, uintptr_t caller, 
char *buf,
 }
 
 SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, const char *kind,
-                             uintptr_t caller) {
+                             uintptr_t caller, const uintptr_t *address) {
   if (caller == 0)
     return;
   while (true) {
@@ -80,15 +84,15 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, 
const char *kind,
     __sanitizer::atomic_store_relaxed(&caller_pcs[sz], caller);
 
     char msg_buf[128];
-    format_msg(kind, caller, msg_buf, msg_buf + sizeof(msg_buf));
+    format_msg(kind, caller, address, msg_buf, msg_buf + sizeof(msg_buf));
     message(msg_buf);
   }
 }
 
 SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error_fatal, const char 
*kind,
-                             uintptr_t caller) {
+                             uintptr_t caller, const uintptr_t *address) {
   // Use another handlers, in case it's already overriden.
-  __ubsan_report_error(kind, caller);
+  __ubsan_report_error(kind, caller, address);
 }
 
 #if defined(__ANDROID__)
@@ -121,13 +125,13 @@ void NORETURN CheckFailed(const char *file, int, const 
char *cond, u64, u64) {
 
 #define HANDLER_RECOVER(name, kind)                                            
\
   INTERFACE void __ubsan_handle_##name##_minimal() {                           
\
-    __ubsan_report_error(kind, GET_CALLER_PC());                               
\
+    __ubsan_report_error(kind, GET_CALLER_PC(), nullptr);                      
\
   }
 
 #define HANDLER_NORECOVER(name, kind)                                          
\
   INTERFACE void __ubsan_handle_##name##_minimal_abort() {                     
\
     uintptr_t caller = GET_CALLER_PC();                                        
\
-    __ubsan_report_error_fatal(kind, caller);                                  
\
+    __ubsan_report_error_fatal(kind, caller, nullptr);                         
\
     abort_with_message(kind, caller);                                          
\
   }
 
@@ -135,7 +139,25 @@ void NORETURN CheckFailed(const char *file, int, const 
char *cond, u64, u64) {
   HANDLER_RECOVER(name, kind)                                                  
\
   HANDLER_NORECOVER(name, kind)
 
-HANDLER(type_mismatch, "type-mismatch")
+#define HANDLER_RECOVER_PTR(name, kind)                                        
\
+  INTERFACE void __ubsan_handle_##name##_minimal(const uintptr_t address) {    
\
+    __ubsan_report_error(kind, GET_CALLER_PC(), &address);                     
\
+  }
+
+#define HANDLER_NORECOVER_PTR(name, kind)                                      
\
+  INTERFACE void __ubsan_handle_##name##_minimal_abort(                        
\
+      const uintptr_t address) {                                               
\
+    uintptr_t caller = GET_CALLER_PC();                                        
\
+    __ubsan_report_error_fatal(kind, caller, &address);                        
\
+    abort_with_message(kind, caller);                                          
\
+  }
+
+// A version of a handler that takes a pointer to a value.
+#define HANDLER_PTR(name, kind)                                                
\
+  HANDLER_RECOVER_PTR(name, kind)                                              
\
+  HANDLER_NORECOVER_PTR(name, kind)
+
+HANDLER_PTR(type_mismatch, "type-mismatch")
 HANDLER(alignment_assumption, "alignment-assumption")
 HANDLER(add_overflow, "add-overflow")
 HANDLER(sub_overflow, "sub-overflow")

diff  --git a/compiler-rt/test/ubsan_minimal/TestCases/misalignment.cpp 
b/compiler-rt/test/ubsan_minimal/TestCases/misalignment.cpp
new file mode 100644
index 0000000000000..cf828792a324f
--- /dev/null
+++ b/compiler-rt/test/ubsan_minimal/TestCases/misalignment.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_min_runtime -fsanitize=alignment %s -o %t && %run %t 2>&1 | 
FileCheck %s --check-prefixes=CHECK
+
+void f(int &n) {}
+
+int *t;
+
+int main() {
+  int r;
+  t = (int *)(((char *)&r) + 1);
+  // CHECK: ubsan: type-mismatch by 0x{{[[:xdigit:]]+}} address 
0x{{[[:xdigit:]]+$}}
+  // CHECK-NOT: type-mismatch
+  f(*t);
+}

diff  --git a/compiler-rt/test/ubsan_minimal/TestCases/null.cpp 
b/compiler-rt/test/ubsan_minimal/TestCases/null.cpp
new file mode 100644
index 0000000000000..c97527b72cd0c
--- /dev/null
+++ b/compiler-rt/test/ubsan_minimal/TestCases/null.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_min_runtime -fsanitize=null %s -o %t && %run %t 2>&1 | 
FileCheck %s --check-prefixes=CHECK
+
+void f(int &n) {}
+
+int *t;
+
+int main() {
+  // CHECK: ubsan: type-mismatch by 0x{{[[:xdigit:]]+}} address 
0x{{[[:xdigit:]]+$}}
+  // CHECK-NOT: type-mismatch
+  f(*t);
+}


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to