Bug ID 1187254
Summary Clang 9 missing EBO for indirect bases causes miscompilations
Classification openSUSE
Product openSUSE Tumbleweed
Version Current
Hardware Other
OS Other
Status NEW
Severity Normal
Priority P5 - None
Component Development
Assignee screening-team-bugs@suse.de
Reporter aaronpuchert@alice-dsl.net
QA Contact qa-bugs@suse.de
Found By ---
Blocker ---

After the update to GCC 11, there were numerous test failures in llvm9. Easiest
to debug seemed to be that in

unittests/Support/SupportTests --gtest_filter=Parallel.*

Where the constructor std::thread::thread calls _M_start_thread, we can observe
that on both ends of the call the structure looks different. That's not because
anyone changed it, but because the constructor (compiled by Clang 9) thinks a
std::unique_ptr<std::thread::_State> is 16 bytes big, whereas _M_start_thread
(compiled by GCC 11) thinks it's only 8 bytes:

#1  std::thread::thread<[...]>([...]&&) at
/usr/include/c++/11/bits/std_thread.h:143
(gdb) p sizeof(_State_ptr)
$32 = 16
(gdb) down
#0  std::thread::_M_start_thread at [...]/libstdc++-v3/src/c++11/thread.cc:136
(gdb) p sizeof(_State_ptr)
$33 = 8

Oops. Drilling down a bit, we find that both compilers agree on the base
classes of std::_Tuple_impl<0, std::thread::_State*,
std::default_delete<std::thread::_State> >, but not on the class itself.

Clang 9:
std::_Tuple_impl<0, ...>: 16 byte
std::_Tuple_impl<1, std::default_delete<std::thread::_State>> : 1 byte
std::_Head_base<0, std::thread::_State*, false>: 8 byte

GCC 11:
std::_Tuple_impl<0, ...>: 8 byte
std::_Tuple_impl<1, std::default_delete<std::thread::_State>> : 1 byte
std::_Head_base<0, std::thread::_State*, false>: 8 byte

Clang 12 agrees with GCC 11, which is why we're not seeing a problem there. The
difference can also be seen in the types emitted into the IR:

--- clang9.ll
+++ clang12.ll
@@ -1,9 +1,9 @@
 %"class.std::unique_ptr" = type { %"struct.std::__uniq_ptr_data" }
   %"struct.std::__uniq_ptr_data" = type { %"class.std::__uniq_ptr_impl" }
     %"class.std::__uniq_ptr_impl" = type { %"class.std::tuple" }
       %"class.std::tuple" = type { %"struct.std::_Tuple_impl" }
-        %"struct.std::_Tuple_impl" = type { %"struct.std::_Tuple_impl.0",
%"struct.std::_Head_base.1" }
-          %"struct.std::_Tuple_impl.0" = type { %"struct.std::_Head_base" }
-            %"struct.std::_Head_base" = type { %"struct.std::default_delete" }
-              %"struct.std::default_delete" = type { i8 }
+        %"struct.std::_Tuple_impl" = type { %"struct.std::_Head_base.1" }
+          %"struct.std::_Tuple_impl.0" = type { i8 }
+            %"struct.std::default_delete" = type { i8 }
+              %"struct.std::_Head_base" = type { i8 }
         %"struct.std::_Head_base.1" = type { i32* }

I've ordered and indented the types for readability. The difference is that
Clang 9 nests the empty types, whereas Clang 12 emits an { i8 } for empty types
and omits them when not needed. So Clang 9 doesn't do EBO for indirect bases.

Clang 10 doesn't seem to have any issues either, so presumably I can just
bisect this and cherry-pick whatever fixes it.


You are receiving this mail because: