diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -378,9 +378,25 @@ `::operator new(size_­t, std::aligned_val_t, nothrow_­t)` if there is `get_­return_­object_­on_­allocation_­failure`. We feel this is more consistent with the intention. + - Added ``--no-default-config`` to disable automatically loading configuration files using default paths. +- Added a new level to the ``-fstrict-flex-arrays=`` flag. The new level ``3`` + recoginizes only "incomplete" arrays as flexible array members. + + .. code-block:: c + + struct foo { + int a; + int b[]; // Flexible array member. + }; + + struct bar { + int a; + int b[0]; // NOT a flexible array member. + }; + Deprecated Compiler Flags ------------------------- - ``-enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang`` diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -376,7 +376,7 @@ /// Any trailing array member of undefined or 0 size is a FAM. ZeroOrIncomplete = 2, /// Any trailing array member of undefined size is a FAM. - Incomplete = 3, + IncompleteOnly = 3, }; public: 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 @@ -1148,11 +1148,11 @@ 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<"StrictFlexArraysLevel">, Flags<[CC1Option]>, NormalizedValuesScope<"LangOptions::StrictFlexArraysLevelKind">, - NormalizedValues<["Default", "OneZeroOrIncomplete", "ZeroOrIncomplete"]>, + NormalizedValues<["Default", "OneZeroOrIncomplete", "ZeroOrIncomplete", "IncompleteOnly"]>, HelpText<"Enable optimizations based on the strict definition of flexible arrays">, MarshallingInfoEnum, "Default">; defm apple_pragma_pack : BoolFOption<"apple-pragma-pack", diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -214,11 +214,15 @@ if (CAT) { llvm::APInt Size = CAT->getSize(); + using FAMKind = LangOptions::StrictFlexArraysLevelKind; + + if (StrictFlexArraysLevel == FAMKind::IncompleteOnly) + return false; + // GCC extension, only allowed to represent a FAM. if (Size == 0) return true; - using FAMKind = LangOptions::StrictFlexArraysLevelKind; if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete && Size.uge(1)) return false; 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 @@ -11621,17 +11621,31 @@ // conservative with the last element in structs (if it's an array), so our // current behavior is more compatible than an explicit list approach would // be. - using FAMKind = LangOptions::StrictFlexArraysLevelKind; - FAMKind StrictFlexArraysLevel = Ctx.getLangOpts().getStrictFlexArraysLevel(); + auto isFlexibleArrayMember = [&] { + using FAMKind = LangOptions::StrictFlexArraysLevelKind; + FAMKind StrictFlexArraysLevel = + Ctx.getLangOpts().getStrictFlexArraysLevel(); + + if (Designator.isMostDerivedAnUnsizedArray()) + return true; + + if (StrictFlexArraysLevel == FAMKind::Default) + return true; + + if (Designator.getMostDerivedArraySize() == 0 && + StrictFlexArraysLevel != FAMKind::IncompleteOnly) + return true; + + if (Designator.getMostDerivedArraySize() == 1 && + StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete) + return true; + + return false; + }; + return LVal.InvalidBase && Designator.Entries.size() == Designator.MostDerivedPathLength && - Designator.MostDerivedIsArrayElement && - (Designator.isMostDerivedAnUnsizedArray() || - Designator.getMostDerivedArraySize() == 0 || - (Designator.getMostDerivedArraySize() == 1 && - StrictFlexArraysLevel != FAMKind::Incomplete && - StrictFlexArraysLevel != FAMKind::ZeroOrIncomplete) || - StrictFlexArraysLevel == FAMKind::Default) && + Designator.MostDerivedIsArrayElement && isFlexibleArrayMember() && isDesignatorAtObjectEnd(Ctx, LVal); } diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -798,7 +798,7 @@ const FAMKind StrictFlexArraysLevel = Ctx.getLangOpts().getStrictFlexArraysLevel(); if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete || - StrictFlexArraysLevel == FAMKind::Incomplete) + StrictFlexArraysLevel == FAMKind::IncompleteOnly) return false; const AnalyzerOptions &Opts = SVB.getAnalyzerOptions(); 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 @@ -5,6 +5,8 @@ // 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 -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 -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 @@ -36,6 +38,7 @@ // CHECK-STRICT-0-NOT: @__ubsan // CHECK-STRICT-1-NOT: @__ubsan // CHECK-STRICT-2-NOT: @__ubsan + // CHECK-STRICT-3-NOT: @__ubsan return p->a[i] + (p->a)[i]; } @@ -44,6 +47,7 @@ // CHECK-STRICT-0-NOT: @__ubsan // CHECK-STRICT-1-NOT: @__ubsan // CHECK-STRICT-2-NOT: @__ubsan + // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort( return p->a[i] + (p->a)[i]; } @@ -52,6 +56,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]; } @@ -68,6 +73,7 @@ // 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( + // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort( return p->a[i] + (p->a)[i]; } @@ -89,6 +95,7 @@ // CHECK-STRICT-0-NOT: @__ubsan // CHECK-STRICT-1-NOT: @__ubsan // CHECK-STRICT-2-NOT: @__ubsan + // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort( return p->a[i] + (p->a)[i]; } @@ -97,6 +104,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]; } @@ -105,6 +113,7 @@ // 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( + // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort( return p->a[i] + (p->a)[i]; } @@ -113,6 +122,7 @@ // 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( + // CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort( return p->a[i] + (p->a)[i]; } @@ -126,6 +136,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]; } 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 -fstrict-flex-arrays=1 %s +// RUN: %clang_cc1 -verify=relaxed,strict -fstrict-flex-arrays=2 %s +// RUN: %clang_cc1 -verify=relaxed,strict,very-strict -fstrict-flex-arrays=3 %s // We cannot know for sure the size of a flexible array. struct t { @@ -10,7 +11,7 @@ s2->a[2] = 0; // no-warning } -// Under -fstrict-flex-arrays={1,2} `a` is not a flexible array +// Under -fstrict-flex-arrays={1,2,3} `a` is not a flexible array struct t0 { int f; int a[10]; // relaxed-note {{array 'a' declared here}} @@ -29,11 +30,11 @@ s2->a[2] = 0; // strict-warning {{array index 2 is past the end of the array (that has type 'int[1]')}} } -// Under -fstrict-flex-arrays={1,2} `a` is a flexible array. +// Under -fstrict-flex-arrays={1,2} `a` is a flexible array, but not under -fstrict-flex-arrays=3. struct t2 { int f; - int a[0]; + int a[0]; // very-strict-note {{array 'a' declared here}} }; void test1(t2 *s2) { - s2->a[2] = 0; // no-warning + s2->a[2] = 0; // very-strict-warning {{array index 2 is past the end of the array (that has type 'int[0]')}} }