From 9a781ed447f583aecdce9b321329a55b90898aaa Mon Sep 17 00:00:00 2001 From: Nicholas Ormrod Date: Thu, 31 Mar 2016 15:09:14 -0700 Subject: [PATCH] New strings no longer relocatable Summary:gcc-5.0 introduced non-relocatable strings in libgcc. Only treat gcc < 5 strings as relocatable. Enable relocation for fbstrings via typedef. Re https://github.com/facebook/folly/issues/316, thanks tomhughes for reporting this. Reviewed By: snarkmaster, ot Differential Revision: D3115580 fb-gh-sync-id: d8aff947d55a0a0c57f6b997f651a190e05f2779 fbshipit-source-id: d8aff947d55a0a0c57f6b997f651a190e05f2779 --- folly/FBString.h | 1 + folly/Traits.h | 3 +++ folly/test/TraitsTest.cpp | 41 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/folly/FBString.h b/folly/FBString.h index dc455991..2f025154 100644 --- a/folly/FBString.h +++ b/folly/FBString.h @@ -975,6 +975,7 @@ public: > const_reverse_iterator; static const size_type npos; // = size_type(-1) + typedef std::true_type IsRelocatable; private: static void procrustes(size_type& n, size_type nmax) { diff --git a/folly/Traits.h b/folly/Traits.h index 76120c32..2d8c52dd 100644 --- a/folly/Traits.h +++ b/folly/Traits.h @@ -386,7 +386,10 @@ constexpr construct_in_place_t construct_in_place{}; } // namespace folly +// gcc-5.0 changed string's implementation in libgcc to be non-relocatable +#if __GNUC__ < 5 FOLLY_ASSUME_FBVECTOR_COMPATIBLE_3(std::basic_string); +#endif FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::vector); FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::list); FOLLY_ASSUME_FBVECTOR_COMPATIBLE_2(std::deque); diff --git a/folly/test/TraitsTest.cpp b/folly/test/TraitsTest.cpp index c76f1daa..82cded67 100644 --- a/folly/test/TraitsTest.cpp +++ b/folly/test/TraitsTest.cpp @@ -16,6 +16,11 @@ #include +#include +#include +#include + +#include #include using namespace folly; @@ -108,6 +113,42 @@ TEST(Traits, relational) { EXPECT_FALSE((folly::greater_than(254u))); } +template +void testIsRelocatable(Args&&... args) { + if (!IsRelocatable::value) return; + + // We use placement new on zeroed memory to avoid garbage subsections + char vsrc[sizeof(T)] = { 0 }; + char vdst[sizeof(T)] = { 0 }; + char vcpy[sizeof(T)]; + + T* src = new (vsrc) T(std::forward(args)...); + SCOPE_EXIT { src->~T(); }; + std::memcpy(vcpy, vsrc, sizeof(T)); + T deep(*src); + T* dst = new (vdst) T(std::move(*src)); + SCOPE_EXIT { dst->~T(); }; + + EXPECT_EQ(deep, *dst); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" + EXPECT_EQ(deep, *reinterpret_cast(vcpy)); +#pragma GCC diagnostic pop + + // This test could technically fail; however, this is what relocation + // almost always means, so it's a good test to have + EXPECT_EQ(std::memcmp(vcpy, vdst, sizeof(T)), 0); +} + +TEST(Traits, actuallyRelocatable) { + // Ensure that we test stack and heap allocation for strings with in-situ + // capacity + testIsRelocatable("1"); + testIsRelocatable(sizeof(std::string) + 1, 'x'); + + testIsRelocatable>(5, 'g'); +} + struct membership_no {}; struct membership_yes { using x = void; }; FOLLY_CREATE_HAS_MEMBER_TYPE_TRAITS(has_member_type_x, x); -- 2.34.1