<html>
<head>
<base href="https://bugs.llvm.org/">
</head>
<body><table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Bug ID</th>
<td><a class="bz_bug_link
bz_status_NEW "
title="NEW - Recent shared_ptr storage change (https://reviews.llvm.org/D91201) causes CFI cast failures during make_shared"
href="https://bugs.llvm.org/show_bug.cgi?id=48993">48993</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>Recent shared_ptr storage change (https://reviews.llvm.org/D91201) causes CFI cast failures during make_shared
</td>
</tr>
<tr>
<th>Product</th>
<td>libc++
</td>
</tr>
<tr>
<th>Version</th>
<td>unspecified
</td>
</tr>
<tr>
<th>Hardware</th>
<td>PC
</td>
</tr>
<tr>
<th>OS</th>
<td>All
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>enhancement
</td>
</tr>
<tr>
<th>Priority</th>
<td>P
</td>
</tr>
<tr>
<th>Component</th>
<td>All Bugs
</td>
</tr>
<tr>
<th>Assignee</th>
<td>unassignedclangbugs@nondot.org
</td>
</tr>
<tr>
<th>Reporter</th>
<td>rnk@google.com
</td>
</tr>
<tr>
<th>CC</th>
<td>llvm-bugs@lists.llvm.org, mclow.lists@gmail.com
</td>
</tr></table>
<p>
<div>
<pre>Consider this program that creates and destroys a shared_ptr object:
$ cat t.cpp
#include <memory>
struct Foo {
Foo() {}
virtual ~Foo() {}
};
int main(int argc, char **argv) { std::make_shared<Foo>(); }
If you compile libc++, lld, clang, cfi, ubsan, etc, at ToT and build this
program like so, it results in CFI cast errors:
$ ./bin/clang++ t.cpp -flto=thin -fuse-ld=lld -stdlib=libc++ -fsanitize=cfi
-fno-sanitize-trap -fvisibility=hidden && LD_LIBRARY_PATH=lib ./a.out ;
echo $?
/usr/local/google/home/rnk/llvm-project/build/bin/../include/c++/v1/memory:2653:27:
runtime error: control flow integrity check for type 'Foo' failed during cast
to unrelated type (vtable address 0x000000000000)
0x000000000000: note: invalid vtable
<memory cannot be printed>
/usr/local/google/home/rnk/llvm-project/build/bin/../include/c++/v1/memory:2653:27:
note: check failed in /usr/local/google/home/rnk/llvm-project/build/a.out,
vtable located in (unknown)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior
/usr/local/google/home/rnk/llvm-project/build/bin/../include/c++/v1/memory:2653:27
in
1
Reverting 955dd7b7f3f6d / <a href="https://reviews.llvm.org/D91201">https://reviews.llvm.org/D91201</a> locally and
rebuilding libc++ to copy the headers makes the problem go away:
$ git revert 955dd7b7f3f6d
Removing
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_construct.pass.cpp
Removing
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/libcxx.control_block_layout.pass.cpp
Auto-merging libcxx/include/memory
[main 5f7ab320457d] Revert "[libc++] LWG2070: Use Allocator construction for
objects created with allocate_shared"
4 files changed, 19 insertions(+), 429 deletions(-)
delete mode 100644
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/libcxx.control_block_layout.pass.cpp
delete mode 100644
libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_construct.pass.cpp
$ ninja cxx
[1 processes, 11/11 @ 17.6/s : 0.626s ] Creating library symlink
lib/libc++.so.1 lib/libc++.so
$ ./bin/clang++ t.cpp -flto=thin -fuse-ld=lld -stdlib=libc++ -fsanitize=cfi
-fno-sanitize-trap -fvisibility=hidden && LD_LIBRARY_PATH=lib ./a.out ;
echo $?
0
These are the lines of the change that matter:
_LIBCPP_HIDE_FROM_ABI
explicit __shared_ptr_emplace(_Alloc __a, _Args&& ...__args)
-#ifndef _LIBCPP_CXX03_LANG
- : __data_(piecewise_construct, _VSTD::forward_as_tuple(__a),
- _VSTD::forward_as_tuple(_VSTD::forward<_Args>(__args)...))
+ : __storage_(_VSTD::move(__a))
+ {
+#if _LIBCPP_STD_VER > 17
+ using _TpAlloc = typename __allocator_traits_rebind<_Alloc,
_Tp>::type;
+ _TpAlloc __tmp(*__get_alloc());
+ allocator_traits<_TpAlloc>::construct(__tmp, __get_elem(),
_VSTD::forward<_Args>(__args)...);
#else
- : __data_(__a, _Tp(_VSTD::forward<_Args>(__args)...))
+ ::new ((void*)__get_elem()) _Tp(_VSTD::forward<_Args>(__args)...);
#endif
That change switches from calling the __compressed_pair constructor directly to
using placement new on the result of __get_elem. Inside __get_elem, the address
of the second pair element is cast to the type that will be constructed. That
reinterpret_cast on the memory before construction is the issue: CFI detects
cast confusion bugs by checking that the vtable is correct for the type of the
cast, but the vptr slot is still uninitialized.</pre>
</div>
</p>
<hr>
<span>You are receiving this mail because:</span>
<ul>
<li>You are on the CC list for the bug.</li>
</ul>
</body>
</html>