[clang] [compiler-rt] [UBSAN] add null and alignment checks for aggregates (PR #164548)
    VASU SHARMA via llvm-commits 
    llvm-commits at lists.llvm.org
       
    Wed Oct 22 03:45:42 PDT 2025
    
    
  
https://github.com/vasu-the-sharma updated https://github.com/llvm/llvm-project/pull/164548
>From 856ac3b4110d79e57bfef9fed52c00a989683083 Mon Sep 17 00:00:00 2001
From: Vasu Sharma <vasusharma at Vasus-MacBook-Pro.local>
Date: Wed, 22 Oct 2025 10:04:59 +0530
Subject: [PATCH 1/2] add null and aligment checks for aggregates
---
 clang/lib/CodeGen/CGExprAgg.cpp | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index eee397f1f3d19..de6d80a273dbd 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -2249,6 +2249,21 @@ void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty,
                                         bool isVolatile) {
   assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
 
+  if (SanOpts.hasOneOf(SanitizerKind::Null | SanitizerKind::Alignment)) {
+    Address SrcAddr = Src.getAddress();
+    Address DestAddr = Dest.getAddress();
+
+    // Check source pointer for null and alignment violations
+    EmitTypeCheck(TCK_Load, SourceLocation(),
+                  SrcAddr.emitRawPointer(*this), Ty, SrcAddr.getAlignment(),
+                  SanitizerSet());
+
+    // Check destination pointer for null and alignment violations
+    EmitTypeCheck(TCK_Store, SourceLocation(),
+                  DestAddr.emitRawPointer(*this), Ty, DestAddr.getAlignment(),
+                  SanitizerSet());
+  }
+
   Address DestPtr = Dest.getAddress();
   Address SrcPtr = Src.getAddress();
 
>From 4b7ff1ed2976e27b82b0ce660d47749add49f817 Mon Sep 17 00:00:00 2001
From: Vasu Sharma <vasusharma at Vasus-MacBook-Pro.local>
Date: Wed, 22 Oct 2025 16:15:22 +0530
Subject: [PATCH 2/2] Add null and alignment checks for aggregate copy
 operation
---
 clang/lib/CodeGen/CGExprAgg.cpp               |  3 +
 .../Misc/Posix/aggregate_null_alignment.cpp   | 79 +++++++++++++++++++
 2 files changed, 82 insertions(+)
 create mode 100644 compiler-rt/test/ubsan/TestCases/Misc/Posix/aggregate_null_alignment.cpp
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index de6d80a273dbd..2e5456233c711 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -2249,6 +2249,9 @@ void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty,
                                         bool isVolatile) {
   assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
 
+  // Sanitizer checks to verify source and destination pointers are
+  // non-null and properly aligned before copying.
+  // Without these checks, undefined behavior from invalid pointers goes undetected.
   if (SanOpts.hasOneOf(SanitizerKind::Null | SanitizerKind::Alignment)) {
     Address SrcAddr = Src.getAddress();
     Address DestAddr = Dest.getAddress();
diff --git a/compiler-rt/test/ubsan/TestCases/Misc/Posix/aggregate_null_alignment.cpp b/compiler-rt/test/ubsan/TestCases/Misc/Posix/aggregate_null_alignment.cpp
new file mode 100644
index 0000000000000..de62c3d5a4df7
--- /dev/null
+++ b/compiler-rt/test/ubsan/TestCases/Misc/Posix/aggregate_null_alignment.cpp
@@ -0,0 +1,79 @@
+// RUN: %clangxx -fsanitize=alignment,null -O0 %s -o %t && %run %t
+// RUN: %clangxx -fsanitize=alignment,null -O0 -DTEST_NULL_SRC %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-SRC
+// RUN: %clangxx -fsanitize=alignment,null -O0 -DTEST_NULL_DEST %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-DEST
+// RUN: %clangxx -fsanitize=alignment,null -O0 -DTEST_MISALIGN_SRC %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ALIGN-SRC
+// RUN: %clangxx -fsanitize=alignment,null -O0 -DTEST_MISALIGN_DEST %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ALIGN-DEST
+
+// Tests for null pointer and alignment checks in aggregate copy operations.
+// This validates the sanitizer checks added to EmitAggregateCopy for both
+// source and destination pointers with null and alignment violations.
+
+#include <stdlib.h>
+#include <string.h>
+
+struct alignas(16) AlignedStruct {
+  int a;
+  int b;
+  int c;
+  int d;
+};
+
+struct NormalStruct {
+  int x;
+  int y;
+  int z;
+};
+
+void test_null_src() {
+  AlignedStruct dest;
+  AlignedStruct *src = nullptr;
+  // CHECK-NULL-SRC: runtime error: load of null pointer of type 'AlignedStruct'
+  dest = *src;
+}
+
+void test_null_dest() {
+  AlignedStruct src = {1, 2, 3, 4};
+  AlignedStruct *dest = nullptr;
+  // CHECK-NULL-DEST: runtime error: store to null pointer of type 'AlignedStruct'
+  *dest = src;
+}
+
+void test_misaligned_src() {
+  char buffer[sizeof(AlignedStruct) + 16];
+  // Create a misaligned pointer (not 16-byte aligned)
+  AlignedStruct *src = (AlignedStruct *)(buffer + 1);
+  AlignedStruct dest;
+  // CHECK-ALIGN-SRC: runtime error: load of misaligned address {{0x[0-9a-f]+}} for type 'AlignedStruct', which requires 16 byte alignment
+  dest = *src;
+}
+
+void test_misaligned_dest() {
+  AlignedStruct src = {1, 2, 3, 4};
+  char buffer[sizeof(AlignedStruct) + 16];
+  // Create a misaligned pointer (not 16-byte aligned)
+  AlignedStruct *dest = (AlignedStruct *)(buffer + 1);
+  // CHECK-ALIGN-DEST: runtime error: store to misaligned address {{0x[0-9a-f]+}} for type 'AlignedStruct', which requires 16 byte alignment
+  *dest = src;
+}
+
+void test_normal_copy() {
+  // This should work fine - properly aligned, non-null pointers
+  AlignedStruct src = {1, 2, 3, 4};
+  AlignedStruct dest;
+  dest = src;
+}
+
+int main() {
+#ifdef TEST_NULL_SRC
+  test_null_src();
+#elif defined(TEST_NULL_DEST)
+  test_null_dest();
+#elif defined(TEST_MISALIGN_SRC)
+  test_misaligned_src();
+#elif defined(TEST_MISALIGN_DEST)
+  test_misaligned_dest();
+#else
+  test_normal_copy();
+#endif
+  return 0;
+}
    
    
More information about the llvm-commits
mailing list