From 511ad6492eabb7797910ce8689577c45f57bce40 Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Tue, 25 Jul 2023 13:04:25 -0700 Subject: InlinedVector: Fix control-flow-inregrity warning when using a class with a vtable The code is getting the pointer, then constructing it on the next line. Using reinterpret_cast on this pointer is legal according to https://clang.llvm.org/docs/ControlFlowIntegrity.html#bad-cast-checking, but it flags it anyway. The docs say it might be necessary for `allocate()`-type APIs, and recommends adding them to an ignorelist. Also note that std::addressof is removed. It is unnecessary since inlined_data is a char-array. PiperOrigin-RevId: 550972834 Change-Id: Ib224cec330bb6bcb770296de6c91881f404ef531 --- absl/base/attributes.h | 2 +- absl/container/inlined_vector_test.cc | 5 +++++ absl/container/internal/inlined_vector.h | 19 ++++++++++++++----- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/absl/base/attributes.h b/absl/base/attributes.h index cb3f367f..a7f279a0 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h @@ -274,7 +274,7 @@ // // Tells the ControlFlowIntegrity sanitizer to not instrument a given function. // See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details. -#if ABSL_HAVE_ATTRIBUTE(no_sanitize) +#if ABSL_HAVE_ATTRIBUTE(no_sanitize) && defined(__llvm__) #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi"))) #else #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc index 6f4625dc..07304518 100644 --- a/absl/container/inlined_vector_test.cc +++ b/absl/container/inlined_vector_test.cc @@ -1621,6 +1621,11 @@ TEST(DynamicVec, DynamicVecCompiles) { (void)v; } +TEST(DynamicVec, CreateNonEmptyDynamicVec) { + DynamicVec v(1); + EXPECT_EQ(v.size(), 1u); +} + TEST(AllocatorSupportTest, Constructors) { using MyAlloc = CountingAllocator; using AllocVec = absl::InlinedVector; diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h index f886dfa0..639bf145 100644 --- a/absl/container/internal/inlined_vector.h +++ b/absl/container/internal/inlined_vector.h @@ -391,13 +391,22 @@ class Storage { } Pointer GetInlinedData() { - return reinterpret_cast>( - std::addressof(data_.inlined.inlined_data[0])); + return reinterpret_cast>(data_.inlined.inlined_data); } ConstPointer GetInlinedData() const { - return reinterpret_cast>( - std::addressof(data_.inlined.inlined_data[0])); + return reinterpret_cast>(data_.inlined.inlined_data); + } + + // Like GetInlinedData(), but for data that has not been constructed yet. The + // only difference is ABSL_ATTRIBUTE_NO_SANITIZE_CFI, which is necessary + // because the object is uninitialized. + // https://clang.llvm.org/docs/ControlFlowIntegrity.html#bad-cast-checking + // NOTE: When this was written, LLVM documentation did not explicitly + // mention that casting `char*` and using `reinterpret_cast` qualifies + // as a bad cast. + ABSL_ATTRIBUTE_NO_SANITIZE_CFI Pointer GetInlinedDataUninitialized() { + return reinterpret_cast>(data_.inlined.inlined_data); } SizeType GetAllocatedCapacity() const { @@ -628,7 +637,7 @@ auto Storage::Initialize(ValueAdapter values, SizeType new_size) SetAllocation(allocation); SetIsAllocated(); } else { - construct_data = GetInlinedData(); + construct_data = GetInlinedDataUninitialized(); } ConstructElements(GetAllocator(), construct_data, values, new_size); -- cgit v1.2.3