void created this revision.
void added reviewers: kees, serge-sans-paille, rsmith, efriedma.
Herald added a project: All.
void requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Clang doesn't have the same behavior as GCC does with union flexible
array members. (Technically, union FAMs are probably not acceptable in
C99 and are an extension / accidentally supported "feature" of GCC and
Clang, but I digress.)

Both Clang and GCC treat *all* arrays at the end of a structure as FAMs.
GCC does the same with unions. Clang does it for some arrays in unions
(incomplete, '0', and '1'), but for all. Instead of having this
half-supported feature, sync Clang's behavior with GCC's.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D135727

Files:
  clang/lib/AST/Expr.cpp
  clang/test/CodeGen/bounds-checking-fam.c
  clang/test/CodeGen/bounds-checking.c

Index: clang/test/CodeGen/bounds-checking.c
===================================================================
--- clang/test/CodeGen/bounds-checking.c
+++ clang/test/CodeGen/bounds-checking.c
@@ -1,10 +1,10 @@
 // RUN: %clang_cc1 -fsanitize=local-bounds -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
-// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s --check-prefixes=CHECK,NONLOCAL
+// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s
 //
 // REQUIRES: x86-registered-target
 
-// CHECK-LABEL: @f
-double f(int b, int i) {
+// CHECK-LABEL: @f1
+double f1(int b, int i) {
   double a[b];
   // CHECK: call {{.*}} @llvm.{{(ubsan)?trap}}
   return a[i];
@@ -31,29 +31,38 @@
   a[2] = 1;
 }
 
+// CHECK-LABEL: @f4
+__attribute__((no_sanitize("bounds")))
+int f4(int i) {
+  int b[64];
+  // CHECK-NOT: call void @llvm.trap()
+  // CHECK-NOT: trap:
+  // CHECK-NOT: cont:
+  return b[i];
+}
+
+// Union flexible-array memebers are a C99 extension. All array members with a
+// constant size should be considered FAMs.
+
 union U { int a[0]; int b[1]; int c[2]; };
 
-// CHECK-LABEL: define {{.*}} @f4
-int f4(union U *u, int i) {
-  // a and b are treated as flexible array members.
-  // CHECK-NOT: @llvm.ubsantrap
-  return u->a[i] + u->b[i];
-  // CHECK: }
-}
-
-// CHECK-LABEL: define {{.*}} @f5
+// CHECK-LABEL: @f5
 int f5(union U *u, int i) {
-  // c is not a flexible array member.
-  // NONLOCAL: call {{.*}} @llvm.ubsantrap
-  return u->c[i];
-  // CHECK: }
+  // a is treated as a flexible array member.
+  // CHECK-NOT: @llvm.ubsantrap
+  return u->a[i];
 }
 
-__attribute__((no_sanitize("bounds")))
-int f6(int i) {
-	int b[64];
-	// CHECK-NOT: call void @llvm.trap()
-	// CHECK-NOT: trap:
-	// CHECK-NOT: cont:
-	return b[i];
+// CHECK-LABEL: @f6
+int f6(union U *u, int i) {
+  // b is treated as a flexible array member.
+  // CHECK-NOT: @llvm.ubsantrap
+  return u->b[i];
+}
+
+// CHECK-LABEL: @f7
+int f7(union U *u, int i) {
+  // c is treated as a flexible array member.
+  // CHECK-NOT: @llvm.ubsantrap
+  return u->c[i];
 }
Index: clang/test/CodeGen/bounds-checking-fam.c
===================================================================
--- clang/test/CodeGen/bounds-checking-fam.c
+++ clang/test/CodeGen/bounds-checking-fam.c
@@ -1,14 +1,18 @@
 // REQUIRES: x86-registered-target
-// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=0 -fsanitize=array-bounds        %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-0
-// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=0 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-0,CXX,CXX-STRICT-0
-// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=1 -fsanitize=array-bounds        %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-1
-// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=1 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-1,CXX
-// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=2 -fsanitize=array-bounds        %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-2
-// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=2 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-2,CXX
+// RUN: %clang_cc1 -O2 -emit-llvm -triple x86_64 -fstrict-flex-arrays=0 -fsanitize=array-bounds        %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-0
+// RUN: %clang_cc1 -O2 -emit-llvm -triple x86_64 -fstrict-flex-arrays=0 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-0,CXX,CXX-STRICT-0
+// RUN: %clang_cc1 -O2 -emit-llvm -triple x86_64 -fstrict-flex-arrays=1 -fsanitize=array-bounds        %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-1
+// RUN: %clang_cc1 -O2 -emit-llvm -triple x86_64 -fstrict-flex-arrays=1 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-1,CXX
+// RUN: %clang_cc1 -O2 -emit-llvm -triple x86_64 -fstrict-flex-arrays=2 -fsanitize=array-bounds        %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-2
+// RUN: %clang_cc1 -O2 -emit-llvm -triple x86_64 -fstrict-flex-arrays=2 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-2,CXX
 // Before flexible array member was added to C99, many projects use a
 // one-element array as the last member of a structure as an alternative.
 // E.g. https://github.com/python/cpython/issues/84301
 // Suppress such errors with -fstrict-flex-arrays=0.
+
+union Zero {
+  int a[0];
+};
 struct One {
   int a[1];
 };
@@ -19,6 +23,14 @@
   int a[3];
 };
 
+// CHECK-LABEL: define {{.*}} @{{.*}}test_zero{{.*}}(
+int test_zero(union Zero *p, int i) {
+  // CHECK-STRICT-0-NOT: @__ubsan
+  // CHECK-STRICT-1-NOT: @__ubsan
+  // CHECK-STRICT-2-NOT: @__ubsan
+  return p->a[i] + (p->a)[i];
+}
+
 // CHECK-LABEL: define {{.*}} @{{.*}}test_one{{.*}}(
 int test_one(struct One *p, int i) {
   // CHECK-STRICT-0-NOT: @__ubsan
@@ -29,7 +41,15 @@
 
 // CHECK-LABEL: define {{.*}} @{{.*}}test_two{{.*}}(
 int test_two(struct Two *p, int i) {
-  // CHECK-STRICT-0:     call void @__ubsan_handle_out_of_bounds_abort(
+  // CHECK-STRICT-0-NOT: @__ubsan
+  // CHECK-STRICT-1:     call void @__ubsan_handle_out_of_bounds_abort(
+  // CHECK-STRICT-2:     call void @__ubsan_handle_out_of_bounds_abort(
+  return p->a[i] + (p->a)[i];
+}
+
+// CHECK-LABEL: define {{.*}} @{{.*}}test_three{{.*}}(
+int test_three(struct Three *p, int i) {
+  // CHECK-STRICT-0-NOT: @__ubsan
   // CHECK-STRICT-1:     call void @__ubsan_handle_out_of_bounds_abort(
   // CHECK-STRICT-2:     call void @__ubsan_handle_out_of_bounds_abort(
   return p->a[i] + (p->a)[i];
@@ -60,29 +80,21 @@
 int test_uone(union uOne *p, int i) {
   // CHECK-STRICT-0-NOT: @__ubsan
   // CHECK-STRICT-1-NOT: @__ubsan
-  // CHECK-STRICT-2: @__ubsan
+  // CHECK-STRICT-2:     call void @__ubsan_handle_out_of_bounds_abort(
   return p->a[i] + (p->a)[i];
 }
 
 // CHECK-LABEL: define {{.*}} @{{.*}}test_utwo{{.*}}(
 int test_utwo(union uTwo *p, int i) {
-  // CHECK-STRICT-0: @__ubsan
-  // CHECK-STRICT-1: @__ubsan
-  // CHECK-STRICT-2: @__ubsan
+  // CHECK-STRICT-0-NOT: @__ubsan
+  // CHECK-STRICT-1:     call void @__ubsan_handle_out_of_bounds_abort(
+  // CHECK-STRICT-2:     call void @__ubsan_handle_out_of_bounds_abort(
   return p->a[i] + (p->a)[i];
 }
 
 // CHECK-LABEL: define {{.*}} @{{.*}}test_uthree{{.*}}(
 int test_uthree(union uThree *p, int i) {
-  // CHECK-STRICT-0: @__ubsan
-  // CHECK-STRICT-1: @__ubsan
-  // CHECK-STRICT-2: @__ubsan
-  return p->a[i] + (p->a)[i];
-}
-
-// CHECK-LABEL: define {{.*}} @{{.*}}test_three{{.*}}(
-int test_three(struct Three *p, int i) {
-  // CHECK-STRICT-0:     call void @__ubsan_handle_out_of_bounds_abort(
+  // CHECK-STRICT-0-NOT: @__ubsan
   // CHECK-STRICT-1:     call void @__ubsan_handle_out_of_bounds_abort(
   // CHECK-STRICT-2:     call void @__ubsan_handle_out_of_bounds_abort(
   return p->a[i] + (p->a)[i];
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -207,7 +207,6 @@
     ASTContext &Context,
     LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
     bool IgnoreTemplateOrMacroSubstitution) const {
-
   // For compatibility with existing code, we treat arrays of length 0 or
   // 1 as flexible array members.
   if (const auto *CAT = Context.getAsConstantArrayType(getType())) {
@@ -217,13 +216,16 @@
     if (Size == 0)
       return true;
 
+    using FAMKind = LangOptions::StrictFlexArraysLevelKind;
+
     // FIXME: While the default -fstrict-flex-arrays=0 permits Size>1 trailing
     // arrays to be treated as flexible-array-members, we still emit diagnostics
     // as if they are not. Pending further discussion...
-    using FAMKind = LangOptions::StrictFlexArraysLevelKind;
-    if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete || Size.uge(2))
+    if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete && Size.uge(1))
       return false;
 
+    if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete && Size.uge(2))
+      return false;
   } else if (!Context.getAsIncompleteArrayType(getType()))
     return false;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to