================
@@ -1,235 +1,172 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm 
-fsanitize=null,alignment,array-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,array-bounds -std=c++17 -x c++ -O0 %s -o %t.cxx.ll && 
FileCheck %s --check-prefixes=CXX,SHARED < %t.cxx.ll
-
-// Precommit test for null, alignment, and array-bounds checks on aggregates.
-// This test documents current behavior: memcpy is called but source operand 
is not checked
-// for null/alignment (unlike scalar types). Array bounds checks exist for 
local
-// arrays but not for past-the-end pointer accesses via parameters.
-
-struct Small { int x; };
-struct Container { struct Small inner; };
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm 
-fsanitize=null,alignment,array-bounds -std=c11 -O0 %s -o - | FileCheck %s 
--check-prefixes=CHECK,C
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm 
-fsanitize=null,alignment,array-bounds -std=c++17 -x c++ -O0 %s -o - | 
FileCheck %s --check-prefixes=CHECK,CXX
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm 
-fsanitize=null,alignment,array-bounds -std=c11 -O0 -DUSE_UNION %s -o - | 
FileCheck %s --check-prefixes=CHECK,C
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm 
-fsanitize=null,alignment,array-bounds -std=c++17 -x c++ -O0 -DUSE_UNION %s -o 
- | FileCheck %s --check-prefixes=CHECK,CXX
+
+#ifdef USE_UNION
+union Agg { int x; };
+#define AGG union Agg
+#else
+struct Agg { int x; };
+#define AGG struct Agg
+#endif
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-// Plain type - arr[idx] operand form (known bounds)
-
-// SHARED-LABEL: define {{[^@]*}}@test_assign_plain_arr_idx
-// SHARED: [[ARR:%.*]] = load ptr, ptr %arr.addr
-// SHARED: [[SRC:%.*]] = getelementptr inbounds %struct.Small, ptr [[ARR]], 
i64 0
-// SHARED-NOT: call void @__ubsan_handle_type_mismatch_v1_abort
-// SHARED-NOT: icmp ne ptr [[SRC]], null
-// SHARED: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.*}}, ptr align 4 
[[SRC]], i64 4, i1 false)
-__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: [[ARR:%.*]] = load ptr, ptr %arr.addr
-// SHARED: [[SRC:%.*]] = getelementptr inbounds %struct.Small, ptr [[ARR]], 
i64 0
-// SHARED-NOT: call void @__ubsan_handle_type_mismatch_v1_abort
-// SHARED-NOT: icmp ne ptr [[SRC]], null
-// SHARED: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.*}}, ptr align 4 
[[SRC]], i64 4, i1 false)
-__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: [[ARR:%.*]] = load ptr, ptr %arr.addr
-// SHARED: [[SRC:%.*]] = getelementptr inbounds %struct.Small, ptr [[ARR]], 
i64 0
-// SHARED-NOT: call void @__ubsan_handle_type_mismatch_v1_abort
-// SHARED-NOT: icmp ne ptr [[SRC]], null
-// SHARED: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.*}}, ptr align 4 
[[SRC]], i64 4, i1 false)
-__attribute__((noinline)) void test_init_list_plain_arr_idx(struct Small 
arr[4]) {
-  struct Small a[] = {arr[0]};
-}
-
-// SHARED-LABEL: define {{[^@]*}}@test_nested_member_plain_arr_idx
-// SHARED: call void @__ubsan_handle_type_mismatch_v1_abort
-// SHARED: call void @llvm.memcpy.p0.p0.i64
-__attribute__((noinline)) void test_nested_member_plain_arr_idx(struct 
Container *c, struct Small arr[4]) {
-  c->inner = arr[0];
-}
-
-// Plain type - *ap operand form
-
-// SHARED-LABEL: define {{[^@]*}}@test_assign_plain_deref_ptr
-// SHARED: [[SRC:%.*]] = load ptr, ptr %ap.addr
-// SHARED-NOT: call void @__ubsan_handle_type_mismatch_v1_abort
-// SHARED-NOT: icmp ne ptr [[SRC]], null
-// SHARED: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.*}}, ptr align 4 
[[SRC]], i64 4, i1 false)
-__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: [[SRC:%.*]] = load ptr, ptr %ap.addr
-// SHARED-NOT: call void @__ubsan_handle_type_mismatch_v1_abort
-// SHARED-NOT: icmp ne ptr [[SRC]], null
-// SHARED: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.*}}, ptr align 4 
[[SRC]], i64 4, i1 false)
-__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: [[SRC:%.*]] = load ptr, ptr %ap.addr
-// SHARED-NOT: call void @__ubsan_handle_type_mismatch_v1_abort
-// SHARED-NOT: icmp ne ptr [[SRC]], null
-// SHARED: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.*}}, ptr align 4 
[[SRC]], i64 4, i1 false)
-__attribute__((noinline)) void test_init_list_plain_deref_ptr(struct Small 
*ap) {
-  struct Small a[] = {*ap};
-}
-
-// SHARED-LABEL: define {{[^@]*}}@test_nested_member_plain_deref_ptr
-// SHARED: call void @__ubsan_handle_type_mismatch_v1_abort
-// 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;
-}
-
-// Misaligned aggregate access
-
-// SHARED-LABEL: define {{[^@]*}}@test_misaligned_access
-// SHARED-NOT: call void @__ubsan_handle_type_mismatch_v1_abort
-// SHARED: call void @llvm.memcpy
-__attribute__((noinline)) void test_misaligned_access(struct Small *dest, char 
*buf) {
-  struct Small *p = (struct Small *)(buf + 1);  // Misaligned
-  *dest = *p;
-}
-
-// Array bounds: out-of-bounds on local array
-
-// SHARED-LABEL: define {{[^@]*}}@test_local_array_oob
-// SHARED: call void @__ubsan_handle_out_of_bounds_abort
-// SHARED-NOT: call void @__ubsan_handle_type_mismatch_v1_abort
-// SHARED: call void @llvm.memcpy.p0.p0.i64
-__attribute__((noinline)) void test_local_array_oob(struct Small *dest) {
-  struct Small arr[4];
-  *dest = arr[5];
-}
-
-// Array bounds: past-the-end via parameter
-
-// SHARED-LABEL: define {{[^@]*}}@test_past_the_end_arr_idx
-// SHARED: [[ARR:%.*]] = load ptr, ptr %arr.addr
-// SHARED: [[SRC:%.*]] = getelementptr inbounds %struct.Small, ptr [[ARR]], 
i64 4
-// SHARED-NOT: call void @__ubsan_handle_out_of_bounds_abort
-// SHARED-NOT: call void @__ubsan_handle_type_mismatch_v1_abort
-// SHARED-NOT: icmp ne ptr [[SRC]], null
-// SHARED: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.*}}, ptr align 4 
[[SRC]], i64 4, i1 false)
-__attribute__((noinline)) void test_past_the_end_arr_idx(struct Small *dest, 
struct Small arr[4]) {
-  *dest = arr[4];
-}
-
-// SHARED-LABEL: define {{[^@]*}}@test_past_the_end_init
-// SHARED: [[ARR:%.*]] = load ptr, ptr %arr.addr
-// SHARED: [[SRC:%.*]] = getelementptr inbounds %struct.Small, ptr [[ARR]], 
i64 4
-// SHARED-NOT: call void @__ubsan_handle_out_of_bounds_abort
-// SHARED-NOT: call void @__ubsan_handle_type_mismatch_v1_abort
-// SHARED-NOT: icmp ne ptr [[SRC]], null
-// SHARED: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.*}}, ptr align 4 
[[SRC]], i64 4, i1 false)
-__attribute__((noinline)) void test_past_the_end_init(struct Small arr[4]) {
-  struct Small a = arr[4];
+// LHS checks - C only
+
+// C-LABEL: define {{.*}}@test_lhs_ptrcheck_deref(
+// C: [[DEST:%.*]] = load ptr, ptr %dest.addr
+// C-NEXT: [[CMP:%.*]] = icmp ne ptr [[DEST]], null, !nosanitize
+// C-NEXT: [[INT:%.*]] = ptrtoint ptr [[DEST]] to i64, !nosanitize
+// C-NEXT: [[AND:%.*]] = and i64 [[INT]], 3, !nosanitize
+// C-NEXT: [[ALIGN:%.*]] = icmp eq i64 [[AND]], 0, !nosanitize
+// C-NEXT: [[OK:%.*]] = and i1 [[CMP]], [[ALIGN]], !nosanitize
+// C-NEXT: br i1 [[OK]], label %cont, label %handler.type_mismatch
+// C: handler.type_mismatch:
+// C-NEXT: call void @__ubsan_handle_type_mismatch_v1_abort
+// C: call void @llvm.memcpy
+void test_lhs_ptrcheck_deref(AGG *dest) {
+  AGG local = {0};
+  *dest = local;
+}
+
+// C-LABEL: define {{.*}}@test_lhs_ptrcheck_subscript(
+// C: [[ARR:%.*]] = load ptr, ptr %arr.addr
+// C-NEXT: [[DEST:%.*]] = getelementptr inbounds %{{(struct|union)}}.Agg, ptr 
[[ARR]], i64 0
+// C-NEXT: [[CMP:%.*]] = icmp ne ptr [[DEST]], null, !nosanitize
+// C: handler.type_mismatch:
+// C-NEXT: call void @__ubsan_handle_type_mismatch_v1_abort
+// C: call void @llvm.memcpy
+void test_lhs_ptrcheck_subscript(AGG arr[4]) {
+  AGG local = {0};
+  arr[0] = local;
+}
+
+// RHS checks - both C and C++
+
+// CHECK-LABEL: define {{.*}}@test_rhs_ptrcheck_deref(
+// CHECK: [[SRC:%.*]] = load ptr, ptr %src.addr
+// CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[SRC]], null, !nosanitize
+// CHECK-NEXT: [[INT:%.*]] = ptrtoint ptr [[SRC]] to i64, !nosanitize
+// CHECK-NEXT: [[AND:%.*]] = and i64 [[INT]], 3, !nosanitize
+// CHECK-NEXT: [[ALIGN:%.*]] = icmp eq i64 [[AND]], 0, !nosanitize
+// CHECK-NEXT: [[OK:%.*]] = and i1 [[CMP]], [[ALIGN]], !nosanitize
+// CHECK-NEXT: br i1 [[OK]], label %cont, label %handler.type_mismatch
+// CHECK: handler.type_mismatch:
+// CHECK-NEXT: call void @__ubsan_handle_type_mismatch_v1_abort
+// CHECK: cont:
+// CHECK-NEXT: call void @llvm.memcpy
+void test_rhs_ptrcheck_deref(AGG *src) {
+  AGG local;
+  local = *src;
+  (void)local;
+}
+
+// CHECK-LABEL: define {{.*}}@test_rhs_ptrcheck_subscript(
+// CHECK: [[ARR:%.*]] = load ptr, ptr %arr.addr
+// CHECK-NEXT: [[SRC:%.*]] = getelementptr inbounds %{{(struct|union)}}.Agg, 
ptr [[ARR]], i64 0
+// CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[SRC]], null, !nosanitize
+// CHECK: handler.type_mismatch:
+// CHECK-NEXT: call void @__ubsan_handle_type_mismatch_v1_abort
+// CHECK: call void @llvm.memcpy
+void test_rhs_ptrcheck_subscript(AGG arr[4]) {
+  AGG local;
+  local = arr[0];
+  (void)local;
+}
+
+// RHS cases - handler call only
+
+// CHECK-LABEL: define {{.*}}@test_init_from_ptr(
+// CHECK: handler.type_mismatch:
+// CHECK-NEXT: call void @__ubsan_handle_type_mismatch_v1_abort
+// CHECK: call void @llvm.memcpy
+void test_init_from_ptr(AGG *src) {
+  AGG local = *src;
+  (void)local;
+}
+
+// CHECK-LABEL: define {{.*}}@test_init_from_array(
+// CHECK: handler.type_mismatch:
+// CHECK-NEXT: call void @__ubsan_handle_type_mismatch_v1_abort
+// CHECK: call void @llvm.memcpy
+void test_init_from_array(AGG arr[4]) {
+  AGG local = arr[0];
+  (void)local;
+}
+
+// Array bounds - out-of-bounds access (RHS)
+
+// CHECK-LABEL: define {{.*}}@test_oob_rhs(
+// CHECK: br i1 {{(true|false)}}, label %cont, label %handler.out_of_bounds
+// CHECK: handler.out_of_bounds:
+// CHECK-NEXT: call void @__ubsan_handle_out_of_bounds_abort
+// CHECK: handler.type_mismatch:
+// CHECK-NEXT: call void @__ubsan_handle_type_mismatch_v1_abort
+// CHECK: call void @llvm.memcpy
+void test_oob_rhs(void) {
+  AGG arr[4];
+  AGG local;
+  local = arr[4];
+  (void)local;
+}
+
+// Array bounds - out-of-bounds access (LHS)
+
+// CHECK-LABEL: define {{.*}}@test_oob_lhs(
+// CHECK: br i1 {{(true|false)}}, label %cont, label %handler.out_of_bounds
+// CHECK: handler.out_of_bounds:
+// CHECK-NEXT: call void @__ubsan_handle_out_of_bounds_abort
+// C: handler.type_mismatch:
+// C-NEXT: call void @__ubsan_handle_type_mismatch_v1_abort
----------------
vasu-the-sharma wrote:

Similar to above, `handler.type_mismatch` is the `LHS` check which is `C-`only. 
The `OOB` part uses `CHECK:` since it fires in both.

https://github.com/llvm/llvm-project/pull/190739
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to