Skip to content

[clang][CodeGen] Added SanitizerHandler mapping, trap messages in debug info, and corresponding test cases. #143758

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

anthonyhatran
Copy link

@anthonyhatran anthonyhatran commented Jun 11, 2025

GSoC 2025
@delcypher @Michael137

Ran the clang test suite before and after changes, and some (~5) test cases failed after my changes:
clang/test/CodeGen/ubsan-trap-debugloc.c
clang/test/CodeGen/bounds-checking-debuginfo.c
clang/test/CodeGen/cfi-icall-normalize2-debuginfo.c
clang/test/CodeGen/cfi-icall-generalize-debuginfo.c
clang/test/Driver/clang_f_opts_withspaces.c

Still need to modify the hard-coded strings after further discussion

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 11, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 11, 2025

@llvm/pr-subscribers-clang-codegen

@llvm/pr-subscribers-clang

Author: None (anthonyhatran)

Changes

GSoC 2025
@delcypher @Michael137

Ran the clang test suite before and after changes, and some (~5) test cases failed:
clang/test/CodeGen/ubsan-trap-debugloc.c
clang/test/CodeGen/bounds-checking-debuginfo.c
clang/test/CodeGen/cfi-icall-normalize2-debuginfo.c
clang/test/CodeGen/cfi-icall-generalize-debuginfo.c
clang/test/Driver/clang_f_opts_withspaces.c

Still need to modify the hard-coded strings after further discussion


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

22 Files Affected:

  • (modified) clang/lib/CodeGen/CGExpr.cpp (+114-3)
  • (modified) clang/lib/CodeGen/CodeGenFunction.h (+2-1)
  • (added) clang/test/CodeGen/ubsan-trap-reason-add-overflow.c (+10)
  • (added) clang/test/CodeGen/ubsan-trap-reason-builtin-unreachable.c (+12)
  • (added) clang/test/CodeGen/ubsan-trap-reason-div-rem-overflow.c (+10)
  • (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 (+12)
  • (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 (+17)
  • (added) clang/test/CodeGen/ubsan-trap-reason-nonnull-return.c (+15)
  • (added) clang/test/CodeGen/ubsan-trap-reason-nullability-arg.c (+19)
  • (added) clang/test/CodeGen/ubsan-trap-reason-nullability-return.c (+19)
  • (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)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 6cb348ffdf55f..9100ef80c13f4 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -85,6 +85,98 @@ enum VariableTypeDescriptorKind : uint16_t {
 //                        Miscellaneous Helper Methods
 //===--------------------------------------------------------------------===//
 
+static llvm::StringRef GetTrapMessageForHandler(SanitizerHandler ID) {
+  switch (ID) {
+  case SanitizerHandler::AddOverflow:
+    return "The addition of two signed integers resulted in overflow.";
+
+  case SanitizerHandler::BuiltinUnreachable:
+    return "_builtin_unreachable encountered.";
+
+  case SanitizerHandler::CFICheckFail:
+    return "Control flow integrity check failed.";
+
+  case SanitizerHandler::DivremOverflow: // Unsure
+    return "stub";
+
+  case SanitizerHandler::DynamicTypeCacheMiss: // Unsure
+    return "Data requested for dynamic type not found in cache memory.";
+
+  case SanitizerHandler::FloatCastOverflow: // Pasted from LLVM docs, maybe
+                                            // something better to put here.
+    return "Conversion to, from, or between floating-point types which would "
+           "overflow the destination.";
+
+  case SanitizerHandler::FunctionTypeMismatch:
+    return "Function called with arguments of a different data type than "
+           "expected";
+
+  case SanitizerHandler::ImplicitConversion:
+    return "Implicit conversion occurred.";
+
+  case SanitizerHandler::InvalidBuiltin:
+    return "Built-in function or keyword not recognized.";
+
+  case SanitizerHandler::InvalidObjCCast:
+    return "Invalid Objective-C cast.";
+
+  case SanitizerHandler::LoadInvalidValue:
+    return "stub";
+
+  case SanitizerHandler::MissingReturn:
+    return "Function is missing a return.";
+
+  case SanitizerHandler::MulOverflow:
+    return "The multiplication of two signed integers resulted in overflow.";
+
+  case SanitizerHandler::NegateOverflow:
+    return "Underflow/negative overflow occurred.";
+
+  case SanitizerHandler::
+      NullabilityArg: // Next 4 pasted from
+                      // https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
+    return "Passing null as a function parameter 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 as a function parameter which is declared to never be "
+           "null";
+
+  case SanitizerHandler::NonnullReturn:
+    return "Returning null pointer from a function which is declared to never "
+           "be null";
+
+  case SanitizerHandler::OutOfBounds:
+    return "Out of bounds -- memory accessed outside of expected boundaries.";
+
+  case SanitizerHandler::PointerOverflow:
+    return "stub";
+
+  case SanitizerHandler::ShiftOutOfBounds:
+    return "Bit shift attempted to move bits beyond boundaries of data type's "
+           "bit size.";
+
+  case SanitizerHandler::SubOverflow:
+    return "The subtraction of two signed integers resulted in overflow.";
+
+  case SanitizerHandler::TypeMismatch:
+    return "Type mismatch -- value type used does not match type expected.";
+
+  case SanitizerHandler::AlignmentAssumption: // Help on bottom 2
+    return "stub";
+
+  case SanitizerHandler::VLABoundNotPositive:
+    return "stub";
+
+  default:
+    return "";
+  }
+}
+
 /// CreateTempAlloca - This creates a alloca and inserts it into the entry
 /// block.
 RawAddress
@@ -4041,7 +4133,8 @@ void CodeGenFunction::EmitUnreachable(SourceLocation Loc) {
 
 void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
                                     SanitizerHandler CheckHandlerID,
-                                    bool NoMerge) {
+                                    bool NoMerge, StringRef Annotation,
+                                    StringRef TrapMessage) {
   llvm::BasicBlock *Cont = createBasicBlock("cont");
 
   // If we're optimizing, collapse all calls to trap down to just one per
@@ -4051,6 +4144,14 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
 
   llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID];
 
+  llvm::DILocation *TrapLocation = Builder.getCurrentDebugLocation();
+  llvm::StringRef Category = GetTrapMessageForHandler(CheckHandlerID);
+
+  if (getDebugInfo() && !Category.empty()) {
+    TrapLocation = getDebugInfo()->CreateTrapFailureMessageFor(
+        TrapLocation, Category, TrapMessage);
+  }
+
   NoMerge = NoMerge || !CGM.getCodeGenOpts().OptimizationLevel ||
             (CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>());
 
@@ -4059,8 +4160,16 @@ 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(),
+    //                           Builder.getCurrentDebugLocation());
+    Call->applyMergedLocation(Call->getDebugLoc(), TrapLocation);
+
+    auto Unreachable = ++TrapBB->begin();
+    if (isa<llvm::UnreachableInst>(Unreachable)) {
+      Unreachable->applyMergedLocation(Unreachable->getDebugLoc(),
+                                       TrapLocation);
+    }
+
     Builder.CreateCondBr(Checked, Cont, TrapBB,
                          MDHelper.createLikelyBranchWeights());
   } else {
@@ -4069,6 +4178,8 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
                          MDHelper.createLikelyBranchWeights());
     EmitBlock(TrapBB);
 
+    ApplyDebugLocation applyTrapDI(*this, TrapLocation);
+
     llvm::CallInst *TrapCall =
         Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::ubsantrap),
                            llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID));
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index a5ab9df01dba9..aa9c862511579 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -5281,7 +5281,8 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// Create a basic block that will call the trap intrinsic, and emit a
   /// conditional branch to it, for the -ftrapv checks.
   void EmitTrapCheck(llvm::Value *Checked, SanitizerHandler CheckHandlerID,
-                     bool NoMerge = false);
+                     bool NoMerge = false, StringRef Annotation = "",
+                     StringRef TrapMessage = "");
 
   /// Emit a call to trap or debugtrap and attach function attribute
   /// "trap-func-name" if specified.
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..822a1c003d16a
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-add-overflow.c
@@ -0,0 +1,10 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=undefined \
+// RUN: -fsanitize-trap=undefined -emit-llvm -S -c %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$
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..ada4c372a92b7
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-builtin-unreachable.c
@@ -0,0 +1,12 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=unreachable \
+// RUN: -fsanitize-trap=unreachable -emit-llvm -S -c %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$
\ 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..17b6dca16cc62
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-div-rem-overflow.c
@@ -0,0 +1,10 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=undefined \
+// RUN: -fsanitize-trap=undefined -emit-llvm -S -c %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$
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..b761e638c5293
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-float-cast-overflow.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O0 -debug-info-kind=standalone -dwarf-version=5 -fsanitize=float-cast-overflow \
+// RUN: -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$
\ 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..25063b69a894c
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-function-type-mismatch.c
@@ -0,0 +1,16 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=undefined \
+// RUN: -fsanitize-trap=undefined -emit-llvm -S -c %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$
\ 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..48eb86d09b51a
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-implicit-conversion.c
@@ -0,0 +1,13 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=implicit-conversion \
+// RUN: -fsanitize-trap=implicit-conversion -emit-llvm -S -c %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$
\ 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..cd136df2f0ed4
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-invalid-builtin.c
@@ -0,0 +1,12 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=builtin \
+// RUN: -fsanitize-trap=builtin -emit-llvm -S -c %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$
\ 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..09d8d588f0a32
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-load-invalid-value.c
@@ -0,0 +1,15 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=undefined \
+// RUN: -fsanitize-trap=undefined -emit-llvm -S -c %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$
\ 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..7f0265abd2305
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-missing-return.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=return \
+// RUN: -fsanitize-trap=return -emit-llvm -S -c %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$
\ 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..e9f76b87455c9
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-mul-overflow.c
@@ -0,0 +1,10 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=undefined \
+// RUN: -fsanitize-trap=undefined -emit-llvm -S -c %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$
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..5660c6bb08d03
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-negate-overflow.c
@@ -0,0 +1,12 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=undefined \
+// RUN: -fsanitize-trap=undefined -emit-llvm -S -c %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$
\ 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..e648f91b86b27
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-nonnull-arg.c
@@ -0,0 +1,17 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=nonnull-attribute \
+// RUN: -fsanitize-trap=nonnull-attribute -emit-llvm -S -c %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$
\ 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..9b14004d96a02
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-nonnull-return.c
@@ -0,0 +1,15 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=returns-nonnull-attribute \
+// RUN: -fsanitize-trap=returns-nonnull-attribute -emit-llvm -S -c %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$
\ 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..e0d6a79b27c02
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-nullability-arg.c
@@ -0,0 +1,19 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=nullability-arg \
+// RUN: -fsanitize-trap=nullability-arg -emit-llvm -S -c %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$
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-nullability-return.c b/clang/test/CodeGen/ubsan-trap-reason-nullability-return.c
new file mode 100644
index 0000000000000..e10fc5b225221
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-nullability-return.c
@@ -0,0 +1,19 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=nullability-return \
+// RUN: -fsanitize-trap=nullability-return -emit-llvm -S -c %s -o - | FileCheck %s
+
+#include <stdbool.h>
+#include <stddef.h>
+
+int* _Nonnull nullability_return(bool fail)
+{
+    if (fail)
+        return NULL;
+
+    static int x = 0;
+    return &x;
+}
+
+
+// CHECK: call void @llvm.ubsantrap(i8 15) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-out-of-bounds.c b/clang/test/CodeGen/ubsan-trap-reason-out-of-bounds.c
new file mode 100644
index 0000000000000..9ed093fc528ed
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-out-of-bounds.c
@@ -0,0 +1,12 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=bounds \
+// RUN: -fsanitize-trap=bounds -emit-llvm -S -c %s -o - | FileCheck %s
+
+int out_of_bounds()
+{
+    int a[1] = {0};
+    return a[1];
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 18) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-pointer-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-pointer-overflow.c
new file mode 100644
index 0000000000000..93ae42208520f
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-pointer-overflow.c
@@ -0,0 +1,16 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=pointer-overflow \
+// RUN: -fsanitize-trap=pointer-overflow -emit-llvm -S -c %s -o - | FileCheck %s
+
+#include <stddef.h>
+#include <stdint.h>
+
+int* pointer_overflow(void)
+{
+    int buf[4];
+    volatile size_t n = (SIZE_MAX / sizeof(int)) - 1;
+    return buf + n;
+}
+
+// CHECK: call void @llvm.ubsantrap(i8 19) {{.*}}!dbg [[LOC:![0-9]+]]
+// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}})
+// CHECK: distinct !DISubprogram(name: "__clang_trap_msg$
\ No newline at end of file
diff --git a/clang/test/CodeGen/ubsan-trap-reason-shift-out-of-bounds.c b/clang/test/CodeGen/ubsan-trap-reason-shift-out-of-bounds.c
new file mode 100644
index 0000000000000..6f5aff7cd197a
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-trap-reason-shift-out-of-bounds.c
@@ -0,0 +1,12 @@
+// RUN: %clang -O0 -g -debug-info-kind=standalone -dwarf-version=5 -fsanitize=shift \
+// RUN: -fsanitize-trap=shift -emi...
[truncated]

@anthonyhatran
Copy link
Author

Forgot to mention missing test cases:
SanitizerHandler::CFICheckFail (was able to get this working with -fsanitize=cfi-cast-strict on my build, but cfi-cast-strict couldn't be identified in the testing dir)
SanitizerHandler::AlignmentAssumption
SanitizerHandler::VLABoundNotPositive
SanitizerHandler::InvalidObjCCast

@@ -4041,7 +4133,8 @@ void CodeGenFunction::EmitUnreachable(SourceLocation Loc) {

void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
SanitizerHandler CheckHandlerID,
bool NoMerge) {
bool NoMerge, StringRef Annotation,
StringRef TrapMessage) {
Copy link
Member

@Michael137 Michael137 Jun 13, 2025

Choose a reason for hiding this comment

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

TrapMessage parameter seems to not get passed from anywhere?


if (getDebugInfo() && !Category.empty()) {
TrapLocation = getDebugInfo()->CreateTrapFailureMessageFor(
TrapLocation, Category, TrapMessage);
Copy link
Member

@Michael137 Michael137 Jun 13, 2025

Choose a reason for hiding this comment

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

Correct me if I'm wrong, but shouldn't TrapMessage be what GetTrapMessageForHandler provides, and Category be something like "UBSan Trap"?

The way the fake inline frame name gets constructed is:

__clang_trap_msg$<category>$<trap message>

Currently you are omitting the "" and putting the failure reason into the category. It would still technically work out with LLDB (it will display the category even if no message was provided), but it wouldn't be consistent with how __verbose_trap is handled

Copy link
Author

@anthonyhatran anthonyhatran Jun 13, 2025

Choose a reason for hiding this comment

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

Yes, you are correct on that. I didn't initially intend on having the TrapMessage part there at all until I examined CreateTrapFailureMessageFor which required it, which was why I left it like so. I think a possible approach could be to put the SanitizerHandler's name as the category, and have the GetTrapMessageForHandler deal with the TrapMessage, but let me know if it would be preferable to have it more general with "UBSan Trap" instead


// 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$
Copy link
Member

Choose a reason for hiding this comment

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

lets check that the "category" part of the fake frame name is correct too

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 Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants