void created this revision. void added a reviewer: kees. Herald added a project: All. void requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
The -fstrict-flex-arrays=3 is the most restrictive type of flex arrays. No number, including 0, is allowed in the FAM. In the cases where a "0" is used, the resulting size is the same as if a zero-sized object were substituted. This is needed for proper _FORTIFY_SOURCE coverage in the Linux kernel, among other reasons. So while the only reason for specifying a zero-length array at the end of a structure is for specify a FAM, treating it as such will cause _FORTIFY_SOURCE not to work correctly. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101836 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D134902 Files: clang/include/clang/Driver/Options.td clang/lib/AST/ExprConstant.cpp clang/lib/CodeGen/CGExpr.cpp clang/test/CodeGen/bounds-checking-fam.c clang/test/CodeGen/object-size-flex-array.c clang/test/Sema/array-bounds-ptr-arith.c clang/test/SemaCXX/array-bounds-strict-flex-arrays.cpp
Index: clang/test/SemaCXX/array-bounds-strict-flex-arrays.cpp =================================================================== --- clang/test/SemaCXX/array-bounds-strict-flex-arrays.cpp +++ clang/test/SemaCXX/array-bounds-strict-flex-arrays.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -verify=relaxed -fstrict-flex-arrays=1 %s // RUN: %clang_cc1 -verify=relaxed,strict -fstrict-flex-arrays=2 %s +// RUN: %clang_cc1 -verify=relaxed,strict -fstrict-flex-arrays=3 %s // We cannot know for sure the size of a flexible array. struct t { Index: clang/test/Sema/array-bounds-ptr-arith.c =================================================================== --- clang/test/Sema/array-bounds-ptr-arith.c +++ clang/test/Sema/array-bounds-ptr-arith.c @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -verify=expected -Warray-bounds-pointer-arithmetic %s // RUN: %clang_cc1 -verify=expected -Warray-bounds-pointer-arithmetic %s -fstrict-flex-arrays=0 // RUN: %clang_cc1 -verify=expected,strict -Warray-bounds-pointer-arithmetic %s -fstrict-flex-arrays=2 +// RUN: %clang_cc1 -verify=expected,strict -Warray-bounds-pointer-arithmetic %s -fstrict-flex-arrays=3 // Test case from PR10615 struct ext2_super_block{ Index: clang/test/CodeGen/object-size-flex-array.c =================================================================== --- clang/test/CodeGen/object-size-flex-array.c +++ clang/test/CodeGen/object-size-flex-array.c @@ -1,6 +1,8 @@ -// RUN: %clang -fstrict-flex-arrays=2 -target x86_64-apple-darwin -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-STRICT-2 %s -// RUN: %clang -fstrict-flex-arrays=1 -target x86_64-apple-darwin -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-STRICT-1 %s -// RUN: %clang -fstrict-flex-arrays=0 -target x86_64-apple-darwin -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-STRICT-0 %s +// RUN: %clang -target x86_64 -O2 -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-NO-STRICT %s +// RUN: %clang -fstrict-flex-arrays=0 -target x86_64 -O2 -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-STRICT-0 %s +// RUN: %clang -fstrict-flex-arrays=1 -target x86_64 -O2 -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-STRICT-1 %s +// RUN: %clang -fstrict-flex-arrays=2 -target x86_64 -O2 -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-STRICT-2 %s +// RUN: %clang -fstrict-flex-arrays=3 -target x86_64 -O2 -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-STRICT-3 %s #define OBJECT_SIZE_BUILTIN __builtin_object_size @@ -26,36 +28,86 @@ // CHECK-LABEL: @bar( unsigned bar(foo_t *f) { - // CHECK-STRICT-0: ret i32 % - // CHECK-STRICT-1: ret i32 % - // CHECK-STRICT-2: ret i32 % + // CHECK-NO-STRICT: ret i32 -1 + // CHECK-STRICT-0: ret i32 -1 + // CHECK-STRICT-1: ret i32 -1 + // CHECK-STRICT-2: ret i32 -1 + // CHECK-STRICT-3: ret i32 -1 return OBJECT_SIZE_BUILTIN(f->c, 1); } // CHECK-LABEL: @bar0( unsigned bar0(foo0_t *f) { - // CHECK-STRICT-0: ret i32 % - // CHECK-STRICT-1: ret i32 % - // CHECK-STRICT-2: ret i32 % + // CHECK-NO-STRICT: ret i32 -1 + // CHECK-STRICT-0: ret i32 -1 + // CHECK-STRICT-1: ret i32 -1 + // CHECK-STRICT-2: ret i32 -1 + // CHECK-STRICT-3: ret i32 0 return OBJECT_SIZE_BUILTIN(f->c, 1); } // CHECK-LABEL: @bar1( unsigned bar1(foo1_t *f) { - // CHECK-STRICT-0: ret i32 % - // CHECK-STRICT-1: ret i32 % + // CHECK-NO-STRICT: ret i32 -1 + // CHECK-STRICT-0: ret i32 -1 + // CHECK-STRICT-1: ret i32 -1 // CHECK-STRICT-2: ret i32 8 + // CHECK-STRICT-3: ret i32 8 return OBJECT_SIZE_BUILTIN(f->c, 1); } // CHECK-LABEL: @bar2( unsigned bar2(foo2_t *f) { - // CHECK-STRICT-0: ret i32 % + // CHECK-NO-STRICT: ret i32 -1 + // CHECK-STRICT-0: ret i32 -1 // CHECK-STRICT-1: ret i32 16 // CHECK-STRICT-2: ret i32 16 + // CHECK-STRICT-3: ret i32 16 return OBJECT_SIZE_BUILTIN(f->c, 1); } +#define DYNAMIC_OBJECT_SIZE_BUILTIN __builtin_dynamic_object_size + +// CHECK-LABEL: @dyn_bar( +unsigned dyn_bar(foo_t *f) { + // CHECK-NO-STRICT: ret i32 -1 + // CHECK-STRICT-0: ret i32 -1 + // CHECK-STRICT-1: ret i32 -1 + // CHECK-STRICT-2: ret i32 -1 + // CHECK-STRICT-3: ret i32 -1 + return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CHECK-LABEL: @dyn_bar0( +unsigned dyn_bar0(foo0_t *f) { + // CHECK-NO-STRICT: ret i32 -1 + // CHECK-STRICT-0: ret i32 -1 + // CHECK-STRICT-1: ret i32 -1 + // CHECK-STRICT-2: ret i32 -1 + // CHECK-STRICT-3: ret i32 0 + return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CHECK-LABEL: @dyn_bar1( +unsigned dyn_bar1(foo1_t *f) { + // CHECK-NO-STRICT: ret i32 -1 + // CHECK-STRICT-0: ret i32 -1 + // CHECK-STRICT-1: ret i32 -1 + // CHECK-STRICT-2: ret i32 8 + // CHECK-STRICT-3: ret i32 8 + return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CHECK-LABEL: @dyn_bar2( +unsigned dyn_bar2(foo2_t *f) { + // CHECK-NO-STRICT: ret i32 -1 + // CHECK-STRICT-0: ret i32 -1 + // CHECK-STRICT-1: ret i32 16 + // CHECK-STRICT-2: ret i32 16 + // CHECK-STRICT-3: ret i32 16 + return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1); +} + // Also checks for non-trailing flex-array like members typedef struct { @@ -75,24 +127,30 @@ // CHECK-LABEL: @babar0( unsigned babar0(foofoo0_t *f) { + // CHECK-NO-STRICT: ret i32 0 // CHECK-STRICT-0: ret i32 0 // CHECK-STRICT-1: ret i32 0 // CHECK-STRICT-2: ret i32 0 + // CHECK-STRICT-3: ret i32 0 return OBJECT_SIZE_BUILTIN(f->c, 1); } // CHECK-LABEL: @babar1( unsigned babar1(foofoo1_t *f) { + // CHECK-NO-STRICT: ret i32 8 // CHECK-STRICT-0: ret i32 8 // CHECK-STRICT-1: ret i32 8 // CHECK-STRICT-2: ret i32 8 + // CHECK-STRICT-3: ret i32 8 return OBJECT_SIZE_BUILTIN(f->c, 1); } // CHECK-LABEL: @babar2( unsigned babar2(foofoo2_t *f) { + // CHECK-NO-STRICT: ret i32 16 // CHECK-STRICT-0: ret i32 16 // CHECK-STRICT-1: ret i32 16 // CHECK-STRICT-2: ret i32 16 + // CHECK-STRICT-3: ret i32 16 return OBJECT_SIZE_BUILTIN(f->c, 1); } Index: clang/test/CodeGen/bounds-checking-fam.c =================================================================== --- clang/test/CodeGen/bounds-checking-fam.c +++ clang/test/CodeGen/bounds-checking-fam.c @@ -1,10 +1,12 @@ // 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 +// RUN: %clang_cc1 -O2 -emit-llvm -triple x86_64 -fstrict-flex-arrays=3 -fsanitize=array-bounds %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-3 +// RUN: %clang_cc1 -O2 -emit-llvm -triple x86_64 -fstrict-flex-arrays=3 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-3,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 @@ -24,6 +26,7 @@ // CHECK-STRICT-0-NOT: @__ubsan // CHECK-STRICT-1-NOT: @__ubsan // CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort( + // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort( return p->a[i] + (p->a)[i]; } @@ -32,6 +35,7 @@ // CHECK-STRICT-0: call void @__ubsan_handle_out_of_bounds_abort( // CHECK-STRICT-1: call void @__ubsan_handle_out_of_bounds_abort( // CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort( + // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort( return p->a[i] + (p->a)[i]; } @@ -53,6 +57,7 @@ // CHECK-STRICT-0-NOT: @__ubsan // CHECK-STRICT-1-NOT: @__ubsan // CHECK-STRICT-2-NOT: @__ubsan + // CHECK-STRICT-3: @__ubsan return p->a[i] + (p->a)[i]; } @@ -61,6 +66,7 @@ // CHECK-STRICT-0-NOT: @__ubsan // CHECK-STRICT-1-NOT: @__ubsan // CHECK-STRICT-2: @__ubsan + // CHECK-STRICT-3: @__ubsan return p->a[i] + (p->a)[i]; } @@ -69,6 +75,7 @@ // CHECK-STRICT-0: @__ubsan // CHECK-STRICT-1: @__ubsan // CHECK-STRICT-2: @__ubsan + // CHECK-STRICT-3: @__ubsan return p->a[i] + (p->a)[i]; } @@ -77,6 +84,7 @@ // CHECK-STRICT-0: @__ubsan // CHECK-STRICT-1: @__ubsan // CHECK-STRICT-2: @__ubsan + // CHECK-STRICT-3: @__ubsan return p->a[i] + (p->a)[i]; } @@ -85,6 +93,7 @@ // CHECK-STRICT-0: call void @__ubsan_handle_out_of_bounds_abort( // CHECK-STRICT-1: call void @__ubsan_handle_out_of_bounds_abort( // CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort( + // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort( return p->a[i] + (p->a)[i]; } Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -885,17 +885,24 @@ // the two mechanisms. const ArrayType *AT = E->getType()->castAsArrayTypeUnsafe(); if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) { + // At -fstrict-flex-arrays=3, only IncompleteArrayTypes are considered + // FAMs. + if (StrictFlexArraysLevel == 3) + return false; + // FIXME: Sema doesn't treat [1] as a flexible array member if the bound // was produced by macro expansion. - if (StrictFlexArraysLevel >= 2 && CAT->getSize().ugt(0)) + if (StrictFlexArraysLevel == 2 && CAT->getSize().ugt(0)) return false; + // FIXME: While the default -fstrict-flex-arrays=0 permits Size>1 trailing // arrays to be treated as flexible-array-members, we still emit ubsan // checks as if they are not. if (CAT->getSize().ugt(1)) return false; - } else if (!isa<IncompleteArrayType>(AT)) + } else if (!isa<IncompleteArrayType>(AT)) { return false; + } E = E->IgnoreParens(); Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -11618,7 +11618,8 @@ Designator.Entries.size() == Designator.MostDerivedPathLength && Designator.MostDerivedIsArrayElement && (Designator.isMostDerivedAnUnsizedArray() || - Designator.getMostDerivedArraySize() == 0 || + (Designator.getMostDerivedArraySize() == 0 && + StrictFlexArraysLevel < 3) || (Designator.getMostDerivedArraySize() == 1 && StrictFlexArraysLevel < 2) || StrictFlexArraysLevel == 0) && Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -1141,7 +1141,7 @@ HelpText<"Use Apple's kernel extensions ABI">, MarshallingInfoFlag<LangOpts<"AppleKext">>; def fstrict_flex_arrays_EQ : Joined<["-"], "fstrict-flex-arrays=">, Group<f_Group>, - MetaVarName<"<n>">, Values<"0,1,2">, + MetaVarName<"<n>">, Values<"0,1,2,3">, LangOpts<"StrictFlexArrays">, Flags<[CC1Option]>, HelpText<"Enable optimizations based on the strict definition of flexible arrays">,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits