Skip to content

Conversation

@anthonyhatran
Copy link
Contributor

@anthonyhatran anthonyhatran commented Jun 26, 2025

This patch adds a human readable trap category and message to UBSan traps. The category and message are encoded in a fake frame in the debug info where the function is a fake inline function where the name encodes the trap category and message. This is the same mechanism used by Clang’s __builtin_verbose_trap().

This change allows consumers of binaries built with trapping UBSan to more easily identify the reason for trapping. In particular LLDB already has a frame recognizer that recognizes the fake function names emitted in debug info by this patch. A patch testing this behavior in LLDB will be added in a separate patch.

The human readable trap messages are based on the messages currently emitted by the userspace runtime for UBSan in compiler-rt. Note the wording is not identical because the userspace UBSan runtime has access to dynamic information that is not available during Clang’s codegen.

Test cases for each UBSan trap kind are included.

Complements the -fsanitize-annotate-debug-info feature. While -fsanitize-annotate-debug-info attempts to annotate all UBSan-added instructions, this feature (-fsanitize-debug-trap-reasons) only annotates the final trap instruction using SanitizerHandler information.

This work is part of a GSoc 2025 project.

Credit to @delcypher for helping with the description.

@github-actions
Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. labels Jun 26, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 26, 2025

@llvm/pr-subscribers-clang-driver
@llvm/pr-subscribers-debuginfo

@llvm/pr-subscribers-clang

Author: Anthony Tran (anthonyhatran)

Changes

Patch is 25.66 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/145967.diff

26 Files Affected:

  • (modified) clang/lib/CodeGen/CGExpr.cpp (+98-2)
  • (added) clang/test/CodeGen/ubsan-trap-reason-add-overflow.c (+10)
  • (added) clang/test/CodeGen/ubsan-trap-reason-alignment-assumption.c (+14)
  • (added) clang/test/CodeGen/ubsan-trap-reason-builtin-unreachable.c (+11)
  • (added) clang/test/CodeGen/ubsan-trap-reason-cfi-check-fail.c (+27)
  • (added) clang/test/CodeGen/ubsan-trap-reason-div-rem-overflow.c (+10)
  • (added) clang/test/CodeGen/ubsan-trap-reason-dynamic-type-cache-miss.cpp (+23)
  • (added) clang/test/CodeGen/ubsan-trap-reason-float-cast-overflow.c (+10)
  • (added) clang/test/CodeGen/ubsan-trap-reason-function-type-mismatch.c (+16)
  • (added) clang/test/CodeGen/ubsan-trap-reason-implicit-conversion.c (+13)
  • (added) clang/test/CodeGen/ubsan-trap-reason-invalid-builtin.c (+11)
  • (added) clang/test/CodeGen/ubsan-trap-reason-invalid-objc-cast.m (+31)
  • (added) clang/test/CodeGen/ubsan-trap-reason-load-invalid-value.c (+15)
  • (added) clang/test/CodeGen/ubsan-trap-reason-missing-return.cpp (+12)
  • (added) clang/test/CodeGen/ubsan-trap-reason-mul-overflow.c (+10)
  • (added) clang/test/CodeGen/ubsan-trap-reason-negate-overflow.c (+12)
  • (added) clang/test/CodeGen/ubsan-trap-reason-nonnull-arg.c (+16)
  • (added) clang/test/CodeGen/ubsan-trap-reason-nonnull-return.c (+15)
  • (added) clang/test/CodeGen/ubsan-trap-reason-nullability-arg.c (+18)
  • (added) clang/test/CodeGen/ubsan-trap-reason-nullability-return.c (+18)
  • (added) clang/test/CodeGen/ubsan-trap-reason-out-of-bounds.c (+12)
  • (added) clang/test/CodeGen/ubsan-trap-reason-pointer-overflow.c (+16)
  • (added) clang/test/CodeGen/ubsan-trap-reason-shift-out-of-bounds.c (+12)
  • (added) clang/test/CodeGen/ubsan-trap-reason-sub-overflow.c (+10)
  • (added) clang/test/CodeGen/ubsan-trap-reason-type-mismatch.c (+11)
  • (added) clang/test/CodeGen/ubsan-trap-reason-vla-bound-not-positive.c (+14)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 85c768807572f..34fd8b4aef0f2 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -85,6 +85,94 @@ enum VariableTypeDescriptorKind : uint16_t {
 //                        Miscellaneous Helper Methods
 //===--------------------------------------------------------------------===//
 
+static llvm::StringRef GetUBSanTrapForHandler(SanitizerHandler ID) {
+  switch (ID) {
+  case SanitizerHandler::AddOverflow:
+    return "Signed integer addition overflowed";
+
+  case SanitizerHandler::BuiltinUnreachable:
+    return "_builtin_unreachable(), execution reached an unreachable program "
+           "point";
+
+  case SanitizerHandler::CFICheckFail:
+    return "Control flow integrity check failed";
+
+  case SanitizerHandler::DivremOverflow:
+    return "Signed integer divide or remainder overflowed";
+
+  case SanitizerHandler::DynamicTypeCacheMiss:
+    return "Dynamic-type cache miss";
+
+  case SanitizerHandler::FloatCastOverflow:
+    return "Floating-point to integer conversion overflowed";
+
+  case SanitizerHandler::FunctionTypeMismatch:
+    return "Function called with mismatched signature";
+
+  case SanitizerHandler::ImplicitConversion:
+    return "Implicit integer conversion overflowed or lost data";
+
+  case SanitizerHandler::InvalidBuiltin:
+    return "Invalid use of builtin function";
+
+  case SanitizerHandler::InvalidObjCCast:
+    return "Invalid Objective-C cast";
+
+  case SanitizerHandler::LoadInvalidValue:
+    return "Loaded an invalid or uninitialized value for the type";
+
+  case SanitizerHandler::MissingReturn:
+    return "Execution reached the end of a value-returning function without "
+           "returning a value";
+
+  case SanitizerHandler::MulOverflow:
+    return "Signed integer multiplication overflowed";
+
+  case SanitizerHandler::NegateOverflow:
+    return "Signed integer negation overflowed";
+
+  case SanitizerHandler::NullabilityArg:
+    return "Passing null as an argument which is annotated with "
+           "_Nonnull";
+
+  case SanitizerHandler::NullabilityReturn:
+    return "Returning null from a function with a return type annotated with "
+           "_Nonnull";
+
+  case SanitizerHandler::NonnullArg:
+    return "Passing null pointer as an argument which is declared to never be "
+           "null";
+
+  case SanitizerHandler::NonnullReturn:
+    return "Returning null pointer from a function which is declared to never "
+           "return null";
+
+  case SanitizerHandler::OutOfBounds:
+    return "Array index out of bounds";
+
+  case SanitizerHandler::PointerOverflow:
+    return "Pointer arithmetic overflowed bounds";
+
+  case SanitizerHandler::ShiftOutOfBounds:
+    return "Shift exponent is too large for the type";
+
+  case SanitizerHandler::SubOverflow:
+    return "Signed integer subtraction overflowed";
+
+  case SanitizerHandler::TypeMismatch:
+    return "Type mismatch in operation";
+
+  case SanitizerHandler::AlignmentAssumption:
+    return "Alignment assumption violated";
+
+  case SanitizerHandler::VLABoundNotPositive:
+    return "Variable length array bound evaluates to non-positive value";
+
+  case SanitizerHandler::BoundsSafety:
+    return {};
+  }
+}
+
 /// CreateTempAlloca - This creates a alloca and inserts it into the entry
 /// block.
 RawAddress
@@ -4051,6 +4139,14 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
 
   llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID];
 
+  llvm::DILocation *TrapLocation = Builder.getCurrentDebugLocation();
+  llvm::StringRef TrapMessage = GetUBSanTrapForHandler(CheckHandlerID);
+
+  if (getDebugInfo()) {
+    TrapLocation = getDebugInfo()->CreateTrapFailureMessageFor(
+        TrapLocation, "Undefined Behavior Sanitizer", TrapMessage);
+  }
+
   NoMerge = NoMerge || !CGM.getCodeGenOpts().OptimizationLevel ||
             (CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>());
 
@@ -4059,8 +4155,8 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
     auto Call = TrapBB->begin();
     assert(isa<llvm::CallInst>(Call) && "Expected call in trap BB");
 
-    Call->applyMergedLocation(Call->getDebugLoc(),
-                              Builder.getCurrentDebugLocation());
+    Call->applyMergedLocation(Call->getDebugLoc(), TrapLocation);
+
     Builder.CreateCondBr(Checked, Cont, TrapBB,
                          MDHelper.createLikelyBranchWeights());
   } else {
diff --git a/clang/test/CodeGen/ubsan-trap-reason-add-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-add-overflow.c
new file mode 100644
index 0000000000000..4b3881ae9c7dc
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-add-overflow.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -emit-llvm %s -o - | FileCheck %s
+
+int add_overflow(int a, int b) {
+  return a + b;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 0) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
diff --git a/clang/test/CodeGen/ubsan-trap-reason-alignment-assumption.c b/clang/test/CodeGen/ubsan-trap-reason-alignment-assumption.c
new file mode 100644
index 0000000000000..a41a238eaf129
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-alignment-assumption.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - | FileCheck %s
+
+#include <stdint.h>
+int32_t* get_int(void) __attribute__((assume_aligned(16)));
+
+void retrieve_int(void) {
+    int* i = get_int();
+    *i = 7;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 23) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-builtin-unreachable.c b/clang/test/CodeGen/ubsan-trap-reason-builtin-unreachable.c
new file mode 100644
index 0000000000000..a85d92319cb7b
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-builtin-unreachable.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=unreachable -fsanitize-trap=unreachable -emit-llvm %s -o - | FileCheck %s
+
+int call_builtin_unreachable()
+{
+    __builtin_unreachable();
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 1) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-cfi-check-fail.c b/clang/test/CodeGen/ubsan-trap-reason-cfi-check-fail.c
new file mode 100644
index 0000000000000..da6c9bc7fb2f9
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-cfi-check-fail.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -emit-llvm %s -o - | FileCheck %s
+
+typedef int (*fp_t)(int);
+
+int good(int x) {
+    return x + 1;
+}
+
+int bad(void) {
+    return 0;
+}
+
+int cfi_trigger(int a) {
+    fp_t p = good;
+    int r1 = p(a);
+
+    p = (fp_t)(void*)bad;
+    int r2 = p(a);
+
+    return r1 + r2;
+}
+
+
+// CHECK: call void @llvm.ubsantrap(i8 2) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-div-rem-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-div-rem-overflow.c
new file mode 100644
index 0000000000000..f98927399272f
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-div-rem-overflow.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -emit-llvm %s -o - | FileCheck %s
+
+int div_rem_overflow(int a, int b) {
+    return a / b;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 3) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-dynamic-type-cache-miss.cpp b/clang/test/CodeGen/ubsan-trap-reason-dynamic-type-cache-miss.cpp
new file mode 100644
index 0000000000000..e279626f09227
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-dynamic-type-cache-miss.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=vptr -fsanitize-trap=vptr -emit-llvm %s -o - | FileCheck %s
+
+struct A {
+  virtual void foo();
+};
+struct B {
+  virtual void bar();
+};
+
+void A::foo() { }
+void B::bar() { }
+
+int dynamic_type_cache_miss() {
+  B b;
+  A &a = reinterpret_cast<A&>(b);
+  a.foo();
+  return 0;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 4) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
diff --git a/clang/test/CodeGen/ubsan-trap-reason-float-cast-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-float-cast-overflow.c
new file mode 100644
index 0000000000000..0524d8bbf9373
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-float-cast-overflow.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=float-cast-overflow -fsanitize-trap=float-cast-overflow -emit-llvm %s -o - | FileCheck %s
+
+int f(float x) { 
+  return (int)x; 
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 5) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-function-type-mismatch.c b/clang/test/CodeGen/ubsan-trap-reason-function-type-mismatch.c
new file mode 100644
index 0000000000000..8811a064a51c0
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-function-type-mismatch.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=function -fsanitize-trap=function -emit-llvm %s -o - | FileCheck %s
+
+void target() { }
+
+int function_type_mismatch() {
+    int (*fp_int)(int);
+
+    fp_int = (int (*)(int))(void *)target;
+
+    return fp_int(42);
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 6) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-implicit-conversion.c b/clang/test/CodeGen/ubsan-trap-reason-implicit-conversion.c
new file mode 100644
index 0000000000000..6e98aeacb17c9
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-implicit-conversion.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=implicit-unsigned-integer-truncation -fsanitize-trap=implicit-unsigned-integer-truncation -emit-llvm %s -o - | FileCheck %s
+
+unsigned long long big; 
+
+unsigned implicit_conversion()
+{
+    return big;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 7) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-invalid-builtin.c b/clang/test/CodeGen/ubsan-trap-reason-invalid-builtin.c
new file mode 100644
index 0000000000000..4703518e11e6e
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-invalid-builtin.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=builtin -fsanitize-trap=builtin -emit-llvm %s -o - | FileCheck %s
+
+unsigned invalid_builtin(unsigned x)
+{
+    return __builtin_clz(x);
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 8) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-invalid-objc-cast.m b/clang/test/CodeGen/ubsan-trap-reason-invalid-objc-cast.m
new file mode 100644
index 0000000000000..f7460b186b9b3
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-invalid-objc-cast.m
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=objc-cast -fsanitize-trap=objc-cast -emit-llvm %s -o - | FileCheck %s
+
+@interface NSFastEnumerationState
+@end
+
+#define NSUInteger unsigned int
+
+@interface NSArray
++(NSArray*) arrayWithObjects: (id) first, ...;
+- (NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *) state 
+                                   objects:(id[]) buffer 
+                                     count:(NSUInteger) len;
+-(unsigned) count;
+@end
+@interface NSString
+-(const char*) cString;
+@end
+
+void receive_NSString(NSString*);
+
+void t0(void) {
+  NSArray *array = [NSArray arrayWithObjects: @"0", @"1", (void*)0];
+  for (NSString *i in array) {
+    receive_NSString(i);
+  }
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 9) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-load-invalid-value.c b/clang/test/CodeGen/ubsan-trap-reason-load-invalid-value.c
new file mode 100644
index 0000000000000..e751d5135a50e
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-load-invalid-value.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=bool -fsanitize-trap=bool -emit-llvm %s -o - | FileCheck %s
+
+#include <stdbool.h> 
+
+unsigned char bad_byte;
+
+bool load_invalid_value()
+{
+    return *((bool *)&bad_byte);
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 10) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-missing-return.cpp b/clang/test/CodeGen/ubsan-trap-reason-missing-return.cpp
new file mode 100644
index 0000000000000..d97523e503eff
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-missing-return.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=return -fsanitize-trap=return -emit-llvm %s -o - | FileCheck %s
+
+int missing_return(int x)
+{
+    if (x > 0)
+        return x;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 11) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-mul-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-mul-overflow.c
new file mode 100644
index 0000000000000..5250e70e61b43
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-mul-overflow.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -emit-llvm %s -o - | FileCheck %s
+
+int mul_overflow(int a, int b) {
+    return a * b;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 12) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-negate-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-negate-overflow.c
new file mode 100644
index 0000000000000..4273efaced40d
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-negate-overflow.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -emit-llvm %s -o - | FileCheck %s
+
+int negate_overflow()
+{
+    int x;
+    return -x;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 13) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-nonnull-arg.c b/clang/test/CodeGen/ubsan-trap-reason-nonnull-arg.c
new file mode 100644
index 0000000000000..e0849c6b81c32
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-nonnull-arg.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=nonnull-attribute -fsanitize-trap=nonnull-attribute -emit-llvm %s -o - | FileCheck %s
+
+__attribute__((nonnull))
+void nonnull_arg(int *p) { 
+    (void)p; 
+}
+
+void trigger_nonnull_arg()
+{
+    nonnull_arg(0);
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 16) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-nonnull-return.c b/clang/test/CodeGen/ubsan-trap-reason-nonnull-return.c
new file mode 100644
index 0000000000000..b513957775c86
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-nonnull-return.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=returns-nonnull-attribute -fsanitize-trap=returns-nonnull-attribute -emit-llvm %s -o - | FileCheck %s
+
+__attribute__((returns_nonnull))
+int* must_return_nonnull(int bad)
+{
+    if (bad)
+        return 0;
+    static int x = 1;
+    return &x;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 17) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-nullability-arg.c b/clang/test/CodeGen/ubsan-trap-reason-nullability-arg.c
new file mode 100644
index 0000000000000..e8012d05e3741
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-nullability-arg.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=nullability-arg -fsanitize-trap=nullability-arg -emit-llvm %s -o - | FileCheck %s
+
+#include <stddef.h>
+
+int nullability_arg(int* _Nonnull p)
+{
+    return *p;
+}
+
+int trigger_nullability_arg()
+{
+    return nullability_arg(NULL);
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 14) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-nullability-return.c b/clang/test/Code...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Jun 26, 2025

@llvm/pr-subscribers-clang-codegen

Author: Anthony Tran (anthonyhatran)

Changes

Patch is 25.66 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/145967.diff

26 Files Affected:

  • (modified) clang/lib/CodeGen/CGExpr.cpp (+98-2)
  • (added) clang/test/CodeGen/ubsan-trap-reason-add-overflow.c (+10)
  • (added) clang/test/CodeGen/ubsan-trap-reason-alignment-assumption.c (+14)
  • (added) clang/test/CodeGen/ubsan-trap-reason-builtin-unreachable.c (+11)
  • (added) clang/test/CodeGen/ubsan-trap-reason-cfi-check-fail.c (+27)
  • (added) clang/test/CodeGen/ubsan-trap-reason-div-rem-overflow.c (+10)
  • (added) clang/test/CodeGen/ubsan-trap-reason-dynamic-type-cache-miss.cpp (+23)
  • (added) clang/test/CodeGen/ubsan-trap-reason-float-cast-overflow.c (+10)
  • (added) clang/test/CodeGen/ubsan-trap-reason-function-type-mismatch.c (+16)
  • (added) clang/test/CodeGen/ubsan-trap-reason-implicit-conversion.c (+13)
  • (added) clang/test/CodeGen/ubsan-trap-reason-invalid-builtin.c (+11)
  • (added) clang/test/CodeGen/ubsan-trap-reason-invalid-objc-cast.m (+31)
  • (added) clang/test/CodeGen/ubsan-trap-reason-load-invalid-value.c (+15)
  • (added) clang/test/CodeGen/ubsan-trap-reason-missing-return.cpp (+12)
  • (added) clang/test/CodeGen/ubsan-trap-reason-mul-overflow.c (+10)
  • (added) clang/test/CodeGen/ubsan-trap-reason-negate-overflow.c (+12)
  • (added) clang/test/CodeGen/ubsan-trap-reason-nonnull-arg.c (+16)
  • (added) clang/test/CodeGen/ubsan-trap-reason-nonnull-return.c (+15)
  • (added) clang/test/CodeGen/ubsan-trap-reason-nullability-arg.c (+18)
  • (added) clang/test/CodeGen/ubsan-trap-reason-nullability-return.c (+18)
  • (added) clang/test/CodeGen/ubsan-trap-reason-out-of-bounds.c (+12)
  • (added) clang/test/CodeGen/ubsan-trap-reason-pointer-overflow.c (+16)
  • (added) clang/test/CodeGen/ubsan-trap-reason-shift-out-of-bounds.c (+12)
  • (added) clang/test/CodeGen/ubsan-trap-reason-sub-overflow.c (+10)
  • (added) clang/test/CodeGen/ubsan-trap-reason-type-mismatch.c (+11)
  • (added) clang/test/CodeGen/ubsan-trap-reason-vla-bound-not-positive.c (+14)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 85c768807572f..34fd8b4aef0f2 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -85,6 +85,94 @@ enum VariableTypeDescriptorKind : uint16_t {
 //                        Miscellaneous Helper Methods
 //===--------------------------------------------------------------------===//
 
+static llvm::StringRef GetUBSanTrapForHandler(SanitizerHandler ID) {
+  switch (ID) {
+  case SanitizerHandler::AddOverflow:
+    return "Signed integer addition overflowed";
+
+  case SanitizerHandler::BuiltinUnreachable:
+    return "_builtin_unreachable(), execution reached an unreachable program "
+           "point";
+
+  case SanitizerHandler::CFICheckFail:
+    return "Control flow integrity check failed";
+
+  case SanitizerHandler::DivremOverflow:
+    return "Signed integer divide or remainder overflowed";
+
+  case SanitizerHandler::DynamicTypeCacheMiss:
+    return "Dynamic-type cache miss";
+
+  case SanitizerHandler::FloatCastOverflow:
+    return "Floating-point to integer conversion overflowed";
+
+  case SanitizerHandler::FunctionTypeMismatch:
+    return "Function called with mismatched signature";
+
+  case SanitizerHandler::ImplicitConversion:
+    return "Implicit integer conversion overflowed or lost data";
+
+  case SanitizerHandler::InvalidBuiltin:
+    return "Invalid use of builtin function";
+
+  case SanitizerHandler::InvalidObjCCast:
+    return "Invalid Objective-C cast";
+
+  case SanitizerHandler::LoadInvalidValue:
+    return "Loaded an invalid or uninitialized value for the type";
+
+  case SanitizerHandler::MissingReturn:
+    return "Execution reached the end of a value-returning function without "
+           "returning a value";
+
+  case SanitizerHandler::MulOverflow:
+    return "Signed integer multiplication overflowed";
+
+  case SanitizerHandler::NegateOverflow:
+    return "Signed integer negation overflowed";
+
+  case SanitizerHandler::NullabilityArg:
+    return "Passing null as an argument which is annotated with "
+           "_Nonnull";
+
+  case SanitizerHandler::NullabilityReturn:
+    return "Returning null from a function with a return type annotated with "
+           "_Nonnull";
+
+  case SanitizerHandler::NonnullArg:
+    return "Passing null pointer as an argument which is declared to never be "
+           "null";
+
+  case SanitizerHandler::NonnullReturn:
+    return "Returning null pointer from a function which is declared to never "
+           "return null";
+
+  case SanitizerHandler::OutOfBounds:
+    return "Array index out of bounds";
+
+  case SanitizerHandler::PointerOverflow:
+    return "Pointer arithmetic overflowed bounds";
+
+  case SanitizerHandler::ShiftOutOfBounds:
+    return "Shift exponent is too large for the type";
+
+  case SanitizerHandler::SubOverflow:
+    return "Signed integer subtraction overflowed";
+
+  case SanitizerHandler::TypeMismatch:
+    return "Type mismatch in operation";
+
+  case SanitizerHandler::AlignmentAssumption:
+    return "Alignment assumption violated";
+
+  case SanitizerHandler::VLABoundNotPositive:
+    return "Variable length array bound evaluates to non-positive value";
+
+  case SanitizerHandler::BoundsSafety:
+    return {};
+  }
+}
+
 /// CreateTempAlloca - This creates a alloca and inserts it into the entry
 /// block.
 RawAddress
@@ -4051,6 +4139,14 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
 
   llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID];
 
+  llvm::DILocation *TrapLocation = Builder.getCurrentDebugLocation();
+  llvm::StringRef TrapMessage = GetUBSanTrapForHandler(CheckHandlerID);
+
+  if (getDebugInfo()) {
+    TrapLocation = getDebugInfo()->CreateTrapFailureMessageFor(
+        TrapLocation, "Undefined Behavior Sanitizer", TrapMessage);
+  }
+
   NoMerge = NoMerge || !CGM.getCodeGenOpts().OptimizationLevel ||
             (CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>());
 
@@ -4059,8 +4155,8 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
     auto Call = TrapBB->begin();
     assert(isa<llvm::CallInst>(Call) && "Expected call in trap BB");
 
-    Call->applyMergedLocation(Call->getDebugLoc(),
-                              Builder.getCurrentDebugLocation());
+    Call->applyMergedLocation(Call->getDebugLoc(), TrapLocation);
+
     Builder.CreateCondBr(Checked, Cont, TrapBB,
                          MDHelper.createLikelyBranchWeights());
   } else {
diff --git a/clang/test/CodeGen/ubsan-trap-reason-add-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-add-overflow.c
new file mode 100644
index 0000000000000..4b3881ae9c7dc
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-add-overflow.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -emit-llvm %s -o - | FileCheck %s
+
+int add_overflow(int a, int b) {
+  return a + b;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 0) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
diff --git a/clang/test/CodeGen/ubsan-trap-reason-alignment-assumption.c b/clang/test/CodeGen/ubsan-trap-reason-alignment-assumption.c
new file mode 100644
index 0000000000000..a41a238eaf129
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-alignment-assumption.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - | FileCheck %s
+
+#include <stdint.h>
+int32_t* get_int(void) __attribute__((assume_aligned(16)));
+
+void retrieve_int(void) {
+    int* i = get_int();
+    *i = 7;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 23) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-builtin-unreachable.c b/clang/test/CodeGen/ubsan-trap-reason-builtin-unreachable.c
new file mode 100644
index 0000000000000..a85d92319cb7b
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-builtin-unreachable.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=unreachable -fsanitize-trap=unreachable -emit-llvm %s -o - | FileCheck %s
+
+int call_builtin_unreachable()
+{
+    __builtin_unreachable();
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 1) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-cfi-check-fail.c b/clang/test/CodeGen/ubsan-trap-reason-cfi-check-fail.c
new file mode 100644
index 0000000000000..da6c9bc7fb2f9
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-cfi-check-fail.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -emit-llvm %s -o - | FileCheck %s
+
+typedef int (*fp_t)(int);
+
+int good(int x) {
+    return x + 1;
+}
+
+int bad(void) {
+    return 0;
+}
+
+int cfi_trigger(int a) {
+    fp_t p = good;
+    int r1 = p(a);
+
+    p = (fp_t)(void*)bad;
+    int r2 = p(a);
+
+    return r1 + r2;
+}
+
+
+// CHECK: call void @llvm.ubsantrap(i8 2) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-div-rem-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-div-rem-overflow.c
new file mode 100644
index 0000000000000..f98927399272f
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-div-rem-overflow.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -emit-llvm %s -o - | FileCheck %s
+
+int div_rem_overflow(int a, int b) {
+    return a / b;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 3) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-dynamic-type-cache-miss.cpp b/clang/test/CodeGen/ubsan-trap-reason-dynamic-type-cache-miss.cpp
new file mode 100644
index 0000000000000..e279626f09227
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-dynamic-type-cache-miss.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=vptr -fsanitize-trap=vptr -emit-llvm %s -o - | FileCheck %s
+
+struct A {
+  virtual void foo();
+};
+struct B {
+  virtual void bar();
+};
+
+void A::foo() { }
+void B::bar() { }
+
+int dynamic_type_cache_miss() {
+  B b;
+  A &a = reinterpret_cast<A&>(b);
+  a.foo();
+  return 0;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 4) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
diff --git a/clang/test/CodeGen/ubsan-trap-reason-float-cast-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-float-cast-overflow.c
new file mode 100644
index 0000000000000..0524d8bbf9373
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-float-cast-overflow.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=float-cast-overflow -fsanitize-trap=float-cast-overflow -emit-llvm %s -o - | FileCheck %s
+
+int f(float x) { 
+  return (int)x; 
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 5) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-function-type-mismatch.c b/clang/test/CodeGen/ubsan-trap-reason-function-type-mismatch.c
new file mode 100644
index 0000000000000..8811a064a51c0
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-function-type-mismatch.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=function -fsanitize-trap=function -emit-llvm %s -o - | FileCheck %s
+
+void target() { }
+
+int function_type_mismatch() {
+    int (*fp_int)(int);
+
+    fp_int = (int (*)(int))(void *)target;
+
+    return fp_int(42);
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 6) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-implicit-conversion.c b/clang/test/CodeGen/ubsan-trap-reason-implicit-conversion.c
new file mode 100644
index 0000000000000..6e98aeacb17c9
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-implicit-conversion.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=implicit-unsigned-integer-truncation -fsanitize-trap=implicit-unsigned-integer-truncation -emit-llvm %s -o - | FileCheck %s
+
+unsigned long long big; 
+
+unsigned implicit_conversion()
+{
+    return big;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 7) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-invalid-builtin.c b/clang/test/CodeGen/ubsan-trap-reason-invalid-builtin.c
new file mode 100644
index 0000000000000..4703518e11e6e
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-invalid-builtin.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=builtin -fsanitize-trap=builtin -emit-llvm %s -o - | FileCheck %s
+
+unsigned invalid_builtin(unsigned x)
+{
+    return __builtin_clz(x);
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 8) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-invalid-objc-cast.m b/clang/test/CodeGen/ubsan-trap-reason-invalid-objc-cast.m
new file mode 100644
index 0000000000000..f7460b186b9b3
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-invalid-objc-cast.m
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=objc-cast -fsanitize-trap=objc-cast -emit-llvm %s -o - | FileCheck %s
+
+@interface NSFastEnumerationState
+@end
+
+#define NSUInteger unsigned int
+
+@interface NSArray
++(NSArray*) arrayWithObjects: (id) first, ...;
+- (NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *) state 
+                                   objects:(id[]) buffer 
+                                     count:(NSUInteger) len;
+-(unsigned) count;
+@end
+@interface NSString
+-(const char*) cString;
+@end
+
+void receive_NSString(NSString*);
+
+void t0(void) {
+  NSArray *array = [NSArray arrayWithObjects: @"0", @"1", (void*)0];
+  for (NSString *i in array) {
+    receive_NSString(i);
+  }
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 9) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-load-invalid-value.c b/clang/test/CodeGen/ubsan-trap-reason-load-invalid-value.c
new file mode 100644
index 0000000000000..e751d5135a50e
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-load-invalid-value.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=bool -fsanitize-trap=bool -emit-llvm %s -o - | FileCheck %s
+
+#include <stdbool.h> 
+
+unsigned char bad_byte;
+
+bool load_invalid_value()
+{
+    return *((bool *)&bad_byte);
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 10) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-missing-return.cpp b/clang/test/CodeGen/ubsan-trap-reason-missing-return.cpp
new file mode 100644
index 0000000000000..d97523e503eff
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-missing-return.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=return -fsanitize-trap=return -emit-llvm %s -o - | FileCheck %s
+
+int missing_return(int x)
+{
+    if (x > 0)
+        return x;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 11) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-mul-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-mul-overflow.c
new file mode 100644
index 0000000000000..5250e70e61b43
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-mul-overflow.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -emit-llvm %s -o - | FileCheck %s
+
+int mul_overflow(int a, int b) {
+    return a * b;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 12) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-negate-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-negate-overflow.c
new file mode 100644
index 0000000000000..4273efaced40d
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-negate-overflow.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -emit-llvm %s -o - | FileCheck %s
+
+int negate_overflow()
+{
+    int x;
+    return -x;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 13) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-nonnull-arg.c b/clang/test/CodeGen/ubsan-trap-reason-nonnull-arg.c
new file mode 100644
index 0000000000000..e0849c6b81c32
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-nonnull-arg.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=nonnull-attribute -fsanitize-trap=nonnull-attribute -emit-llvm %s -o - | FileCheck %s
+
+__attribute__((nonnull))
+void nonnull_arg(int *p) { 
+    (void)p; 
+}
+
+void trigger_nonnull_arg()
+{
+    nonnull_arg(0);
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 16) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-nonnull-return.c b/clang/test/CodeGen/ubsan-trap-reason-nonnull-return.c
new file mode 100644
index 0000000000000..b513957775c86
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-nonnull-return.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=returns-nonnull-attribute -fsanitize-trap=returns-nonnull-attribute -emit-llvm %s -o - | FileCheck %s
+
+__attribute__((returns_nonnull))
+int* must_return_nonnull(int bad)
+{
+    if (bad)
+        return 0;
+    static int x = 1;
+    return &x;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 17) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-nullability-arg.c b/clang/test/CodeGen/ubsan-trap-reason-nullability-arg.c
new file mode 100644
index 0000000000000..e8012d05e3741
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-nullability-arg.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \
+// RUN: -fsanitize=nullability-arg -fsanitize-trap=nullability-arg -emit-llvm %s -o - | FileCheck %s
+
+#include <stddef.h>
+
+int nullability_arg(int* _Nonnull p)
+{
+    return *p;
+}
+
+int trigger_nullability_arg()
+{
+    return nullability_arg(NULL);
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 14) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-nullability-return.c b/clang/test/Code...
[truncated]

@anthonyhatran anthonyhatran changed the title Gsoc ubsan trap reason v2 [Clang] [CodeGen] UBSan Trap Reasons Jun 26, 2025
@anthonyhatran
Copy link
Contributor Author

Anyways, to address Dan's comments, I changed all test cases so that they utilize clang_cc1 instead of clang. This also meant that I had to change any -fsanitize=undefined and -fsanitize-trap=undefined to the specific check since undefined is a check grouping and is not recognized by front-end. I also adjusted the strings in the switch function to more closely match what was emitted when the test cases were run without -fsanitize-trap=, removed the unnecessary bug fix for unreachable, and added all test cases in for each SanitizerHandler, aside from SanitizerHandler::BoundsSafety.

@delcypher delcypher self-requested a review June 26, 2025 21:45
Copy link
Member

@Michael137 Michael137 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (modulo the question about one of the message strings)

I'll let @delcypher comment on whether all his concerns have been addressed

Copy link
Contributor

@delcypher delcypher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we need to fix a few more things. Did you resolve the issue with the existing test cases failing?

@anthonyhatran
Copy link
Contributor Author

anthonyhatran commented Jul 1, 2025

Looks like we need to fix a few more things. Did you resolve the issue with the existing test cases failing?

Apologies for the belated reply on this one; I ran the test suite overnight just to double-check that the test cases I listed were actually caused by my changes.

To answer your question,: yes, I have proposed solutions for most of them. Unfortunately I don't think there is just one adjustment that fixes all of them though (some include modifying the test cases themselves, others involve changing what I added). I'll try to get the commit in as soon as possible so you can take a look.

@anthonyhatran anthonyhatran force-pushed the gsoc-ubsan-trap-reason-v2 branch from 5a25319 to 338505e Compare July 4, 2025 05:49
@anthonyhatran
Copy link
Contributor Author

anthonyhatran commented Jul 4, 2025

Commit 3 (338505e) Update:
Apologies for taking a bit on the commit, took a while to fix test cases. I'll list how the 5 test cases were fixed below:

  1. {clang/test/CodeGen/ubsan-trap-debugloc.c}: Hand written, so I adjusted the unmerged trap checks to expect a synthetic line: 0 trap-message location.
  2. {clang/test/CodeGen/bounds-checking-debuginfo.c, clang/test/CodeGen/cfi-icall-generalize-debuginfo.c, clang/test/CodeGen/cfi-icall-normalize2-debuginfo.c}: Noticed that these were auto generated to match emitted IR. Since our feature made changes to emitted IR (at least when -fsanitize-trap= is enabled), I just reran utils/update_cc_test_checks.py to regenerate them.
  3. {clang/test/CodeGen/cfi-check-fail-debuginfo.c}: This tried to wrap an already-synthetic location a second time causing a crash, so I added a guard in EmitTrapCheck: if the current DILocation is synthetic, we skip rewrapping it.

As for other changes, I re-added the TrapMessage is empty check, reworded SanitizerHandler::DynamicTypeCacheMiss's string and updated the test cases to reflect the actual strings. Also added a comment for BoundsSafety

Copy link
Contributor

@delcypher delcypher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is pretty much at the point where we can start having other reviewers take a look at this. Let's address the minor comments, reword the PR description to describe what's implemented and then we can add other reviewers.

@anthonyhatran anthonyhatran force-pushed the gsoc-ubsan-trap-reason-v2 branch from 338505e to b41f9e7 Compare July 8, 2025 22:37
@anthonyhatran anthonyhatran changed the title [Clang] [CodeGen] UBSan Trap Reasons [Clang][CodeGen] Emit “trap reasons” on UBSan traps Jul 8, 2025
@anthonyhatran
Copy link
Contributor Author

anthonyhatran commented Jul 8, 2025

Crash report from clang/test/CodeGen/cfi-check-fail-debuginfo.c:

PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.    Program arguments: clang -cc1 -internal-isystem /usr/local/lib/clang/21/include -nostdsysteminc -triple x86_64-unknown-linux -O2 -fsanitize-cfi-cross-dso -fsanitize=cfi-icall,cfi-nvcall,cfi-vcall,cfi-unrelated-cast,cfi-derived-cast -fsanitize-trap=cfi-icall,cfi-nvcall -fsanitize-recover=cfi-vcall,cfi-unrelated-cast -fsanitize-annotate-debug-info=cfi-icall,cfi-nvcall,cfi-vcall,cfi-unrelated-cast,cfi-derived-cast -fdebug-prefix-map=clang/test/CodeGen/= -fno-ident -fdebug-compilation-dir=clang/test/CodeGen -debug-info-kind=limited -emit-llvm -o - clang/test/CodeGen/cfi-check-fail-debuginfo.c
1.    <eof> parser at end of file
2.    Per-file LLVM IR generation
 #0 0x0000000105c88648 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/usr/local/bin/clang-21+0x10550c648)
 #1 0x0000000105c88c28 PrintStackTraceSignalHandler(void*) (/usr/local/bin/clang-21+0x10550cc28)
 #2 0x0000000105c86950 llvm::sys::RunSignalHandlers() (/usr/local/bin/clang-21+0x10550a950)
 #3 0x0000000105c89570 SignalHandler(int, __siginfo*, void*) (/usr/local/bin/clang-21+0x10550d570)
 #4 0x0000000190dfe584 (/usr/lib/system/libsystem_platform.dylib+0x18047a584)
 #5 0x00000001009eb0cc llvm::MDNode::getNumOperands() const (/usr/local/bin/clang-21+0x10026f0cc)
 #6 0x00000001009eb0cc llvm::MDNode::getNumOperands() const (/usr/local/bin/clang-21+0x10026f0cc)
 #7 0x00000001009eac10 llvm::MDNode::getOperand(unsigned int) const (/usr/local/bin/clang-21+0x10026ec10)
 #8 0x0000000101ee1aec llvm::DILocation::getRawScope() const (/usr/local/bin/clang-21+0x101765aec)
 #9 0x0000000101ee1a44 llvm::DILocation::getScope() const (/usr/local/bin/clang-21+0x101765a44)
#10 0x0000000101eddecc llvm::DILocation::getFile() const (/usr/local/bin/clang-21+0x101761ecc)
#11 0x000000010673a8c4 clang::CodeGen::CGDebugInfo::CreateSyntheticInlineAt(llvm::DebugLoc, llvm::StringRef) (/usr/local/bin/clang-21+0x105fbe8c4)
# 12 0x000000010673aa44 clang::CodeGen::CGDebugInfo::CreateTrapFailureMessageFor(llvm::DebugLoc, llvm::StringRef, llvm::StringRef) (/usr/local/bin/clang-21+0x105fbea44)
#13 0x0000000106974838 clang::CodeGen::CodeGenFunction::EmitTrapCheck(llvm::Value*, clang::CodeGen::SanitizerHandler, bool, llvm::StringRef, llvm::StringRef) (/usr/local/bin/clang-21+0x1061f8838)
#14 0x0000000106975f7c clang::CodeGen::CodeGenFunction::EmitCfiCheckFail() (/usr/local/bin/clang-21+0x1061f9f7c)
#15 0x0000000106d7c138 clang::CodeGen::CodeGenModule::Release() (/usr/local/bin/clang-21+0x106600138)
#16 0x0000000106fabea8 (anonymous namespace)::CodeGeneratorImpl::HandleTranslationUnit(clang::ASTContext&) (/usr/local/bin/clang-21+0x10682fea8)
#17 0x0000000106d412e4 clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/usr/local/bin/clang-21+0x1065c52e4)
#18 0x00000001094ea118 clang::ParseAST(clang::Sema&, bool, bool) (/usr/local/bin/clang-21+0x108d6e118)
#19 0x00000001078c808c clang::ASTFrontendAction::ExecuteAction() (/usr/local/bin/clang-21+0x10714c08c)
#20 0x0000000106d47344 clang::CodeGenAction::ExecuteAction() (/usr/local/bin/clang-21+0x1065cb344)
#21 0x00000001078c78fc clang::FrontendAction::Execute() (/usr/local/bin/clang-21+0x10714b8fc)
#22 0x00000001077df330 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/usr/local/bin/clang-21+0x107063330)
# 23 0x0000000107a0a724 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/usr/local/bin/clang-21+0x10728e724)
#24 0x000000010078e178 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/usr/local/bin/clang-21+0x100012178)
#25 0x000000010077f93c ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) (/usr/local/bin/clang-21+0x10000393c)
#26 0x000000010077e5e4 clang_main(int, char**, llvm::ToolContext const&) (/usr/local/bin/clang-21+0x1000025e4)
#27 0x00000001007bacb8 main (/usr/local/bin/clang-21+0x10003ecb8)
#28 0x0000000190a43154 
Error: Failed to update test clang/test/CodeGen/cfi-check-fail-debuginfo.c

@Michael137
Copy link
Member

Crash report from clang/test/CodeGen/cfi-check-fail-debuginfo.c:

PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.    Program arguments: clang -cc1 -internal-isystem /usr/local/lib/clang/21/include -nostdsysteminc -triple x86_64-unknown-linux -O2 -fsanitize-cfi-cross-dso -fsanitize=cfi-icall,cfi-nvcall,cfi-vcall,cfi-unrelated-cast,cfi-derived-cast -fsanitize-trap=cfi-icall,cfi-nvcall -fsanitize-recover=cfi-vcall,cfi-unrelated-cast -fsanitize-annotate-debug-info=cfi-icall,cfi-nvcall,cfi-vcall,cfi-unrelated-cast,cfi-derived-cast -fdebug-prefix-map=clang/test/CodeGen/= -fno-ident -fdebug-compilation-dir=clang/test/CodeGen -debug-info-kind=limited -emit-llvm -o - clang/test/CodeGen/cfi-check-fail-debuginfo.c
1.    <eof> parser at end of file
2.    Per-file LLVM IR generation
 #0 0x0000000105c88648 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/usr/local/bin/clang-21+0x10550c648)
 #1 0x0000000105c88c28 PrintStackTraceSignalHandler(void*) (/usr/local/bin/clang-21+0x10550cc28)
 #2 0x0000000105c86950 llvm::sys::RunSignalHandlers() (/usr/local/bin/clang-21+0x10550a950)
 #3 0x0000000105c89570 SignalHandler(int, __siginfo*, void*) (/usr/local/bin/clang-21+0x10550d570)
 #4 0x0000000190dfe584 (/usr/lib/system/libsystem_platform.dylib+0x18047a584)
 #5 0x00000001009eb0cc llvm::MDNode::getNumOperands() const (/usr/local/bin/clang-21+0x10026f0cc)
 #6 0x00000001009eb0cc llvm::MDNode::getNumOperands() const (/usr/local/bin/clang-21+0x10026f0cc)
 #7 0x00000001009eac10 llvm::MDNode::getOperand(unsigned int) const (/usr/local/bin/clang-21+0x10026ec10)
 #8 0x0000000101ee1aec llvm::DILocation::getRawScope() const (/usr/local/bin/clang-21+0x101765aec)
 #9 0x0000000101ee1a44 llvm::DILocation::getScope() const (/usr/local/bin/clang-21+0x101765a44)
#10 0x0000000101eddecc llvm::DILocation::getFile() const (/usr/local/bin/clang-21+0x101761ecc)
#11 0x000000010673a8c4 clang::CodeGen::CGDebugInfo::CreateSyntheticInlineAt(llvm::DebugLoc, llvm::StringRef) (/usr/local/bin/clang-21+0x105fbe8c4)
# 12 0x000000010673aa44 clang::CodeGen::CGDebugInfo::CreateTrapFailureMessageFor(llvm::DebugLoc, llvm::StringRef, llvm::StringRef) (/usr/local/bin/clang-21+0x105fbea44)
#13 0x0000000106974838 clang::CodeGen::CodeGenFunction::EmitTrapCheck(llvm::Value*, clang::CodeGen::SanitizerHandler, bool, llvm::StringRef, llvm::StringRef) (/usr/local/bin/clang-21+0x1061f8838)
#14 0x0000000106975f7c clang::CodeGen::CodeGenFunction::EmitCfiCheckFail() (/usr/local/bin/clang-21+0x1061f9f7c)
#15 0x0000000106d7c138 clang::CodeGen::CodeGenModule::Release() (/usr/local/bin/clang-21+0x106600138)
#16 0x0000000106fabea8 (anonymous namespace)::CodeGeneratorImpl::HandleTranslationUnit(clang::ASTContext&) (/usr/local/bin/clang-21+0x10682fea8)
#17 0x0000000106d412e4 clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/usr/local/bin/clang-21+0x1065c52e4)
#18 0x00000001094ea118 clang::ParseAST(clang::Sema&, bool, bool) (/usr/local/bin/clang-21+0x108d6e118)
#19 0x00000001078c808c clang::ASTFrontendAction::ExecuteAction() (/usr/local/bin/clang-21+0x10714c08c)
#20 0x0000000106d47344 clang::CodeGenAction::ExecuteAction() (/usr/local/bin/clang-21+0x1065cb344)
#21 0x00000001078c78fc clang::FrontendAction::Execute() (/usr/local/bin/clang-21+0x10714b8fc)
#22 0x00000001077df330 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/usr/local/bin/clang-21+0x107063330)
# 23 0x0000000107a0a724 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/usr/local/bin/clang-21+0x10728e724)
#24 0x000000010078e178 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/usr/local/bin/clang-21+0x100012178)
#25 0x000000010077f93c ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) (/usr/local/bin/clang-21+0x10000393c)
#26 0x000000010077e5e4 clang_main(int, char**, llvm::ToolContext const&) (/usr/local/bin/clang-21+0x1000025e4)
#27 0x00000001007bacb8 main (/usr/local/bin/clang-21+0x10003ecb8)
#28 0x0000000190a43154 
Error: Failed to update test clang/test/CodeGen/cfi-check-fail-debuginfo.c

In the debugger this is what i'm seeing:

(lldb) 
frame #6: 0x000000010114d614 clang`clang::CodeGen::CGDebugInfo::CreateSyntheticInlineAt(this=0x0000000a8ed10000, Location=DebugLoc @ 0x000000016fdf0a38, FuncName="__clang_trap_msg$Undefined Behavior Sanitizer$Control flow integrity check failed") at CGDebugInfo.cpp:3790:51
   3787 llvm::DILocation *CGDebugInfo::CreateSyntheticInlineAt(llvm::DebugLoc Location,
   3788                                                        StringRef FuncName) {
   3789   llvm::DISubprogram *SP =
-> 3790       createInlinedSubprogram(FuncName, Location->getFile());
   3791   return llvm::DILocation::get(CGM.getLLVMContext(), /*Line=*/0, /*Column=*/0,
   3792                                /*Scope=*/SP, /*InlinedAt=*/Location);
   3793 }
(lldb) v Location
(llvm::DebugLoc) Location = {
  Loc = {
    Ref = {
      MD = nullptr
    }
  }
}

So looks like Builder.getCurrentDebugLocation() returned a nullptr. Though I'm not sure we want a nullptr check here. Could be that we're not updating the current debug-info location correctly.

@Michael137
Copy link
Member

Yea I think what we need is to just set the current DebugLocation. We usually do this using ApplyDebugLocation::CreateArtificial so that the artificial function we're generating has some artificial debug-location.

When I do this in EmitCfiCheckFail the crash disappears and we generate reasonable looking debug-info:

0x00000061:   DW_TAG_subprogram
                DW_AT_name      ("__clang_trap_msg$Undefined Behavior Sanitizer$Control flow integrity check failed")
                DW_AT_artificial        (true)
                DW_AT_external  (true)
                DW_AT_inline    (DW_INL_inlined)

0x00000067:   DW_TAG_subprogram
                DW_AT_low_pc    (0x0000000000000000)
                DW_AT_high_pc   (0x0000000000000043)
                DW_AT_frame_base        (DW_OP_reg7 RSP)
                DW_AT_linkage_name      ("__cfi_check_fail")
                DW_AT_artificial        (true)
                DW_AT_external  (true)

0x0000007a:     DW_TAG_formal_parameter
                  DW_AT_location        (DW_OP_reg5 RDI)
                  DW_AT_type    (0x0000009a "void *")
                  DW_AT_artificial      (true)

0x00000081:     DW_TAG_formal_parameter
                  DW_AT_location        (DW_OP_reg4 RSI)
                  DW_AT_type    (0x0000009a "void *")
                  DW_AT_artificial      (true)

0x00000088:     DW_TAG_inlined_subroutine
                  DW_AT_abstract_origin (0x00000061 "__clang_trap_msg$Undefined Behavior Sanitizer$Control flow integrity check failed")
                  DW_AT_ranges  (0x00000030
                     [0x0000000000000029, 0x0000000000000033)
                     [0x000000000000003e, 0x0000000000000043))
                  DW_AT_call_file       ("clang/test/CodeGen/<stdin>")
                  DW_AT_call_line       (0)

0x00000093:     NULL

I.e., the artificial ubsan trap frame is inlined into __cfi_check_fail. We should probably follow-up on how this looks in LLDB. But off the top I think this should Just Work.

@delcypher
Copy link
Contributor

@anthonyhatran Oh and don't forget about #145967 (comment) as well.

@anthonyhatran anthonyhatran force-pushed the gsoc-ubsan-trap-reason-v2 branch from 86489ec to 50e28ef Compare July 25, 2025 23:46
@llvmbot llvmbot added clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" debuginfo labels Jul 25, 2025
@anthonyhatran anthonyhatran force-pushed the gsoc-ubsan-trap-reason-v2 branch from 50e28ef to 07773d5 Compare July 26, 2025 07:03
@delcypher delcypher merged commit 29992cf into llvm:main Jul 26, 2025
10 checks passed
@github-actions
Copy link

@anthonyhatran Congratulations on having your first Pull Request (PR) merged into the LLVM Project!

Your changes will be combined with recent changes from other authors, then tested by our build bots. If there is a problem with a build, you may receive a report in an email or a comment on this PR.

Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues.

How to do this, and the rest of the post-merge process, is covered in detail here.

If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of LLVM development. You can fix your changes and open a new PR to merge them again.

If you don't get any reports, no action is required from you. Your changes are working as expected, well done!

@llvm-ci
Copy link
Collaborator

llvm-ci commented Jul 26, 2025

LLVM Buildbot has detected a new failure on builder fuchsia-x86_64-linux running on fuchsia-debian-64-us-central1-a-1 while building clang at step 4 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/11/builds/20443

Here is the relevant piece of the build log for the reference
Step 4 (annotate) failure: 'python ../llvm-zorg/zorg/buildbot/builders/annotated/fuchsia-linux.py ...' (failure)
...
[475/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_has_single_bit_us.dir/stdc_has_single_bit_us.cpp.obj
[476/2522] Building CXX object libc/src/complex/generic/CMakeFiles/libc.src.complex.generic.conjf.dir/conjf.cpp.obj
[477/2522] Building CXX object libc/src/complex/generic/CMakeFiles/libc.src.complex.generic.conjl.dir/conjl.cpp.obj
[478/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_has_single_bit_uc.dir/stdc_has_single_bit_uc.cpp.obj
[479/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_trailing_zeros_ull.dir/stdc_trailing_zeros_ull.cpp.obj
[480/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_has_single_bit_ui.dir/stdc_has_single_bit_ui.cpp.obj
[481/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_has_single_bit_ul.dir/stdc_has_single_bit_ul.cpp.obj
[482/2522] Building CXX object libc/src/complex/generic/CMakeFiles/libc.src.complex.generic.cprojf.dir/cprojf.cpp.obj
[483/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_width_us.dir/stdc_bit_width_us.cpp.obj
[484/2522] Building CXX object libc/src/stdio/CMakeFiles/libc.src.stdio.vsscanf.dir/vsscanf.cpp.obj
FAILED: libc/src/stdio/CMakeFiles/libc.src.stdio.vsscanf.dir/vsscanf.cpp.obj 
/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-onr0xued/./bin/clang++ --target=armv7m-none-eabi -DLIBC_NAMESPACE=__llvm_libc_22_0_0_git -I/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc -isystem /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-onr0xued/include/armv7m-unknown-none-eabi --target=armv7m-none-eabi -Wno-atomic-alignment "-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)" "-Dfprintf(stream, format, ...)=printf(format)" "-Dfputs(string, stream)=puts(string)" -D_LIBCPP_PRINT=1 -mthumb -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -ffunction-sections -fdata-sections -ffile-prefix-map=/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-onr0xued/runtimes/runtimes-armv7m-none-eabi-bins=../../../../llvm-project -ffile-prefix-map=/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/= -no-canonical-prefixes -Os -DNDEBUG --target=armv7m-none-eabi -DLIBC_QSORT_IMPL=LIBC_QSORT_HEAP_SORT -DLIBC_TYPES_TIME_T_IS_32_BIT -DLIBC_ADD_NULL_CHECKS "-DLIBC_MATH=(LIBC_MATH_SKIP_ACCURATE_PASS | LIBC_MATH_SMALL_TABLES)" -DLIBC_ERRNO_MODE=LIBC_ERRNO_MODE_EXTERNAL -fpie -ffreestanding -DLIBC_FULL_BUILD -nostdlibinc -ffixed-point -fno-builtin -fno-exceptions -fno-lax-vector-conversions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -ftrivial-auto-var-init=pattern -fno-omit-frame-pointer -Wall -Wextra -Werror -Wconversion -Wno-sign-conversion -Wdeprecated -Wno-c99-extensions -Wno-gnu-imaginary-constant -Wno-pedantic -Wimplicit-fallthrough -Wwrite-strings -Wextra-semi -Wnewline-eof -Wnonportable-system-include-path -Wstrict-prototypes -Wthread-safety -Wglobal-constructors -DLIBC_COPT_PUBLIC_PACKAGING -MD -MT libc/src/stdio/CMakeFiles/libc.src.stdio.vsscanf.dir/vsscanf.cpp.obj -MF libc/src/stdio/CMakeFiles/libc.src.stdio.vsscanf.dir/vsscanf.cpp.obj.d -o libc/src/stdio/CMakeFiles/libc.src.stdio.vsscanf.dir/vsscanf.cpp.obj -c /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdio/vsscanf.cpp
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdio/vsscanf.cpp:14:
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdio/scanf_core/scanf_main.h:14:
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdio/scanf_core/converter.h:15:
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdio/scanf_core/core_structs.h:16:
/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-onr0xued/./lib/clang/22/include/inttypes.h:24:15: fatal error: 'inttypes.h' file not found
   24 | #include_next <inttypes.h>
      |               ^~~~~~~~~~~~
1 error generated.
[485/2522] Building CXX object libc/src/complex/generic/CMakeFiles/libc.src.complex.generic.cprojl.dir/cprojl.cpp.obj
[486/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_width_uc.dir/stdc_bit_width_uc.cpp.obj
[487/2522] Building CXX object libc/src/complex/generic/CMakeFiles/libc.src.complex.generic.cproj.dir/cproj.cpp.obj
[488/2522] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.issignaling.dir/issignaling.cpp.obj
[489/2522] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.issignalingl.dir/issignalingl.cpp.obj
[490/2522] Building CXX object libc/src/__support/CMakeFiles/libc.src.__support.freelist.dir/freelist.cpp.obj
[491/2522] Building CXX object libc/src/__support/StringUtil/CMakeFiles/libc.src.__support.StringUtil.error_to_string.dir/error_to_string.cpp.obj
[492/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_has_single_bit_ull.dir/stdc_has_single_bit_ull.cpp.obj
[493/2522] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.iscanonicalf.dir/iscanonicalf.cpp.obj
[494/2522] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.issignalingf.dir/issignalingf.cpp.obj
[495/2522] Building CXX object libc/src/__support/CMakeFiles/libc.src.__support.freetrie.dir/freetrie.cpp.obj
[496/2522] Building CXX object libc/src/inttypes/CMakeFiles/libc.src.inttypes.imaxabs.dir/imaxabs.cpp.obj
[497/2522] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.iscanonical.dir/iscanonical.cpp.obj
[498/2522] Building CXX object libc/src/inttypes/CMakeFiles/libc.src.inttypes.imaxdiv.dir/imaxdiv.cpp.obj
[499/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_width_ui.dir/stdc_bit_width_ui.cpp.obj
[500/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_width_ul.dir/stdc_bit_width_ul.cpp.obj
[501/2522] Building CXX object libc/src/__support/CMakeFiles/libc.src.__support.freelist_heap.dir/freelist_heap.cpp.obj
[502/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_floor_ul.dir/stdc_bit_floor_ul.cpp.obj
[503/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_width_ull.dir/stdc_bit_width_ull.cpp.obj
[504/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_floor_ui.dir/stdc_bit_floor_ui.cpp.obj
[505/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_floor_uc.dir/stdc_bit_floor_uc.cpp.obj
[506/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_first_leading_zero_ui.dir/stdc_first_leading_zero_ui.cpp.obj
[507/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_first_leading_zero_ull.dir/stdc_first_leading_zero_ull.cpp.obj
[508/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_floor_ull.dir/stdc_bit_floor_ull.cpp.obj
[509/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_first_leading_one_ull.dir/stdc_first_leading_one_ull.cpp.obj
[510/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_ceil_ui.dir/stdc_bit_ceil_ui.cpp.obj
[511/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_ceil_uc.dir/stdc_bit_ceil_uc.cpp.obj
[512/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_floor_us.dir/stdc_bit_floor_us.cpp.obj
[513/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_ceil_ul.dir/stdc_bit_ceil_ul.cpp.obj
Step 6 (build) failure: build (failure)
...
[475/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_has_single_bit_us.dir/stdc_has_single_bit_us.cpp.obj
[476/2522] Building CXX object libc/src/complex/generic/CMakeFiles/libc.src.complex.generic.conjf.dir/conjf.cpp.obj
[477/2522] Building CXX object libc/src/complex/generic/CMakeFiles/libc.src.complex.generic.conjl.dir/conjl.cpp.obj
[478/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_has_single_bit_uc.dir/stdc_has_single_bit_uc.cpp.obj
[479/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_trailing_zeros_ull.dir/stdc_trailing_zeros_ull.cpp.obj
[480/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_has_single_bit_ui.dir/stdc_has_single_bit_ui.cpp.obj
[481/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_has_single_bit_ul.dir/stdc_has_single_bit_ul.cpp.obj
[482/2522] Building CXX object libc/src/complex/generic/CMakeFiles/libc.src.complex.generic.cprojf.dir/cprojf.cpp.obj
[483/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_width_us.dir/stdc_bit_width_us.cpp.obj
[484/2522] Building CXX object libc/src/stdio/CMakeFiles/libc.src.stdio.vsscanf.dir/vsscanf.cpp.obj
FAILED: libc/src/stdio/CMakeFiles/libc.src.stdio.vsscanf.dir/vsscanf.cpp.obj 
/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-onr0xued/./bin/clang++ --target=armv7m-none-eabi -DLIBC_NAMESPACE=__llvm_libc_22_0_0_git -I/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc -isystem /var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-onr0xued/include/armv7m-unknown-none-eabi --target=armv7m-none-eabi -Wno-atomic-alignment "-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)" "-Dfprintf(stream, format, ...)=printf(format)" "-Dfputs(string, stream)=puts(string)" -D_LIBCPP_PRINT=1 -mthumb -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -ffunction-sections -fdata-sections -ffile-prefix-map=/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-onr0xued/runtimes/runtimes-armv7m-none-eabi-bins=../../../../llvm-project -ffile-prefix-map=/var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/= -no-canonical-prefixes -Os -DNDEBUG --target=armv7m-none-eabi -DLIBC_QSORT_IMPL=LIBC_QSORT_HEAP_SORT -DLIBC_TYPES_TIME_T_IS_32_BIT -DLIBC_ADD_NULL_CHECKS "-DLIBC_MATH=(LIBC_MATH_SKIP_ACCURATE_PASS | LIBC_MATH_SMALL_TABLES)" -DLIBC_ERRNO_MODE=LIBC_ERRNO_MODE_EXTERNAL -fpie -ffreestanding -DLIBC_FULL_BUILD -nostdlibinc -ffixed-point -fno-builtin -fno-exceptions -fno-lax-vector-conversions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -ftrivial-auto-var-init=pattern -fno-omit-frame-pointer -Wall -Wextra -Werror -Wconversion -Wno-sign-conversion -Wdeprecated -Wno-c99-extensions -Wno-gnu-imaginary-constant -Wno-pedantic -Wimplicit-fallthrough -Wwrite-strings -Wextra-semi -Wnewline-eof -Wnonportable-system-include-path -Wstrict-prototypes -Wthread-safety -Wglobal-constructors -DLIBC_COPT_PUBLIC_PACKAGING -MD -MT libc/src/stdio/CMakeFiles/libc.src.stdio.vsscanf.dir/vsscanf.cpp.obj -MF libc/src/stdio/CMakeFiles/libc.src.stdio.vsscanf.dir/vsscanf.cpp.obj.d -o libc/src/stdio/CMakeFiles/libc.src.stdio.vsscanf.dir/vsscanf.cpp.obj -c /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdio/vsscanf.cpp
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdio/vsscanf.cpp:14:
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdio/scanf_core/scanf_main.h:14:
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdio/scanf_core/converter.h:15:
In file included from /var/lib/buildbot/fuchsia-x86_64-linux/llvm-project/libc/src/stdio/scanf_core/core_structs.h:16:
/var/lib/buildbot/fuchsia-x86_64-linux/build/llvm-build-onr0xued/./lib/clang/22/include/inttypes.h:24:15: fatal error: 'inttypes.h' file not found
   24 | #include_next <inttypes.h>
      |               ^~~~~~~~~~~~
1 error generated.
[485/2522] Building CXX object libc/src/complex/generic/CMakeFiles/libc.src.complex.generic.cprojl.dir/cprojl.cpp.obj
[486/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_width_uc.dir/stdc_bit_width_uc.cpp.obj
[487/2522] Building CXX object libc/src/complex/generic/CMakeFiles/libc.src.complex.generic.cproj.dir/cproj.cpp.obj
[488/2522] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.issignaling.dir/issignaling.cpp.obj
[489/2522] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.issignalingl.dir/issignalingl.cpp.obj
[490/2522] Building CXX object libc/src/__support/CMakeFiles/libc.src.__support.freelist.dir/freelist.cpp.obj
[491/2522] Building CXX object libc/src/__support/StringUtil/CMakeFiles/libc.src.__support.StringUtil.error_to_string.dir/error_to_string.cpp.obj
[492/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_has_single_bit_ull.dir/stdc_has_single_bit_ull.cpp.obj
[493/2522] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.iscanonicalf.dir/iscanonicalf.cpp.obj
[494/2522] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.issignalingf.dir/issignalingf.cpp.obj
[495/2522] Building CXX object libc/src/__support/CMakeFiles/libc.src.__support.freetrie.dir/freetrie.cpp.obj
[496/2522] Building CXX object libc/src/inttypes/CMakeFiles/libc.src.inttypes.imaxabs.dir/imaxabs.cpp.obj
[497/2522] Building CXX object libc/src/math/generic/CMakeFiles/libc.src.math.generic.iscanonical.dir/iscanonical.cpp.obj
[498/2522] Building CXX object libc/src/inttypes/CMakeFiles/libc.src.inttypes.imaxdiv.dir/imaxdiv.cpp.obj
[499/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_width_ui.dir/stdc_bit_width_ui.cpp.obj
[500/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_width_ul.dir/stdc_bit_width_ul.cpp.obj
[501/2522] Building CXX object libc/src/__support/CMakeFiles/libc.src.__support.freelist_heap.dir/freelist_heap.cpp.obj
[502/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_floor_ul.dir/stdc_bit_floor_ul.cpp.obj
[503/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_width_ull.dir/stdc_bit_width_ull.cpp.obj
[504/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_floor_ui.dir/stdc_bit_floor_ui.cpp.obj
[505/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_floor_uc.dir/stdc_bit_floor_uc.cpp.obj
[506/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_first_leading_zero_ui.dir/stdc_first_leading_zero_ui.cpp.obj
[507/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_first_leading_zero_ull.dir/stdc_first_leading_zero_ull.cpp.obj
[508/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_floor_ull.dir/stdc_bit_floor_ull.cpp.obj
[509/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_first_leading_one_ull.dir/stdc_first_leading_one_ull.cpp.obj
[510/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_ceil_ui.dir/stdc_bit_ceil_ui.cpp.obj
[511/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_ceil_uc.dir/stdc_bit_ceil_uc.cpp.obj
[512/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_floor_us.dir/stdc_bit_floor_us.cpp.obj
[513/2522] Building CXX object libc/src/stdbit/CMakeFiles/libc.src.stdbit.stdc_bit_ceil_ul.dir/stdc_bit_ceil_ul.cpp.obj

@llvm-ci
Copy link
Collaborator

llvm-ci commented Jul 26, 2025

LLVM Buildbot has detected a new failure on builder clang-aarch64-quick running on linaro-clang-aarch64-quick while building clang at step 5 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/65/builds/20240

Here is the relevant piece of the build log for the reference
Step 5 (ninja check 1) failure: stage 1 checked (failure)
******************** TEST 'Clangd Unit Tests :: ./ClangdTests/54/162' FAILED ********************
Script(shard):
--
GTEST_OUTPUT=json:/home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests-Clangd Unit Tests-1509181-54-162.json GTEST_SHUFFLE=0 GTEST_TOTAL_SHARDS=162 GTEST_SHARD_INDEX=54 /home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests
--

Note: This is test shard 55 of 162.
[==========] Running 8 tests from 8 test suites.
[----------] Global test environment set-up.
[----------] 1 test from ClangdServerTest
[ RUN      ] ClangdServerTest.FormatCode
ASTWorker building file /clangd-test/foo.cpp version null with command 
[/clangd-test]
clang -ffreestanding /clangd-test/foo.cpp
Driver produced command: cc1 -cc1 -triple aarch64-unknown-linux-gnu -fsyntax-only -disable-free -clear-ast-before-backend -main-file-name foo.cpp -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=non-leaf -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -ffreestanding -enable-tlsdesc -target-cpu generic -target-feature +v8a -target-feature +fp-armv8 -target-feature +neon -target-abi aapcs -debugger-tuning=gdb -fdebug-compilation-dir=/clangd-test -fcoverage-compilation-dir=/clangd-test -resource-dir lib/clang/22 -internal-isystem lib/clang/22/include -internal-isystem /usr/local/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdeprecated-macro -ferror-limit 19 -fno-signed-char -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -no-round-trip-args -target-feature -fmv -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -x c++ /clangd-test/foo.cpp
Building first preamble for /clangd-test/foo.cpp version null
not idle after addDocument
UNREACHABLE executed at ../llvm/clang-tools-extra/clangd/unittests/SyncAPI.cpp:22!
 #0 0x0000afd4fc4d7a90 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests+0xc37a90)
 #1 0x0000afd4fc4d5558 llvm::sys::RunSignalHandlers() (/home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests+0xc35558)
 #2 0x0000afd4fc4d88ec SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #3 0x0000faa05a5b48f8 (linux-vdso.so.1+0x8f8)
 #4 0x0000faa05a0cf1f0 __pthread_kill_implementation ./nptl/./nptl/pthread_kill.c:44:76
 #5 0x0000faa05a08a67c gsignal ./signal/../sysdeps/posix/raise.c:27:6
 #6 0x0000faa05a077130 abort ./stdlib/./stdlib/abort.c:81:7
 #7 0x0000afd4fc484420 llvm::RTTIRoot::anchor() (/home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests+0xbe4420)
 #8 0x0000afd4fc3354a4 clang::clangd::runCodeComplete(clang::clangd::ClangdServer&, llvm::StringRef, clang::clangd::Position, clang::clangd::CodeCompleteOptions) (/home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests+0xa954a4)
 #9 0x0000afd4fbe6b5bc clang::clangd::(anonymous namespace)::ClangdServerTest_FormatCode_Test::TestBody() ClangdTests.cpp:0:0
#10 0x0000afd4fc52e22c testing::Test::Run() (/home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests+0xc8e22c)
#11 0x0000afd4fc52f550 testing::TestInfo::Run() (/home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests+0xc8f550)
#12 0x0000afd4fc53018c testing::TestSuite::Run() (/home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests+0xc9018c)
#13 0x0000afd4fc54050c testing::internal::UnitTestImpl::RunAllTests() (/home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests+0xca050c)
#14 0x0000afd4fc53fe58 testing::UnitTest::Run() (/home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests+0xc9fe58)
#15 0x0000afd4fc51af74 main (/home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests+0xc7af74)
#16 0x0000faa05a0773fc __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:74:3
#17 0x0000faa05a0774cc call_init ./csu/../csu/libc-start.c:128:20
#18 0x0000faa05a0774cc __libc_start_main ./csu/../csu/libc-start.c:379:5
#19 0x0000afd4fbcf39f0 _start (/home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests+0x4539f0)

--
exit: -6
--
shard JSON output does not exist: /home/tcwg-buildbot/worker/clang-aarch64-quick/stage1/tools/clang/tools/extra/clangd/unittests/./ClangdTests-Clangd Unit Tests-1509181-54-162.json
********************


@llvm-ci
Copy link
Collaborator

llvm-ci commented Jul 26, 2025

LLVM Buildbot has detected a new failure on builder lldb-arm-ubuntu running on linaro-lldb-arm-ubuntu while building clang at step 6 "test".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/18/builds/19589

Here is the relevant piece of the build log for the reference
Step 6 (test) failure: build (failure)
...
PASS: lldb-unit :: ValueObject/./LLDBValueObjectTests/4/12 (3336 of 3345)
PASS: lldb-unit :: ValueObject/./LLDBValueObjectTests/5/12 (3337 of 3345)
PASS: lldb-unit :: ValueObject/./LLDBValueObjectTests/6/12 (3338 of 3345)
PASS: lldb-unit :: ValueObject/./LLDBValueObjectTests/7/12 (3339 of 3345)
PASS: lldb-unit :: ValueObject/./LLDBValueObjectTests/8/12 (3340 of 3345)
PASS: lldb-unit :: ValueObject/./LLDBValueObjectTests/9/12 (3341 of 3345)
PASS: lldb-unit :: tools/lldb-server/tests/./LLDBServerTests/0/2 (3342 of 3345)
PASS: lldb-unit :: tools/lldb-server/tests/./LLDBServerTests/1/2 (3343 of 3345)
PASS: lldb-unit :: Process/gdb-remote/./ProcessGdbRemoteTests/8/35 (3344 of 3345)
TIMEOUT: lldb-api :: tools/lldb-dap/module/TestDAP_module.py (3345 of 3345)
******************** TEST 'lldb-api :: tools/lldb-dap/module/TestDAP_module.py' FAILED ********************
Script:
--
/usr/bin/python3.10 /home/tcwg-buildbot/worker/lldb-arm-ubuntu/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./lib --env LLVM_INCLUDE_DIR=/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/include --env LLVM_TOOLS_DIR=/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin --arch armv8l --build-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex --lldb-module-cache-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin/lldb --compiler /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin/clang --dsymutil /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin/dsymutil --make /usr/bin/gmake --llvm-tools-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin --lldb-obj-root /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/tools/lldb --lldb-libs-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./lib --cmake-build-type Release /home/tcwg-buildbot/worker/lldb-arm-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/module -p TestDAP_module.py
--
Exit Code: -9
Timeout: Reached timeout of 600 seconds

Command Output (stdout):
--
lldb version 22.0.0git (https://github.com/llvm/llvm-project.git revision 29992cfd628ed5b968ccb73b17ed0521382ba317)
  clang revision 29992cfd628ed5b968ccb73b17ed0521382ba317
  llvm revision 29992cfd628ed5b968ccb73b17ed0521382ba317

--
Command Output (stderr):
--
========= DEBUG ADAPTER PROTOCOL LOGS =========
1753546063.448370934 (stdio) --> {"command":"initialize","type":"request","arguments":{"adapterID":"lldb-native","clientID":"vscode","columnsStartAt1":true,"linesStartAt1":true,"locale":"en-us","pathFormat":"path","supportsRunInTerminalRequest":true,"supportsVariablePaging":true,"supportsVariableType":true,"supportsStartDebuggingRequest":true,"supportsProgressReporting":true,"$__lldb_sourceInitFile":false},"seq":1}
1753546063.451938629 (stdio) <-- {"body":{"$__lldb_version":"lldb version 22.0.0git (https://github.com/llvm/llvm-project.git revision 29992cfd628ed5b968ccb73b17ed0521382ba317)\n  clang revision 29992cfd628ed5b968ccb73b17ed0521382ba317\n  llvm revision 29992cfd628ed5b968ccb73b17ed0521382ba317","completionTriggerCharacters":["."," ","\t"],"exceptionBreakpointFilters":[{"description":"C++ Catch","filter":"cpp_catch","label":"C++ Catch","supportsCondition":true},{"description":"C++ Throw","filter":"cpp_throw","label":"C++ Throw","supportsCondition":true},{"description":"Objective-C Catch","filter":"objc_catch","label":"Objective-C Catch","supportsCondition":true},{"description":"Objective-C Throw","filter":"objc_throw","label":"Objective-C Throw","supportsCondition":true}],"supportTerminateDebuggee":true,"supportsBreakpointLocationsRequest":true,"supportsCancelRequest":true,"supportsCompletionsRequest":true,"supportsConditionalBreakpoints":true,"supportsConfigurationDoneRequest":true,"supportsDataBreakpoints":true,"supportsDelayedStackTraceLoading":true,"supportsDisassembleRequest":true,"supportsEvaluateForHovers":true,"supportsExceptionFilterOptions":true,"supportsExceptionInfoRequest":true,"supportsFunctionBreakpoints":true,"supportsHitConditionalBreakpoints":true,"supportsInstructionBreakpoints":true,"supportsLogPoints":true,"supportsModulesRequest":true,"supportsReadMemoryRequest":true,"supportsSetVariable":true,"supportsSteppingGranularity":true,"supportsValueFormattingOptions":true,"supportsWriteMemoryRequest":true},"command":"initialize","request_seq":1,"seq":0,"success":true,"type":"response"}
1753546063.452424526 (stdio) --> {"command":"launch","type":"request","arguments":{"program":"/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/tools/lldb-dap/module/TestDAP_module.test_compile_units/a.out","initCommands":["settings clear --all","settings set symbols.enable-external-lookup false","settings set target.inherit-tcc true","settings set target.disable-aslr false","settings set target.detach-on-error false","settings set target.auto-apply-fixits false","settings set plugin.process.gdb-remote.packet-timeout 60","settings set symbols.clang-modules-cache-path \"/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api\"","settings set use-color false","settings set show-statusline false"],"disableASLR":false,"enableAutoVariableSummaries":false,"enableSyntheticChildDebugging":false,"displayExtendedBacktrace":false},"seq":2}
1753546063.452872515 (stdio) <-- {"body":{"category":"console","output":"Running initCommands:\n"},"event":"output","seq":0,"type":"event"}
1753546063.452930927 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings clear --all\n"},"event":"output","seq":0,"type":"event"}
1753546063.452944994 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set symbols.enable-external-lookup false\n"},"event":"output","seq":0,"type":"event"}
1753546063.452957392 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set target.inherit-tcc true\n"},"event":"output","seq":0,"type":"event"}
1753546063.452969313 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set target.disable-aslr false\n"},"event":"output","seq":0,"type":"event"}
1753546063.452980757 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set target.detach-on-error false\n"},"event":"output","seq":0,"type":"event"}
1753546063.452992678 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set target.auto-apply-fixits false\n"},"event":"output","seq":0,"type":"event"}
1753546063.453004837 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set plugin.process.gdb-remote.packet-timeout 60\n"},"event":"output","seq":0,"type":"event"}
1753546063.453063011 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set symbols.clang-modules-cache-path \"/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api\"\n"},"event":"output","seq":0,"type":"event"}
1753546063.453075647 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set use-color false\n"},"event":"output","seq":0,"type":"event"}
1753546063.453087568 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set show-statusline false\n"},"event":"output","seq":0,"type":"event"}
1753546063.600565195 (stdio) <-- {"command":"launch","request_seq":2,"seq":0,"success":true,"type":"response"}
1753546063.600648165 (stdio) <-- {"event":"initialized","seq":0,"type":"event"}
1753546063.600725412 (stdio) <-- {"body":{"module":{"addressRange":"0xf78bf000","debugInfoSize":"983.3KB","id":"253BA35E-436C-EC85-2949-CBD09E38AFEE-11B460BF","name":"ld-linux-armhf.so.3","path":"/usr/lib/arm-linux-gnueabihf/ld-linux-armhf.so.3","symbolFilePath":"/usr/lib/arm-linux-gnueabihf/ld-linux-armhf.so.3","symbolStatus":"Symbols loaded."},"reason":"new"},"event":"module","seq":0,"type":"event"}
1753546063.600907326 (stdio) <-- {"body":{"module":{"addressRange":"0x7d0000","debugInfoSize":"1.1KB","id":"713B0F17","name":"a.out","path":"/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/tools/lldb-dap/module/TestDAP_module.test_compile_units/a.out","symbolFilePath":"/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/tools/lldb-dap/module/TestDAP_module.test_compile_units/a.out","symbolStatus":"Symbols loaded."},"reason":"new"},"event":"module","seq":0,"type":"event"}
1753546063.601345778 (stdio) --> {"command":"setBreakpoints","type":"request","arguments":{"source":{"name":"main.cpp","path":"main.cpp"},"sourceModified":false,"lines":[5],"breakpoints":[{"line":5}]},"seq":3}
1753546063.613084078 (stdio) <-- {"body":{"breakpoints":[{"column":3,"id":1,"instructionReference":"0x7E073C","line":5,"source":{"name":"main.cpp","path":"main.cpp"},"verified":true}]},"command":"setBreakpoints","request_seq":3,"seq":0,"success":true,"type":"response"}
1753546063.613429070 (stdio) <-- {"body":{"breakpoint":{"column":3,"id":1,"instructionReference":"0x7E073C","line":5,"verified":true},"reason":"changed"},"event":"breakpoint","seq":0,"type":"event"}

mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Jul 28, 2025
This patch adds a human readable trap category and message to UBSan
traps. The category and message are encoded in a fake frame in the debug
info where the function is a fake inline function where the name encodes
the trap category and message. This is the same mechanism used by
Clang’s `__builtin_verbose_trap()`.

This change allows consumers of binaries built with trapping UBSan to
more easily identify the reason for trapping. In particular LLDB already
has a frame recognizer that recognizes the fake function names emitted
in debug info by this patch. A patch testing this behavior in LLDB will
be added in a separately.

The human readable trap messages are based on the messages currently
emitted by the userspace runtime for UBSan in compiler-rt. Note the
wording is not identical because the userspace UBSan runtime has access
to dynamic information that is not available during Clang’s codegen.

Test cases for each UBSan trap kind are included.

This complements the [`-fsanitize-annotate-debug-info`
feature](llvm#141997). While
`-fsanitize-annotate-debug-info` attempts to annotate all UBSan-added
instructions, this feature (`-fsanitize-debug-trap-reasons`) only
annotates the final trap instruction using SanitizerHandler information.

This work is part of a GSoc 2025 project.
delcypher pushed a commit that referenced this pull request Jul 31, 2025
)

In #145967 Clang was taught to emit trap reasons on UBSan traps in debug
info using the same method as `__builtin_verbose_trap`. This patch adds
a test case to make sure that the existing "Verbose Trap StackFrame
Recognizer" recognizes the trap reason and sets the stop reason and
stack frame appropriately.

Part of a GSoC 2025 Project.
delcypher added a commit to delcypher/apple-llvm-project that referenced this pull request Aug 27, 2025
…sons"

In 29992cf (llvm#145967) support was added
for "trap reasons" on traps emitted in UBSan in trapping mode (e.g.
`-fsanitize-trap=undefined`). This improved the debugging experience by
attaching the reason for trapping as a string on the debug info on trap
instructions. Consumers such as LLDB can display this trap reason string
when the trap is reached.

A limitation of that patch is that the trap reason string is hard-coded
for each `SanitizerKind` even though the compiler actually has much more
information about the trap available at compile time that could be shown
to the user.

This patch is an incremental step in fixing that. It consists of two
main steps.

**1. Introduce infrastructure for building trap reason strings **

To make it convenient to construct trap reason strings this patch
re-uses Clang's powerful diagnostic infrastructure to provide a
convenient API for constructing trap reason strings. This is achieved
by:

* Introducing a new `Trap` diagnostic kind to represent trap
  diagnostics in TableGen files.
* Adding a new `CodeGen` diagnostic component. While this part probably
  isn't technically necessary it seemed like I should follow the
  existing convention used by the diagnostic system.
* Adding `DiagnosticCodeGenKinds.td` to describe the different trap
  reasons.
* Add the `RuntimeTrapDiagnosticBuilder` class to provide an interface
  for constructing trap reason strings and the trap category. Note this
  API while similar to `DiagnosticBuilder` has different semantics which
  are described in the code comments. In particular the behavior when
  the destructor is called is very different.
* Adding `CodeGenModule::RuntimeDiag()` as a convenient constructor for
  the `RuntimeTrapDiagnosticBuilder`.

This use of the diagnostic system is a little unusual in that the
emitted trap diagnostics aren't actually consumed by normal diagnostic
consumers (e.g. the console). Instead the `RuntimeTrapDiagnosticBuilder`
is just used to format a string, so in effect the builder is somewhat
analagous to "printf". However, re-using the diagnostics system in this
way brings a several benefits:

* The powerful diagnostic templating languge (e.g. `%select`) can be
  used.
* Formatting Clang data types (e.g. `Type`, `Expr`, etc.) just
  work out-of-the-box.
* Describing trap reasons in tablegen files opens the door for
  translation to different languages in the future.
* The `RuntimeTrapDiagnosticBuilder` API is very similar to
  `DiagnosticBuilder` which makes it easy to use by anyone already
  familiar with Clang's diagnostic system.

While UBSan is the first consumer of this new infrastructure the intent
is to use this to overhaul how trap reasons are implemented in the
`-fbounds-safety` implementation (currently exists downstream).

**2. Apply the new infrastructure to UBSan checks for arithmetic overflow**

To demonstrate using `RuntimeTrapDiagnosticBuilder` this patch applies
it to UBSan traps for arithmetic overflow. The intention is that we
would iteratively switch to using the `RuntimeTrapDiagnosticBuilder` for
all UBSan traps where it makes sense in future patches.

Previously for code like

```
int test(int a, int b) { return a + b; }
```

The trap reason string looked like

```
Undefined Behavior Sanitizer: Integer addition overflowed
```

now the trap message looks like:

```
Undefined Behavior Sanitizer: signed integer addition overflow in 'a + b'
```

This string is much more specific because

* It explains if signed or unsigned overflow occurred
* It actually shows the expression that overflowed

This seems a lot more helpful.

One possible downside of this approach is it may blow up Debug info size
because now there can be many more distinct trap reason strings. If this
is a concern we may want to add a flag to make it possible to continue
to use the original hard-coded trap messages to avoid increasing the
size of Debug info.

rdar://158612755
delcypher added a commit that referenced this pull request Aug 27, 2025
…sons" (#154618)

In 29992cf (#145967) support was added
for "trap reasons" on traps emitted in UBSan in trapping mode (e.g.
`-fsanitize-trap=undefined`). This improved the debugging experience by
attaching the reason for trapping as a string on the debug info on trap
instructions. Consumers such as LLDB can display this trap reason string
when the trap is reached.

A limitation of that patch is that the trap reason string is hard-coded
for each `SanitizerKind` even though the compiler actually has much more
information about the trap available at compile time that could be shown
to the user.

This patch is an incremental step in fixing that. It consists of two
main steps.

**1. Introduce infrastructure for building trap reason strings**

To make it convenient to construct trap reason strings this patch
re-uses Clang's powerful diagnostic infrastructure to provide a
convenient API for constructing trap reason strings. This is achieved
by:

* Introducing a new `Trap` diagnostic kind to represent trap diagnostics
in TableGen files.
* Adding a new `Trap` diagnostic component. While this part probably
isn't technically necessary it seemed like I should follow the existing
convention used by the diagnostic system.
* Adding `DiagnosticTrapKinds.td` to describe the different trap
reasons.
* Add the `TrapReasonBuilder` and `TrapReason` classes to provide an
interface for constructing trap reason strings and the trap category.
Note this API while similar to `DiagnosticBuilder` has different
semantics which are described in the code comments. In particular the
behavior when the destructor is called is very different.
* Adding `CodeGenModule::BuildTrapReason()` as a convenient constructor
for the `TrapReasonBuilder`.

This use of the diagnostic system is a little unusual in that the
emitted trap diagnostics aren't actually consumed by normal diagnostic
consumers (e.g. the console). Instead the `TrapReasonBuilder` is just
used to format a string, so in effect the builder is somewhat analagous
to "printf". However, re-using the diagnostics system in this way brings
a several benefits:

* The powerful diagnostic templating languge (e.g. `%select`) can be
used.
* Formatting Clang data types (e.g. `Type`, `Expr`, etc.) just work
out-of-the-box.
* Describing trap reasons in tablegen files opens the door for
translation to different languages in the future.
* The `TrapReasonBuilder` API is very similar to `DiagnosticBuilder`
which makes it easy to use by anyone already familiar with Clang's
diagnostic system.

While UBSan is the first consumer of this new infrastructure the intent
is to use this to overhaul how trap reasons are implemented in the
`-fbounds-safety` implementation (currently exists downstream).

**2. Apply the new infrastructure to UBSan checks for arithmetic
overflow**

To demonstrate using `TrapReasonBuilder` this patch applies it to UBSan
traps for arithmetic overflow. The intention is that we would
iteratively switch to using the `TrapReasonBuilder` for all UBSan traps
where it makes sense in future patches.

Previously for code like

```
int test(int a, int b) { return a + b; }
```

The trap reason string looked like

```
Undefined Behavior Sanitizer: Integer addition overflowed
```

now the trap message looks like:

```
Undefined Behavior Sanitizer: signed integer addition overflow in 'a + b'
```

This string is much more specific because

* It explains if signed or unsigned overflow occurred
* It actually shows the expression that overflowed

One possible downside of this approach is it may blow up Debug info size
because now there can be many more distinct trap reason strings. To
allow users to avoid this a new driver/cc1 flag
`-fsanitize-debug-trap-reasons=` has been added which can either be
`none` (disable trap reasons entirely), `basic` (use the per
`SanitizerKind` hard coded strings), and `detailed` (use the new
expressive trap reasons implemented in this patch). The default is
`detailed` to give the best out-of-the-box debugging experience. The
existing `-fsanitize-debug-trap-reasons` and
`-fno-sanitize-debug-trap-reasons` have been kept for compatibility and
are aliases of the new flag with `detailed` and `none` arguments passed
respectively.


rdar://158612755
delcypher added a commit to delcypher/apple-llvm-project that referenced this pull request Sep 9, 2025
…sons" (llvm#154618)

In 29992cf (llvm#145967) support was added
for "trap reasons" on traps emitted in UBSan in trapping mode (e.g.
`-fsanitize-trap=undefined`). This improved the debugging experience by
attaching the reason for trapping as a string on the debug info on trap
instructions. Consumers such as LLDB can display this trap reason string
when the trap is reached.

A limitation of that patch is that the trap reason string is hard-coded
for each `SanitizerKind` even though the compiler actually has much more
information about the trap available at compile time that could be shown
to the user.

This patch is an incremental step in fixing that. It consists of two
main steps.

**1. Introduce infrastructure for building trap reason strings**

To make it convenient to construct trap reason strings this patch
re-uses Clang's powerful diagnostic infrastructure to provide a
convenient API for constructing trap reason strings. This is achieved
by:

* Introducing a new `Trap` diagnostic kind to represent trap diagnostics
in TableGen files.
* Adding a new `Trap` diagnostic component. While this part probably
isn't technically necessary it seemed like I should follow the existing
convention used by the diagnostic system.
* Adding `DiagnosticTrapKinds.td` to describe the different trap
reasons.
* Add the `TrapReasonBuilder` and `TrapReason` classes to provide an
interface for constructing trap reason strings and the trap category.
Note this API while similar to `DiagnosticBuilder` has different
semantics which are described in the code comments. In particular the
behavior when the destructor is called is very different.
* Adding `CodeGenModule::BuildTrapReason()` as a convenient constructor
for the `TrapReasonBuilder`.

This use of the diagnostic system is a little unusual in that the
emitted trap diagnostics aren't actually consumed by normal diagnostic
consumers (e.g. the console). Instead the `TrapReasonBuilder` is just
used to format a string, so in effect the builder is somewhat analagous
to "printf". However, re-using the diagnostics system in this way brings
a several benefits:

* The powerful diagnostic templating languge (e.g. `%select`) can be
used.
* Formatting Clang data types (e.g. `Type`, `Expr`, etc.) just work
out-of-the-box.
* Describing trap reasons in tablegen files opens the door for
translation to different languages in the future.
* The `TrapReasonBuilder` API is very similar to `DiagnosticBuilder`
which makes it easy to use by anyone already familiar with Clang's
diagnostic system.

While UBSan is the first consumer of this new infrastructure the intent
is to use this to overhaul how trap reasons are implemented in the
`-fbounds-safety` implementation (currently exists downstream).

**2. Apply the new infrastructure to UBSan checks for arithmetic
overflow**

To demonstrate using `TrapReasonBuilder` this patch applies it to UBSan
traps for arithmetic overflow. The intention is that we would
iteratively switch to using the `TrapReasonBuilder` for all UBSan traps
where it makes sense in future patches.

Previously for code like

```
int test(int a, int b) { return a + b; }
```

The trap reason string looked like

```
Undefined Behavior Sanitizer: Integer addition overflowed
```

now the trap message looks like:

```
Undefined Behavior Sanitizer: signed integer addition overflow in 'a + b'
```

This string is much more specific because

* It explains if signed or unsigned overflow occurred
* It actually shows the expression that overflowed

One possible downside of this approach is it may blow up Debug info size
because now there can be many more distinct trap reason strings. To
allow users to avoid this a new driver/cc1 flag
`-fsanitize-debug-trap-reasons=` has been added which can either be
`none` (disable trap reasons entirely), `basic` (use the per
`SanitizerKind` hard coded strings), and `detailed` (use the new
expressive trap reasons implemented in this patch). The default is
`detailed` to give the best out-of-the-box debugging experience. The
existing `-fsanitize-debug-trap-reasons` and
`-fno-sanitize-debug-trap-reasons` have been kept for compatibility and
are aliases of the new flag with `detailed` and `none` arguments passed
respectively.

rdar://158612755

Conflicts:
	clang/include/clang/Basic/AllDiagnosticKinds.inc
	clang/include/clang/Basic/DiagnosticIDs.h
	clang/lib/Basic/DiagnosticIDs.cpp
	clang/lib/CodeGen/CGExpr.cpp
	clang/lib/CodeGen/CodeGenFunction.h
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticIDs.h

rdar://159302620

(cherry picked from commit 6d385c3)
(cherry picked from commit f1ee047)
delcypher pushed a commit to swiftlang/llvm-project that referenced this pull request Sep 9, 2025
This patch adds a human readable trap category and message to UBSan
traps. The category and message are encoded in a fake frame in the debug
info where the function is a fake inline function where the name encodes
the trap category and message. This is the same mechanism used by
Clang’s `__builtin_verbose_trap()`.

This change allows consumers of binaries built with trapping UBSan to
more easily identify the reason for trapping. In particular LLDB already
has a frame recognizer that recognizes the fake function names emitted
in debug info by this patch. A patch testing this behavior in LLDB will
be added in a separately.

The human readable trap messages are based on the messages currently
emitted by the userspace runtime for UBSan in compiler-rt. Note the
wording is not identical because the userspace UBSan runtime has access
to dynamic information that is not available during Clang’s codegen.

Test cases for each UBSan trap kind are included.

This complements the [`-fsanitize-annotate-debug-info`
feature](llvm#141997). While
`-fsanitize-annotate-debug-info` attempts to annotate all UBSan-added
instructions, this feature (`-fsanitize-debug-trap-reasons`) only
annotates the final trap instruction using SanitizerHandler information.

This work is part of a GSoc 2025 project.

(cherry picked from commit ba477b9)
(cherry picked from commit 29992cf)
delcypher pushed a commit to swiftlang/llvm-project that referenced this pull request Sep 9, 2025
…#151231)

In llvm#145967 Clang was taught to emit trap reasons on UBSan traps in debug
info using the same method as `__builtin_verbose_trap`. This patch adds
a test case to make sure that the existing "Verbose Trap StackFrame
Recognizer" recognizes the trap reason and sets the stop reason and
stack frame appropriately.

Part of a GSoC 2025 Project.

(cherry picked from commit a8d0ae3)
delcypher added a commit to swiftlang/llvm-project that referenced this pull request Sep 9, 2025
…sons" (llvm#154618)

In 29992cf (llvm#145967) support was added
for "trap reasons" on traps emitted in UBSan in trapping mode (e.g.
`-fsanitize-trap=undefined`). This improved the debugging experience by
attaching the reason for trapping as a string on the debug info on trap
instructions. Consumers such as LLDB can display this trap reason string
when the trap is reached.

A limitation of that patch is that the trap reason string is hard-coded
for each `SanitizerKind` even though the compiler actually has much more
information about the trap available at compile time that could be shown
to the user.

This patch is an incremental step in fixing that. It consists of two
main steps.

**1. Introduce infrastructure for building trap reason strings**

To make it convenient to construct trap reason strings this patch
re-uses Clang's powerful diagnostic infrastructure to provide a
convenient API for constructing trap reason strings. This is achieved
by:

* Introducing a new `Trap` diagnostic kind to represent trap diagnostics
in TableGen files.
* Adding a new `Trap` diagnostic component. While this part probably
isn't technically necessary it seemed like I should follow the existing
convention used by the diagnostic system.
* Adding `DiagnosticTrapKinds.td` to describe the different trap
reasons.
* Add the `TrapReasonBuilder` and `TrapReason` classes to provide an
interface for constructing trap reason strings and the trap category.
Note this API while similar to `DiagnosticBuilder` has different
semantics which are described in the code comments. In particular the
behavior when the destructor is called is very different.
* Adding `CodeGenModule::BuildTrapReason()` as a convenient constructor
for the `TrapReasonBuilder`.

This use of the diagnostic system is a little unusual in that the
emitted trap diagnostics aren't actually consumed by normal diagnostic
consumers (e.g. the console). Instead the `TrapReasonBuilder` is just
used to format a string, so in effect the builder is somewhat analagous
to "printf". However, re-using the diagnostics system in this way brings
a several benefits:

* The powerful diagnostic templating languge (e.g. `%select`) can be
used.
* Formatting Clang data types (e.g. `Type`, `Expr`, etc.) just work
out-of-the-box.
* Describing trap reasons in tablegen files opens the door for
translation to different languages in the future.
* The `TrapReasonBuilder` API is very similar to `DiagnosticBuilder`
which makes it easy to use by anyone already familiar with Clang's
diagnostic system.

While UBSan is the first consumer of this new infrastructure the intent
is to use this to overhaul how trap reasons are implemented in the
`-fbounds-safety` implementation (currently exists downstream).

**2. Apply the new infrastructure to UBSan checks for arithmetic
overflow**

To demonstrate using `TrapReasonBuilder` this patch applies it to UBSan
traps for arithmetic overflow. The intention is that we would
iteratively switch to using the `TrapReasonBuilder` for all UBSan traps
where it makes sense in future patches.

Previously for code like

```
int test(int a, int b) { return a + b; }
```

The trap reason string looked like

```
Undefined Behavior Sanitizer: Integer addition overflowed
```

now the trap message looks like:

```
Undefined Behavior Sanitizer: signed integer addition overflow in 'a + b'
```

This string is much more specific because

* It explains if signed or unsigned overflow occurred
* It actually shows the expression that overflowed

One possible downside of this approach is it may blow up Debug info size
because now there can be many more distinct trap reason strings. To
allow users to avoid this a new driver/cc1 flag
`-fsanitize-debug-trap-reasons=` has been added which can either be
`none` (disable trap reasons entirely), `basic` (use the per
`SanitizerKind` hard coded strings), and `detailed` (use the new
expressive trap reasons implemented in this patch). The default is
`detailed` to give the best out-of-the-box debugging experience. The
existing `-fsanitize-debug-trap-reasons` and
`-fno-sanitize-debug-trap-reasons` have been kept for compatibility and
are aliases of the new flag with `detailed` and `none` arguments passed
respectively.

rdar://158612755

Conflicts:
	clang/include/clang/Basic/AllDiagnosticKinds.inc
	clang/include/clang/Basic/DiagnosticIDs.h
	clang/lib/Basic/DiagnosticIDs.cpp
	clang/lib/CodeGen/CGExpr.cpp
	clang/lib/CodeGen/CodeGenFunction.h
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticIDs.h

rdar://159302620

(cherry picked from commit 6d385c3)
(cherry picked from commit f1ee047)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:codegen IR generation bugs: mangling, exceptions, etc. clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category debuginfo

Projects

None yet

Development

Successfully merging this pull request may close these issues.