diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1141,7 +1141,7 @@ HelpText<"Use Apple's kernel extensions ABI">, MarshallingInfoFlag>; def fstrict_flex_arrays_EQ : Joined<["-"], "fstrict-flex-arrays=">, Group, - MetaVarName<"">, Values<"0,1,2">, + MetaVarName<"">, Values<"0,1,2,3">, LangOpts<"StrictFlexArrays">, Flags<[CC1Option]>, HelpText<"Enable optimizations based on the strict definition of flexible arrays">, diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/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) && diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -885,17 +885,24 @@ // the two mechanisms. const ArrayType *AT = E->getType()->castAsArrayTypeUnsafe(); if (const auto *CAT = dyn_cast(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(AT)) + } else if (!isa(AT)) { return false; + } E = E->IgnoreParens(); diff --git a/clang/test/CodeGen/bounds-checking-fam.c b/clang/test/CodeGen/bounds-checking-fam.c --- a/clang/test/CodeGen/bounds-checking-fam.c +++ b/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]; } diff --git a/clang/test/CodeGen/object-size-flex-array.c b/clang/test/CodeGen/object-size-flex-array.c --- a/clang/test/CodeGen/object-size-flex-array.c +++ b/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); } diff --git a/clang/test/Sema/array-bounds-ptr-arith.c b/clang/test/Sema/array-bounds-ptr-arith.c --- a/clang/test/Sema/array-bounds-ptr-arith.c +++ b/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{ diff --git a/clang/test/SemaCXX/array-bounds-strict-flex-arrays.cpp b/clang/test/SemaCXX/array-bounds-strict-flex-arrays.cpp --- a/clang/test/SemaCXX/array-bounds-strict-flex-arrays.cpp +++ b/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 {