[libcxx] r351290 - Fix PR40230 - std::pair may have padding on FreeBSD.

Eric Fiselier eric at efcs.ca
Tue Jan 15 17:54:34 PST 2019


Author: ericwf
Date: Tue Jan 15 17:54:34 2019
New Revision: 351290

URL: http://llvm.org/viewvc/llvm-project?rev=351290&view=rev
Log:
Fix PR40230 - std::pair may have padding on FreeBSD.

Summary:
FreeBSD ships a very old and deprecated ABI for std::pair where the copy and move constructors are not allowed to be trivial. D25389 change how this was implemented by introducing a non-trivial base class. This patch, introduced in October 2016, introduced an ABI bug that caused nested `std::pair` instantiations to have padding. For example:

```
using PairT = std::pair< std::pair<char, char>, char >;
static_assert(offsetof(PairT, first) == 0, "First member should exist at offset zero"); // Fails on FreeBSD!
```

The bug occurs because the base class for the first element (the nested pair) cannot be put at offset zero because the top-level pair already has the same base class laid out there.

This patch fixes that ABI bug by templating the dummy base class on the same parameters as the pair.

Technically this fix is an ABI break for users who depend on the "broken" ABI introduced in 2016. I'm putting this up for review so that the FreeBSD maintainers can sign off on fixing the ABI by breaking the ABI.
Another option, since we have to "break" the ABI to fix it, would be to move FreeBSD off the deprecated non-trivial pair ABI instead.

Also see:

* https://llvm.org/PR40230
* https://reviews.llvm.org/D21329



Reviewers: rsmith, dim, emaste

Reviewed By: rsmith

Subscribers: mclow.lists, krytarowski, christof, ldionne, libcxx-commits

Differential Revision: https://reviews.llvm.org/D56357

Modified:
    libcxx/trunk/include/utility
    libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp
    libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/trivial_copy_move_ABI.pass.cpp

Modified: libcxx/trunk/include/utility
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?rev=351290&r1=351289&r2=351290&view=diff
==============================================================================
--- libcxx/trunk/include/utility (original)
+++ libcxx/trunk/include/utility Tue Jan 15 17:54:34 2019
@@ -303,6 +303,7 @@ extern _LIBCPP_EXPORTED_FROM_ABI const p
 #endif
 
 #if defined(_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR)
+template <class, class>
 struct __non_trivially_copyable_base {
   _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
   __non_trivially_copyable_base() _NOEXCEPT {}
@@ -314,7 +315,7 @@ struct __non_trivially_copyable_base {
 template <class _T1, class _T2>
 struct _LIBCPP_TEMPLATE_VIS pair
 #if defined(_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR)
-: private __non_trivially_copyable_base
+: private __non_trivially_copyable_base<_T1, _T2>
 #endif
 {
     typedef _T1 first_type;

Modified: libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp?rev=351290&r1=351289&r2=351290&view=diff
==============================================================================
--- libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp (original)
+++ libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/non_trivial_copy_move_ABI.pass.cpp Tue Jan 15 17:54:34 2019
@@ -30,6 +30,7 @@
 #include <utility>
 #include <type_traits>
 #include <cstdlib>
+#include <cstddef>
 #include <cassert>
 
 #include "test_macros.h"
@@ -86,7 +87,7 @@ static_assert(!HasNonTrivialABI<Trivial>
 #endif
 
 
-int main()
+void test_trivial()
 {
     {
         typedef std::pair<int, short> P;
@@ -150,3 +151,15 @@ int main()
     }
 #endif
 }
+
+void test_layout() {
+    typedef std::pair<std::pair<char, char>, char> PairT;
+    static_assert(sizeof(PairT) == 3, "");
+    static_assert(TEST_ALIGNOF(PairT) == TEST_ALIGNOF(char), "");
+    static_assert(offsetof(PairT, first) == 0, "");
+}
+
+int main() {
+    test_trivial();
+    test_layout();
+}

Modified: libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/trivial_copy_move_ABI.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/trivial_copy_move_ABI.pass.cpp?rev=351290&r1=351289&r2=351290&view=diff
==============================================================================
--- libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/trivial_copy_move_ABI.pass.cpp (original)
+++ libcxx/trunk/test/libcxx/utilities/utility/pairs/pairs.pair/trivial_copy_move_ABI.pass.cpp Tue Jan 15 17:54:34 2019
@@ -25,6 +25,7 @@
 #include <utility>
 #include <type_traits>
 #include <cstdlib>
+#include <cstddef>
 #include <cassert>
 
 #include "test_macros.h"
@@ -81,7 +82,7 @@ static_assert(HasTrivialABI<Trivial>::va
 #endif
 
 
-int main()
+void test_trivial()
 {
     {
         typedef std::pair<int, short> P;
@@ -145,3 +146,15 @@ int main()
     }
 #endif
 }
+
+void test_layout() {
+    typedef std::pair<std::pair<char, char>, char> PairT;
+    static_assert(sizeof(PairT) == 3, "");
+    static_assert(TEST_ALIGNOF(PairT) == TEST_ALIGNOF(char), "");
+    static_assert(offsetof(PairT, first) == 0, "");
+}
+
+int main() {
+    test_trivial();
+    test_layout();
+}




More information about the libcxx-commits mailing list