https://github.com/vasu-the-sharma updated https://github.com/llvm/llvm-project/pull/176210
>From c3c8b0bf9ce0c27378aecd28c95c929ba34bf237 Mon Sep 17 00:00:00 2001 From: vasu-ibm <[email protected]> Date: Thu, 15 Jan 2026 13:11:53 -0500 Subject: [PATCH 1/3] add coverage for null and alignment checks --- .../test/CodeGen/ubsan-aggregate-null-align.c | 507 ++++++++++++++++++ 1 file changed, 507 insertions(+) create mode 100644 clang/test/CodeGen/ubsan-aggregate-null-align.c diff --git a/clang/test/CodeGen/ubsan-aggregate-null-align.c b/clang/test/CodeGen/ubsan-aggregate-null-align.c new file mode 100644 index 0000000000000..da87f7bece163 --- /dev/null +++ b/clang/test/CodeGen/ubsan-aggregate-null-align.c @@ -0,0 +1,507 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=null,alignment -std=c11 -O0 %s -o %t.c.ll && FileCheck %s --check-prefixes=C,SHARED < %t.c.ll +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=null,alignment -std=c++17 -x c++ -O0 %s -o %t.cxx.ll && FileCheck %s --check-prefixes=CXX,SHARED < %t.cxx.ll + +struct Small { int x; }; +struct Container { struct Small inner; }; +struct SmallWrapper { struct Small a; }; + +extern void variadic_func(int, ...); + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================================ +// TYPE VARIANT: plain +// ============================================================================ + +// --- OPERAND FORM: arr[idx] --- + +// SHARED-LABEL: define {{[^@]*}}@test_assign_plain_arr_idx +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_assign_plain_arr_idx(struct Small *dest, struct Small arr[]) { + *dest = arr[0]; +} + +// SHARED-LABEL: define {{[^@]*}}@test_init_plain_arr_idx +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_init_plain_arr_idx(struct Small arr[]) { + struct Small a = arr[0]; +} + +// SHARED-LABEL: define {{[^@]*}}@test_init_list_plain_arr_idx +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_init_list_plain_arr_idx(struct Small arr[]) { + struct Small a[] = {arr[0]}; +} + +// SHARED-LABEL: define {{[^@]*}}@test_init_list_designate_plain_arr_idx +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_init_list_designate_plain_arr_idx(struct Small arr[]) { + struct Small a[] = {[0] = arr[0]}; +} + +// SHARED-LABEL: define {{[^@]*}}@test_variadic_plain_arr_idx +__attribute__((noinline)) void test_variadic_plain_arr_idx(struct Small arr[]) { + variadic_func(0, arr[0]); +} + +// SHARED-LABEL: define {{[^@]*}}@test_nested_member_plain_arr_idx +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_nested_member_plain_arr_idx(struct Container *c, struct Small arr[]) { + c->inner = arr[0]; +} + +// --- OPERAND FORM: *ap --- + +// SHARED-LABEL: define {{[^@]*}}@test_assign_plain_deref_ptr +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_assign_plain_deref_ptr(struct Small *dest, struct Small *ap) { + *dest = *ap; +} + +// SHARED-LABEL: define {{[^@]*}}@test_init_plain_deref_ptr +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_init_plain_deref_ptr(struct Small *ap) { + struct Small a = *ap; +} + +// SHARED-LABEL: define {{[^@]*}}@test_init_list_plain_deref_ptr +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_init_list_plain_deref_ptr(struct Small *ap) { + struct Small a[] = {*ap}; +} + +// SHARED-LABEL: define {{[^@]*}}@test_init_list_designate_plain_deref_ptr +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_init_list_designate_plain_deref_ptr(struct Small *ap) { + struct Small a[] = {[0] = *ap}; +} + +// SHARED-LABEL: define {{[^@]*}}@test_variadic_plain_deref_ptr +__attribute__((noinline)) void test_variadic_plain_deref_ptr(struct Small *ap) { + variadic_func(0, *ap); +} + +// SHARED-LABEL: define {{[^@]*}}@test_nested_member_plain_deref_ptr +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_nested_member_plain_deref_ptr(struct Container *c, struct Small *ap) { + c->inner = *ap; +} + +#ifdef __cplusplus +} // extern "C" +#endif + +// ============================================================================ +// TYPE VARIANT: atomic (C only) +// ============================================================================ + +#ifndef __cplusplus + +// --- OPERAND FORM: arr[idx] --- + +// C-LABEL: define {{[^@]*}}@test_assign_atomic_arr_idx +// C: call void @__ubsan_handle_type_mismatch_v1_abort +__attribute__((noinline)) void test_assign_atomic_arr_idx(struct Small *dest, _Atomic(struct Small) arr[]) { + *dest = arr[0]; +} + +// C-LABEL: define {{[^@]*}}@test_init_atomic_arr_idx +// C: call void @__ubsan_handle_type_mismatch_v1_abort +__attribute__((noinline)) void test_init_atomic_arr_idx(_Atomic(struct Small) arr[]) { + struct Small a = arr[0]; +} + +// C-LABEL: define {{[^@]*}}@test_init_list_atomic_arr_idx +// C: call void @__ubsan_handle_type_mismatch_v1_abort +__attribute__((noinline)) void test_init_list_atomic_arr_idx(_Atomic(struct Small) arr[]) { + struct Small a[] = {arr[0]}; +} + +// C-LABEL: define {{[^@]*}}@test_init_list_designate_atomic_arr_idx +// C: call void @__ubsan_handle_type_mismatch_v1_abort +__attribute__((noinline)) void test_init_list_designate_atomic_arr_idx(_Atomic(struct Small) arr[]) { + struct Small a[] = {[0] = arr[0]}; +} + +// C-LABEL: define {{[^@]*}}@test_variadic_atomic_arr_idx +__attribute__((noinline)) void test_variadic_atomic_arr_idx(_Atomic(struct Small) arr[]) { + variadic_func(0, arr[0]); +} + +// C-LABEL: define {{[^@]*}}@test_nested_member_atomic_arr_idx +// C: call void @__ubsan_handle_type_mismatch_v1_abort +__attribute__((noinline)) void test_nested_member_atomic_arr_idx(struct Container *c, _Atomic(struct Small) arr[]) { + c->inner = arr[0]; +} + +// C-LABEL: define {{[^@]*}}@test_lvalue_to_rvalue_atomic_arr_idx +// C: call void @__ubsan_handle_type_mismatch_v1_abort +__attribute__((noinline)) void test_lvalue_to_rvalue_atomic_arr_idx(_Atomic(struct Small) arr[]) { + (void)arr[0]; +} + +// --- OPERAND FORM: *ap --- + +// C-LABEL: define {{[^@]*}}@test_assign_atomic_deref_ptr +// C: call void @__ubsan_handle_type_mismatch_v1_abort +__attribute__((noinline)) void test_assign_atomic_deref_ptr(struct Small *dest, _Atomic(struct Small) *ap) { + *dest = *ap; +} + +// C-LABEL: define {{[^@]*}}@test_init_atomic_deref_ptr +// C: call void @__ubsan_handle_type_mismatch_v1_abort +__attribute__((noinline)) void test_init_atomic_deref_ptr(_Atomic(struct Small) *ap) { + struct Small a = *ap; +} + +// C-LABEL: define {{[^@]*}}@test_init_list_atomic_deref_ptr +// C: call void @__ubsan_handle_type_mismatch_v1_abort +__attribute__((noinline)) void test_init_list_atomic_deref_ptr(_Atomic(struct Small) *ap) { + struct Small a[] = {*ap}; +} + +// C-LABEL: define {{[^@]*}}@test_init_list_designate_atomic_deref_ptr +// C: call void @__ubsan_handle_type_mismatch_v1_abort +__attribute__((noinline)) void test_init_list_designate_atomic_deref_ptr(_Atomic(struct Small) *ap) { + struct Small a[] = {[0] = *ap}; +} + +// C-LABEL: define {{[^@]*}}@test_variadic_atomic_deref_ptr +__attribute__((noinline)) void test_variadic_atomic_deref_ptr(_Atomic(struct Small) *ap) { + variadic_func(0, *ap); +} + +// C-LABEL: define {{[^@]*}}@test_nested_member_atomic_deref_ptr +// C: call void @__ubsan_handle_type_mismatch_v1_abort +__attribute__((noinline)) void test_nested_member_atomic_deref_ptr(struct Container *c, _Atomic(struct Small) *ap) { + c->inner = *ap; +} + +// C-LABEL: define {{[^@]*}}@test_lvalue_to_rvalue_atomic_deref_ptr +// C: call void @__ubsan_handle_type_mismatch_v1_abort +__attribute__((noinline)) void test_lvalue_to_rvalue_atomic_deref_ptr(_Atomic(struct Small) *ap) { + (void)*ap; +} + +#endif // !__cplusplus + +// ============================================================================ +// TYPE VARIANT: volatile (C only) +// ============================================================================ + +#ifndef __cplusplus + +// --- OPERAND FORM: arr[idx] --- + +// C-LABEL: define {{[^@]*}}@test_assign_volatile_arr_idx +// C: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_assign_volatile_arr_idx(struct Small *dest, volatile struct Small arr[]) { + *dest = arr[0]; +} + +// C-LABEL: define {{[^@]*}}@test_init_volatile_arr_idx +// C: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_init_volatile_arr_idx(volatile struct Small arr[]) { + struct Small a = arr[0]; +} + +// C-LABEL: define {{[^@]*}}@test_init_list_volatile_arr_idx +// C: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_init_list_volatile_arr_idx(volatile struct Small arr[]) { + struct Small a[] = {arr[0]}; +} + +// C-LABEL: define {{[^@]*}}@test_init_list_designate_volatile_arr_idx +// C: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_init_list_designate_volatile_arr_idx(volatile struct Small arr[]) { + struct Small a[] = {[0] = arr[0]}; +} + +// C-LABEL: define {{[^@]*}}@test_variadic_volatile_arr_idx +__attribute__((noinline)) void test_variadic_volatile_arr_idx(volatile struct Small arr[]) { + variadic_func(0, arr[0]); +} + +// C-LABEL: define {{[^@]*}}@test_nested_member_volatile_arr_idx +// C: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_nested_member_volatile_arr_idx(struct Container *c, volatile struct Small arr[]) { + c->inner = arr[0]; +} + +// C-LABEL: define {{[^@]*}}@test_lvalue_to_rvalue_volatile_arr_idx +// C: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_lvalue_to_rvalue_volatile_arr_idx(volatile struct Small arr[]) { + (void)arr[0]; +} + +// --- OPERAND FORM: *ap --- + +// C-LABEL: define {{[^@]*}}@test_assign_volatile_deref_ptr +// C: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_assign_volatile_deref_ptr(struct Small *dest, volatile struct Small *ap) { + *dest = *ap; +} + +// C-LABEL: define {{[^@]*}}@test_init_volatile_deref_ptr +// C: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_init_volatile_deref_ptr(volatile struct Small *ap) { + struct Small a = *ap; +} + +// C-LABEL: define {{[^@]*}}@test_init_list_volatile_deref_ptr +// C: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_init_list_volatile_deref_ptr(volatile struct Small *ap) { + struct Small a[] = {*ap}; +} + +// C-LABEL: define {{[^@]*}}@test_init_list_designate_volatile_deref_ptr +// C: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_init_list_designate_volatile_deref_ptr(volatile struct Small *ap) { + struct Small a[] = {[0] = *ap}; +} + +// C-LABEL: define {{[^@]*}}@test_variadic_volatile_deref_ptr +__attribute__((noinline)) void test_variadic_volatile_deref_ptr(volatile struct Small *ap) { + variadic_func(0, *ap); +} + +// C-LABEL: define {{[^@]*}}@test_nested_member_volatile_deref_ptr +// C: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_nested_member_volatile_deref_ptr(struct Container *c, volatile struct Small *ap) { + c->inner = *ap; +} + +// C-LABEL: define {{[^@]*}}@test_lvalue_to_rvalue_volatile_deref_ptr +// C: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_lvalue_to_rvalue_volatile_deref_ptr(volatile struct Small *ap) { + (void)*ap; +} + +#endif // !__cplusplus + +// ============================================================================ +// C++ ONLY: Additional initialization and operation forms +// ============================================================================ + +#ifdef __cplusplus + +extern "C" { + +// --- OPERAND FORM: arr[idx] with plain type --- + +// CXX-LABEL: define {{[^@]*}}@test_cxx_init_direct_plain_arr_idx +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_init_direct_plain_arr_idx(struct Small arr[]) { + struct Small a(arr[0]); +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_init_brace_plain_arr_idx +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_init_brace_plain_arr_idx(struct Small arr[]) { + struct Small a{arr[0]}; +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_init_copy_list_plain_arr_idx +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_init_copy_list_plain_arr_idx(struct Small arr[]) { + struct Small a = {arr[0]}; +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_new_direct_plain_arr_idx +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_new_direct_plain_arr_idx(struct Small arr[]) { + struct Small *a = new struct Small(arr[0]); + delete a; +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_new_brace_plain_arr_idx +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_new_brace_plain_arr_idx(struct Small arr[]) { + struct Small *a = new struct Small{arr[0]}; + delete a; +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_functional_cast_plain_arr_idx +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_functional_cast_plain_arr_idx(struct Small arr[]) { + (void)Small(arr[0]); +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_functional_cast_brace_plain_arr_idx +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_functional_cast_brace_plain_arr_idx(struct Small arr[]) { + (void)Small{arr[0]}; +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_static_cast_plain_arr_idx +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_static_cast_plain_arr_idx(struct Small arr[]) { + (void)static_cast<struct Small>(arr[0]); +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_c_cast_plain_arr_idx +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_c_cast_plain_arr_idx(struct Small arr[]) { + (void)(struct Small)(arr[0]); +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_member_init_plain_arr_idx +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_member_init_plain_arr_idx(struct Small arr[]) { + (void)new SmallWrapper{arr[0]}; +} + +// --- OPERAND FORM: *ap with plain type --- + +// CXX-LABEL: define {{[^@]*}}@test_cxx_init_direct_plain_deref_ptr +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_init_direct_plain_deref_ptr(struct Small *ap) { + struct Small a(*ap); +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_init_brace_plain_deref_ptr +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_init_brace_plain_deref_ptr(struct Small *ap) { + struct Small a{*ap}; +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_init_copy_list_plain_deref_ptr +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_init_copy_list_plain_deref_ptr(struct Small *ap) { + struct Small a = {*ap}; +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_new_direct_plain_deref_ptr +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_new_direct_plain_deref_ptr(struct Small *ap) { + struct Small *a = new struct Small(*ap); + delete a; +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_new_brace_plain_deref_ptr +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_new_brace_plain_deref_ptr(struct Small *ap) { + struct Small *a = new struct Small{*ap}; + delete a; +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_functional_cast_plain_deref_ptr +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_functional_cast_plain_deref_ptr(struct Small *ap) { + (void)Small(*ap); +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_functional_cast_brace_plain_deref_ptr +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_functional_cast_brace_plain_deref_ptr(struct Small *ap) { + (void)Small{*ap}; +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_static_cast_plain_deref_ptr +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_static_cast_plain_deref_ptr(struct Small *ap) { + (void)static_cast<struct Small>(*ap); +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_c_cast_plain_deref_ptr +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_c_cast_plain_deref_ptr(struct Small *ap) { + (void)(struct Small)(*ap); +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_member_init_plain_deref_ptr +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_member_init_plain_deref_ptr(struct Small *ap) { + (void)new SmallWrapper{*ap}; +} + +// --- VARIADIC with plain type --- + +// CXX-LABEL: define {{[^@]*}}@test_cxx_variadic_plain_arr_idx +__attribute__((noinline)) void test_cxx_variadic_plain_arr_idx(struct Small arr[]) { + variadic_func(0, arr[0]); +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_variadic_plain_deref_ptr +__attribute__((noinline)) void test_cxx_variadic_plain_deref_ptr(struct Small *ap) { + variadic_func(0, *ap); +} + +// --- Explicit operator= calls --- + +// CXX-LABEL: define {{[^@]*}}@test_cxx_operator_assign_lhs_arr_idx +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_operator_assign_lhs_arr_idx(struct Small *dest, struct Small arr[]) { + dest->operator=(arr[0]); +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_operator_assign_lhs_deref_ptr +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_operator_assign_lhs_deref_ptr(struct Small *dest, struct Small *ap) { + dest->operator=(*ap); +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_operator_assign_obj_arr_idx +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_operator_assign_obj_arr_idx(struct Small arr[]) { + struct Small a; + a.operator=(arr[0]); +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_operator_assign_obj_deref_ptr +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_operator_assign_obj_deref_ptr(struct Small *ap) { + struct Small a; + a.operator=(*ap); +} + +} // extern "C" + +// --- Virtual base initialization (cannot be extern "C") --- +// Use a simple struct to ensure memcpy is used for the copy + +struct VirtualBaseSimple { + int x; +}; + +struct DerivedVirtualArrSimple : virtual VirtualBaseSimple { + __attribute__((noinline)) DerivedVirtualArrSimple(VirtualBaseSimple arr[]) : VirtualBaseSimple(arr[0]) {} +}; + +struct DerivedVirtualPtrSimple : virtual VirtualBaseSimple { + __attribute__((noinline)) DerivedVirtualPtrSimple(VirtualBaseSimple *ap) : VirtualBaseSimple(*ap) {} +}; + +// Force instantiation of constructors +// The constructors are emitted inline after their first use, so we check them +// in the order they appear: ArrSimple constructor, then wrapper for Ptr, then PtrSimple constructor + +extern "C" { + +// CXX-LABEL: define {{[^@]*}}@test_cxx_virtual_base_init_arr_idx +__attribute__((noinline)) void test_cxx_virtual_base_init_arr_idx(VirtualBaseSimple arr[]) { + DerivedVirtualArrSimple d(arr); +} + +} + +// Check the first constructor (DerivedVirtualArrSimple) - emitted after test_cxx_virtual_base_init_arr_idx +// CXX-LABEL: define {{[^@]*}}@_ZN23DerivedVirtualArrSimpleC1EP17VirtualBaseSimple +// CXX: call void @llvm.memcpy.p0.p0.i64 + +extern "C" { + +// CXX-LABEL: define {{[^@]*}}@test_cxx_virtual_base_init_deref_ptr +__attribute__((noinline)) void test_cxx_virtual_base_init_deref_ptr(VirtualBaseSimple *ap) { + DerivedVirtualPtrSimple d(ap); +} + +} + +// Check the second constructor (DerivedVirtualPtrSimple) - emitted after test_cxx_virtual_base_init_deref_ptr +// CXX-LABEL: define {{[^@]*}}@_ZN23DerivedVirtualPtrSimpleC1EP17VirtualBaseSimple +// CXX: call void @llvm.memcpy.p0.p0.i64 + +#endif // __cplusplus >From 704d9c60efab711d0b7c05674d5caa35777fbf5d Mon Sep 17 00:00:00 2001 From: vasu-ibm <[email protected]> Date: Mon, 19 Jan 2026 02:57:29 -0500 Subject: [PATCH 2/3] update ubsan-aggregate-null-align --- .../test/CodeGen/ubsan-aggregate-null-align.c | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/clang/test/CodeGen/ubsan-aggregate-null-align.c b/clang/test/CodeGen/ubsan-aggregate-null-align.c index da87f7bece163..a49ea2c08e3e9 100644 --- a/clang/test/CodeGen/ubsan-aggregate-null-align.c +++ b/clang/test/CodeGen/ubsan-aggregate-null-align.c @@ -95,6 +95,8 @@ __attribute__((noinline)) void test_nested_member_plain_deref_ptr(struct Contain // ============================================================================ // TYPE VARIANT: atomic (C only) +// NOTE: Atomic struct operations use atomic load/store instructions and do not +// go through EmitAggregateCopy, so UBSAN null/alignment checks are not emitted. // ============================================================================ #ifndef __cplusplus @@ -102,42 +104,43 @@ __attribute__((noinline)) void test_nested_member_plain_deref_ptr(struct Contain // --- OPERAND FORM: arr[idx] --- // C-LABEL: define {{[^@]*}}@test_assign_atomic_arr_idx -// C: call void @__ubsan_handle_type_mismatch_v1_abort +// C: load atomic i32 __attribute__((noinline)) void test_assign_atomic_arr_idx(struct Small *dest, _Atomic(struct Small) arr[]) { *dest = arr[0]; } // C-LABEL: define {{[^@]*}}@test_init_atomic_arr_idx -// C: call void @__ubsan_handle_type_mismatch_v1_abort +// C: load atomic i32 __attribute__((noinline)) void test_init_atomic_arr_idx(_Atomic(struct Small) arr[]) { struct Small a = arr[0]; } // C-LABEL: define {{[^@]*}}@test_init_list_atomic_arr_idx -// C: call void @__ubsan_handle_type_mismatch_v1_abort +// C: load atomic i32 __attribute__((noinline)) void test_init_list_atomic_arr_idx(_Atomic(struct Small) arr[]) { struct Small a[] = {arr[0]}; } // C-LABEL: define {{[^@]*}}@test_init_list_designate_atomic_arr_idx -// C: call void @__ubsan_handle_type_mismatch_v1_abort +// C: load atomic i32 __attribute__((noinline)) void test_init_list_designate_atomic_arr_idx(_Atomic(struct Small) arr[]) { struct Small a[] = {[0] = arr[0]}; } // C-LABEL: define {{[^@]*}}@test_variadic_atomic_arr_idx +// C: load atomic i32 __attribute__((noinline)) void test_variadic_atomic_arr_idx(_Atomic(struct Small) arr[]) { variadic_func(0, arr[0]); } // C-LABEL: define {{[^@]*}}@test_nested_member_atomic_arr_idx -// C: call void @__ubsan_handle_type_mismatch_v1_abort +// C: load atomic i32 __attribute__((noinline)) void test_nested_member_atomic_arr_idx(struct Container *c, _Atomic(struct Small) arr[]) { c->inner = arr[0]; } // C-LABEL: define {{[^@]*}}@test_lvalue_to_rvalue_atomic_arr_idx -// C: call void @__ubsan_handle_type_mismatch_v1_abort +// C: load atomic i32 __attribute__((noinline)) void test_lvalue_to_rvalue_atomic_arr_idx(_Atomic(struct Small) arr[]) { (void)arr[0]; } @@ -145,42 +148,43 @@ __attribute__((noinline)) void test_lvalue_to_rvalue_atomic_arr_idx(_Atomic(stru // --- OPERAND FORM: *ap --- // C-LABEL: define {{[^@]*}}@test_assign_atomic_deref_ptr -// C: call void @__ubsan_handle_type_mismatch_v1_abort +// C: load atomic i32 __attribute__((noinline)) void test_assign_atomic_deref_ptr(struct Small *dest, _Atomic(struct Small) *ap) { *dest = *ap; } // C-LABEL: define {{[^@]*}}@test_init_atomic_deref_ptr -// C: call void @__ubsan_handle_type_mismatch_v1_abort +// C: load atomic i32 __attribute__((noinline)) void test_init_atomic_deref_ptr(_Atomic(struct Small) *ap) { struct Small a = *ap; } // C-LABEL: define {{[^@]*}}@test_init_list_atomic_deref_ptr -// C: call void @__ubsan_handle_type_mismatch_v1_abort +// C: load atomic i32 __attribute__((noinline)) void test_init_list_atomic_deref_ptr(_Atomic(struct Small) *ap) { struct Small a[] = {*ap}; } // C-LABEL: define {{[^@]*}}@test_init_list_designate_atomic_deref_ptr -// C: call void @__ubsan_handle_type_mismatch_v1_abort +// C: load atomic i32 __attribute__((noinline)) void test_init_list_designate_atomic_deref_ptr(_Atomic(struct Small) *ap) { struct Small a[] = {[0] = *ap}; } // C-LABEL: define {{[^@]*}}@test_variadic_atomic_deref_ptr +// C: load atomic i32 __attribute__((noinline)) void test_variadic_atomic_deref_ptr(_Atomic(struct Small) *ap) { variadic_func(0, *ap); } // C-LABEL: define {{[^@]*}}@test_nested_member_atomic_deref_ptr -// C: call void @__ubsan_handle_type_mismatch_v1_abort +// C: load atomic i32 __attribute__((noinline)) void test_nested_member_atomic_deref_ptr(struct Container *c, _Atomic(struct Small) *ap) { c->inner = *ap; } // C-LABEL: define {{[^@]*}}@test_lvalue_to_rvalue_atomic_deref_ptr -// C: call void @__ubsan_handle_type_mismatch_v1_abort +// C: load atomic i32 __attribute__((noinline)) void test_lvalue_to_rvalue_atomic_deref_ptr(_Atomic(struct Small) *ap) { (void)*ap; } >From 4abb7d001d11ccae998f626da9e8515d41ad8a09 Mon Sep 17 00:00:00 2001 From: vasu-ibm <[email protected]> Date: Tue, 3 Feb 2026 02:55:18 -0500 Subject: [PATCH 3/3] add arrays bounds check --- .../test/CodeGen/ubsan-aggregate-null-align.c | 205 +++++++++++++----- 1 file changed, 151 insertions(+), 54 deletions(-) diff --git a/clang/test/CodeGen/ubsan-aggregate-null-align.c b/clang/test/CodeGen/ubsan-aggregate-null-align.c index a49ea2c08e3e9..706ac3d4d6055 100644 --- a/clang/test/CodeGen/ubsan-aggregate-null-align.c +++ b/clang/test/CodeGen/ubsan-aggregate-null-align.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=null,alignment -std=c11 -O0 %s -o %t.c.ll && FileCheck %s --check-prefixes=C,SHARED < %t.c.ll -// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=null,alignment -std=c++17 -x c++ -O0 %s -o %t.cxx.ll && FileCheck %s --check-prefixes=CXX,SHARED < %t.cxx.ll +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=null,alignment,bounds -std=c11 -O0 %s -o %t.c.ll && FileCheck %s --check-prefixes=C,SHARED < %t.c.ll +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fsanitize=null,alignment,bounds -std=c++17 -x c++ -O0 %s -o %t.cxx.ll && FileCheck %s --check-prefixes=CXX,SHARED < %t.cxx.ll struct Small { int x; }; struct Container { struct Small inner; }; @@ -19,36 +19,30 @@ extern "C" { // SHARED-LABEL: define {{[^@]*}}@test_assign_plain_arr_idx // SHARED: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_assign_plain_arr_idx(struct Small *dest, struct Small arr[]) { +__attribute__((noinline)) void test_assign_plain_arr_idx(struct Small *dest, struct Small arr[4]) { *dest = arr[0]; } // SHARED-LABEL: define {{[^@]*}}@test_init_plain_arr_idx // SHARED: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_init_plain_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_init_plain_arr_idx(struct Small arr[4]) { struct Small a = arr[0]; } // SHARED-LABEL: define {{[^@]*}}@test_init_list_plain_arr_idx // SHARED: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_init_list_plain_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_init_list_plain_arr_idx(struct Small arr[4]) { struct Small a[] = {arr[0]}; } -// SHARED-LABEL: define {{[^@]*}}@test_init_list_designate_plain_arr_idx -// SHARED: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_init_list_designate_plain_arr_idx(struct Small arr[]) { - struct Small a[] = {[0] = arr[0]}; -} - // SHARED-LABEL: define {{[^@]*}}@test_variadic_plain_arr_idx -__attribute__((noinline)) void test_variadic_plain_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_variadic_plain_arr_idx(struct Small arr[4]) { variadic_func(0, arr[0]); } // SHARED-LABEL: define {{[^@]*}}@test_nested_member_plain_arr_idx // SHARED: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_nested_member_plain_arr_idx(struct Container *c, struct Small arr[]) { +__attribute__((noinline)) void test_nested_member_plain_arr_idx(struct Container *c, struct Small arr[4]) { c->inner = arr[0]; } @@ -72,12 +66,6 @@ __attribute__((noinline)) void test_init_list_plain_deref_ptr(struct Small *ap) struct Small a[] = {*ap}; } -// SHARED-LABEL: define {{[^@]*}}@test_init_list_designate_plain_deref_ptr -// SHARED: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_init_list_designate_plain_deref_ptr(struct Small *ap) { - struct Small a[] = {[0] = *ap}; -} - // SHARED-LABEL: define {{[^@]*}}@test_variadic_plain_deref_ptr __attribute__((noinline)) void test_variadic_plain_deref_ptr(struct Small *ap) { variadic_func(0, *ap); @@ -89,14 +77,92 @@ __attribute__((noinline)) void test_nested_member_plain_deref_ptr(struct Contain c->inner = *ap; } +// ============================================================================ +// ARRAY BOUNDS CHECKING +// Tests for array out-of-bounds access, including past-the-end pointer cases. +// Currently, bounds checking triggers for invalid indices but the planned fix +// will also trigger when indexing generates a past-the-end pointer. +// ============================================================================ + +// --- In-bounds access (index 0 of array[4]) - should NOT trigger bounds error --- + +// SHARED-LABEL: define {{[^@]*}}@test_bounds_inbounds_idx0 +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_bounds_inbounds_idx0(struct Small *dest, struct Small arr[4]) { + *dest = arr[0]; +} + +// --- In-bounds access (index 3, last valid element of array[4]) --- + +// SHARED-LABEL: define {{[^@]*}}@test_bounds_inbounds_idx3 +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_bounds_inbounds_idx3(struct Small *dest, struct Small arr[4]) { + *dest = arr[3]; +} + +// --- Out-of-bounds access (index 4, past-the-end of array[4]) --- +// This generates the past-the-end pointer. Currently no bounds check is emitted +// for this case; the planned fix will add checking for past-the-end access. + +// SHARED-LABEL: define {{[^@]*}}@test_bounds_oob_past_end +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_bounds_oob_past_end(struct Small *dest, struct Small arr[4]) { + *dest = arr[4]; +} + +// --- Out-of-bounds access (index 5, clearly beyond array[4]) --- + +// SHARED-LABEL: define {{[^@]*}}@test_bounds_oob_beyond +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_bounds_oob_beyond(struct Small *dest, struct Small arr[4]) { + *dest = arr[5]; +} + +// --- Dynamic index bounds checking --- + +// SHARED-LABEL: define {{[^@]*}}@test_bounds_dynamic_idx +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_bounds_dynamic_idx(struct Small *dest, struct Small arr[4], int idx) { + *dest = arr[idx]; +} + +// --- Bounds checking with initialization --- + +// SHARED-LABEL: define {{[^@]*}}@test_bounds_init_past_end +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_bounds_init_past_end(struct Small arr[4]) { + struct Small a = arr[4]; +} + +// --- Bounds checking with nested member assignment --- + +// SHARED-LABEL: define {{[^@]*}}@test_bounds_nested_past_end +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_bounds_nested_past_end(struct Container *c, struct Small arr[4]) { + c->inner = arr[4]; +} + +// --- Bounds checking in initializer list --- + +// SHARED-LABEL: define {{[^@]*}}@test_bounds_init_list_past_end +// SHARED: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_bounds_init_list_past_end(struct Small arr[4]) { + struct Small a[] = {arr[4]}; +} + +// --- Bounds checking with variadic function --- + +// SHARED-LABEL: define {{[^@]*}}@test_bounds_variadic_past_end +__attribute__((noinline)) void test_bounds_variadic_past_end(struct Small arr[4]) { + variadic_func(0, arr[4]); +} + #ifdef __cplusplus } // extern "C" #endif // ============================================================================ // TYPE VARIANT: atomic (C only) -// NOTE: Atomic struct operations use atomic load/store instructions and do not -// go through EmitAggregateCopy, so UBSAN null/alignment checks are not emitted. // ============================================================================ #ifndef __cplusplus @@ -105,43 +171,43 @@ __attribute__((noinline)) void test_nested_member_plain_deref_ptr(struct Contain // C-LABEL: define {{[^@]*}}@test_assign_atomic_arr_idx // C: load atomic i32 -__attribute__((noinline)) void test_assign_atomic_arr_idx(struct Small *dest, _Atomic(struct Small) arr[]) { +__attribute__((noinline)) void test_assign_atomic_arr_idx(struct Small *dest, _Atomic(struct Small) arr[4]) { *dest = arr[0]; } // C-LABEL: define {{[^@]*}}@test_init_atomic_arr_idx // C: load atomic i32 -__attribute__((noinline)) void test_init_atomic_arr_idx(_Atomic(struct Small) arr[]) { +__attribute__((noinline)) void test_init_atomic_arr_idx(_Atomic(struct Small) arr[4]) { struct Small a = arr[0]; } // C-LABEL: define {{[^@]*}}@test_init_list_atomic_arr_idx // C: load atomic i32 -__attribute__((noinline)) void test_init_list_atomic_arr_idx(_Atomic(struct Small) arr[]) { +__attribute__((noinline)) void test_init_list_atomic_arr_idx(_Atomic(struct Small) arr[4]) { struct Small a[] = {arr[0]}; } // C-LABEL: define {{[^@]*}}@test_init_list_designate_atomic_arr_idx // C: load atomic i32 -__attribute__((noinline)) void test_init_list_designate_atomic_arr_idx(_Atomic(struct Small) arr[]) { +__attribute__((noinline)) void test_init_list_designate_atomic_arr_idx(_Atomic(struct Small) arr[4]) { struct Small a[] = {[0] = arr[0]}; } // C-LABEL: define {{[^@]*}}@test_variadic_atomic_arr_idx // C: load atomic i32 -__attribute__((noinline)) void test_variadic_atomic_arr_idx(_Atomic(struct Small) arr[]) { +__attribute__((noinline)) void test_variadic_atomic_arr_idx(_Atomic(struct Small) arr[4]) { variadic_func(0, arr[0]); } // C-LABEL: define {{[^@]*}}@test_nested_member_atomic_arr_idx // C: load atomic i32 -__attribute__((noinline)) void test_nested_member_atomic_arr_idx(struct Container *c, _Atomic(struct Small) arr[]) { +__attribute__((noinline)) void test_nested_member_atomic_arr_idx(struct Container *c, _Atomic(struct Small) arr[4]) { c->inner = arr[0]; } // C-LABEL: define {{[^@]*}}@test_lvalue_to_rvalue_atomic_arr_idx // C: load atomic i32 -__attribute__((noinline)) void test_lvalue_to_rvalue_atomic_arr_idx(_Atomic(struct Small) arr[]) { +__attribute__((noinline)) void test_lvalue_to_rvalue_atomic_arr_idx(_Atomic(struct Small) arr[4]) { (void)arr[0]; } @@ -189,54 +255,50 @@ __attribute__((noinline)) void test_lvalue_to_rvalue_atomic_deref_ptr(_Atomic(st (void)*ap; } -#endif // !__cplusplus - // ============================================================================ // TYPE VARIANT: volatile (C only) // ============================================================================ -#ifndef __cplusplus - // --- OPERAND FORM: arr[idx] --- // C-LABEL: define {{[^@]*}}@test_assign_volatile_arr_idx // C: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_assign_volatile_arr_idx(struct Small *dest, volatile struct Small arr[]) { +__attribute__((noinline)) void test_assign_volatile_arr_idx(struct Small *dest, volatile struct Small arr[4]) { *dest = arr[0]; } // C-LABEL: define {{[^@]*}}@test_init_volatile_arr_idx // C: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_init_volatile_arr_idx(volatile struct Small arr[]) { +__attribute__((noinline)) void test_init_volatile_arr_idx(volatile struct Small arr[4]) { struct Small a = arr[0]; } // C-LABEL: define {{[^@]*}}@test_init_list_volatile_arr_idx // C: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_init_list_volatile_arr_idx(volatile struct Small arr[]) { +__attribute__((noinline)) void test_init_list_volatile_arr_idx(volatile struct Small arr[4]) { struct Small a[] = {arr[0]}; } // C-LABEL: define {{[^@]*}}@test_init_list_designate_volatile_arr_idx // C: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_init_list_designate_volatile_arr_idx(volatile struct Small arr[]) { +__attribute__((noinline)) void test_init_list_designate_volatile_arr_idx(volatile struct Small arr[4]) { struct Small a[] = {[0] = arr[0]}; } // C-LABEL: define {{[^@]*}}@test_variadic_volatile_arr_idx -__attribute__((noinline)) void test_variadic_volatile_arr_idx(volatile struct Small arr[]) { +__attribute__((noinline)) void test_variadic_volatile_arr_idx(volatile struct Small arr[4]) { variadic_func(0, arr[0]); } // C-LABEL: define {{[^@]*}}@test_nested_member_volatile_arr_idx // C: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_nested_member_volatile_arr_idx(struct Container *c, volatile struct Small arr[]) { +__attribute__((noinline)) void test_nested_member_volatile_arr_idx(struct Container *c, volatile struct Small arr[4]) { c->inner = arr[0]; } // C-LABEL: define {{[^@]*}}@test_lvalue_to_rvalue_volatile_arr_idx // C: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_lvalue_to_rvalue_volatile_arr_idx(volatile struct Small arr[]) { +__attribute__((noinline)) void test_lvalue_to_rvalue_volatile_arr_idx(volatile struct Small arr[4]) { (void)arr[0]; } @@ -283,6 +345,20 @@ __attribute__((noinline)) void test_lvalue_to_rvalue_volatile_deref_ptr(volatile (void)*ap; } +// --- Designated initializers (C only) --- + +// C-LABEL: define {{[^@]*}}@test_init_list_designate_plain_arr_idx +// C: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_init_list_designate_plain_arr_idx(struct Small arr[4]) { + struct Small a[] = {[0] = arr[0]}; +} + +// C-LABEL: define {{[^@]*}}@test_init_list_designate_plain_deref_ptr +// C: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_init_list_designate_plain_deref_ptr(struct Small *ap) { + struct Small a[] = {[0] = *ap}; +} + #endif // !__cplusplus // ============================================================================ @@ -297,63 +373,63 @@ extern "C" { // CXX-LABEL: define {{[^@]*}}@test_cxx_init_direct_plain_arr_idx // CXX: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_cxx_init_direct_plain_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_cxx_init_direct_plain_arr_idx(struct Small arr[4]) { struct Small a(arr[0]); } // CXX-LABEL: define {{[^@]*}}@test_cxx_init_brace_plain_arr_idx // CXX: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_cxx_init_brace_plain_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_cxx_init_brace_plain_arr_idx(struct Small arr[4]) { struct Small a{arr[0]}; } // CXX-LABEL: define {{[^@]*}}@test_cxx_init_copy_list_plain_arr_idx // CXX: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_cxx_init_copy_list_plain_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_cxx_init_copy_list_plain_arr_idx(struct Small arr[4]) { struct Small a = {arr[0]}; } // CXX-LABEL: define {{[^@]*}}@test_cxx_new_direct_plain_arr_idx // CXX: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_cxx_new_direct_plain_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_cxx_new_direct_plain_arr_idx(struct Small arr[4]) { struct Small *a = new struct Small(arr[0]); delete a; } // CXX-LABEL: define {{[^@]*}}@test_cxx_new_brace_plain_arr_idx // CXX: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_cxx_new_brace_plain_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_cxx_new_brace_plain_arr_idx(struct Small arr[4]) { struct Small *a = new struct Small{arr[0]}; delete a; } // CXX-LABEL: define {{[^@]*}}@test_cxx_functional_cast_plain_arr_idx // CXX: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_cxx_functional_cast_plain_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_cxx_functional_cast_plain_arr_idx(struct Small arr[4]) { (void)Small(arr[0]); } // CXX-LABEL: define {{[^@]*}}@test_cxx_functional_cast_brace_plain_arr_idx // CXX: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_cxx_functional_cast_brace_plain_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_cxx_functional_cast_brace_plain_arr_idx(struct Small arr[4]) { (void)Small{arr[0]}; } // CXX-LABEL: define {{[^@]*}}@test_cxx_static_cast_plain_arr_idx // CXX: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_cxx_static_cast_plain_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_cxx_static_cast_plain_arr_idx(struct Small arr[4]) { (void)static_cast<struct Small>(arr[0]); } // CXX-LABEL: define {{[^@]*}}@test_cxx_c_cast_plain_arr_idx // CXX: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_cxx_c_cast_plain_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_cxx_c_cast_plain_arr_idx(struct Small arr[4]) { (void)(struct Small)(arr[0]); } // CXX-LABEL: define {{[^@]*}}@test_cxx_member_init_plain_arr_idx // CXX: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_cxx_member_init_plain_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_cxx_member_init_plain_arr_idx(struct Small arr[4]) { (void)new SmallWrapper{arr[0]}; } @@ -424,7 +500,7 @@ __attribute__((noinline)) void test_cxx_member_init_plain_deref_ptr(struct Small // --- VARIADIC with plain type --- // CXX-LABEL: define {{[^@]*}}@test_cxx_variadic_plain_arr_idx -__attribute__((noinline)) void test_cxx_variadic_plain_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_cxx_variadic_plain_arr_idx(struct Small arr[4]) { variadic_func(0, arr[0]); } @@ -437,7 +513,7 @@ __attribute__((noinline)) void test_cxx_variadic_plain_deref_ptr(struct Small *a // CXX-LABEL: define {{[^@]*}}@test_cxx_operator_assign_lhs_arr_idx // CXX: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_cxx_operator_assign_lhs_arr_idx(struct Small *dest, struct Small arr[]) { +__attribute__((noinline)) void test_cxx_operator_assign_lhs_arr_idx(struct Small *dest, struct Small arr[4]) { dest->operator=(arr[0]); } @@ -449,7 +525,7 @@ __attribute__((noinline)) void test_cxx_operator_assign_lhs_deref_ptr(struct Sma // CXX-LABEL: define {{[^@]*}}@test_cxx_operator_assign_obj_arr_idx // CXX: call void @llvm.memcpy.p0.p0.i64 -__attribute__((noinline)) void test_cxx_operator_assign_obj_arr_idx(struct Small arr[]) { +__attribute__((noinline)) void test_cxx_operator_assign_obj_arr_idx(struct Small arr[4]) { struct Small a; a.operator=(arr[0]); } @@ -461,6 +537,27 @@ __attribute__((noinline)) void test_cxx_operator_assign_obj_deref_ptr(struct Sma a.operator=(*ap); } +// --- C++ bounds checking with past-the-end access --- + +// CXX-LABEL: define {{[^@]*}}@test_cxx_bounds_init_direct_past_end +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_bounds_init_direct_past_end(struct Small arr[4]) { + struct Small a(arr[4]); +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_bounds_init_brace_past_end +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_bounds_init_brace_past_end(struct Small arr[4]) { + struct Small a{arr[4]}; +} + +// CXX-LABEL: define {{[^@]*}}@test_cxx_bounds_new_past_end +// CXX: call void @llvm.memcpy.p0.p0.i64 +__attribute__((noinline)) void test_cxx_bounds_new_past_end(struct Small arr[4]) { + struct Small *a = new struct Small(arr[4]); + delete a; +} + } // extern "C" // --- Virtual base initialization (cannot be extern "C") --- @@ -471,7 +568,7 @@ struct VirtualBaseSimple { }; struct DerivedVirtualArrSimple : virtual VirtualBaseSimple { - __attribute__((noinline)) DerivedVirtualArrSimple(VirtualBaseSimple arr[]) : VirtualBaseSimple(arr[0]) {} + __attribute__((noinline)) DerivedVirtualArrSimple(VirtualBaseSimple arr[4]) : VirtualBaseSimple(arr[0]) {} }; struct DerivedVirtualPtrSimple : virtual VirtualBaseSimple { @@ -485,7 +582,7 @@ struct DerivedVirtualPtrSimple : virtual VirtualBaseSimple { extern "C" { // CXX-LABEL: define {{[^@]*}}@test_cxx_virtual_base_init_arr_idx -__attribute__((noinline)) void test_cxx_virtual_base_init_arr_idx(VirtualBaseSimple arr[]) { +__attribute__((noinline)) void test_cxx_virtual_base_init_arr_idx(VirtualBaseSimple arr[4]) { DerivedVirtualArrSimple d(arr); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
