<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 - CFI (Control Flow Integrity) emits invalid checks when using std::make_shared (C++11)"
href="https://bugs.llvm.org/show_bug.cgi?id=35431">35431</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>CFI (Control Flow Integrity) emits invalid checks when using std::make_shared (C++11)
</td>
</tr>
<tr>
<th>Product</th>
<td>clang
</td>
</tr>
<tr>
<th>Version</th>
<td>trunk
</td>
</tr>
<tr>
<th>Hardware</th>
<td>PC
</td>
</tr>
<tr>
<th>OS</th>
<td>Linux
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>normal
</td>
</tr>
<tr>
<th>Priority</th>
<td>P
</td>
</tr>
<tr>
<th>Component</th>
<td>-New Bugs
</td>
</tr>
<tr>
<th>Assignee</th>
<td>unassignedclangbugs@nondot.org
</td>
</tr>
<tr>
<th>Reporter</th>
<td>adrien@guinet.me
</td>
</tr>
<tr>
<th>CC</th>
<td>llvm-bugs@lists.llvm.org
</td>
</tr></table>
<p>
<div>
<pre>Created <span class=""><a href="attachment.cgi?id=19477" name="attach_19477" title="test case">attachment 19477</a> <a href="attachment.cgi?id=19477&action=edit" title="test case">[details]</a></span>
test case
Hello all,
CFI (Control Flow Integrity) generates bad code when std::make_shared is used
for C++11 code. The bad code involve a comparaison which will always fail, and
jump to the "ud2" instruction (on X86), as if an invalid call (in the CFI
sense) would have been made.
Using the joint a.cpp file, one can reproduce this using current LLVM trunk
(r319014). The bug happens using GNU's libstdc++, with full or thin lto:
$ build/bin/clang++ -fsanitize=cfi -fvisibility=hidden -flto=full -O2 a.cpp
-fPIC -o a_full -std=c++11 && ./a_full
Illegal instruction
$ build/bin/clang++ -fsanitize=cfi -fvisibility=hidden -flto=thin -O2 a.cpp
-fPIC -o a_thin -std=c++11 && ./a_thin
Illegal instruction
If we take a look at the assembly generated in both cases, it looks like this:
- for a_full:
400850 new_ptr2(void) proc near
400850 push rbx
400851 mov rbx, rdi
400854 mov edi, 28h
400859 call operator new(ulong)
40085E mov rcx, 100000001h
400868 mov [rax+8], rcx
40086C mov qword ptr [rax], offset off_400C80
400873 mov ecx, offset off_400CC0
400878 cmp [rax+10h], rcx <-- memory at rax+0x10 has never been
initialized, this equality is always false!
40087C jnz short loc_40089D
40087E mov rcx, rax
400881 add rcx, 10h
400885 xorps xmm0, xmm0
400888 movups xmmword ptr [rax+18h], xmm0
40088C mov qword ptr [rax+10h], offset off_400CC0
400894 mov [rbx], rcx
400897 mov [rbx+8], rax
40089B pop rbx
40089C retn
- for a_thin:
400850 new_ptr2(void) proc near
400850 push rbx
400851 mov rbx, rdi
400854 mov edi, 28h
400859 call operator new(ulong)
40085E mov rcx, 100000001h
400868 mov [rax+8], rcx
40086C mov qword ptr [rax], offset
__typeid__ZTSSt23_Sp_counted_ptr_inplaceI2S2SaIS0_ELN9__gnu_cxx12_Lock_policyE2EE_global_addr400873
mov ecx, offset
__typeid__ZTSSt23_Sp_counted_ptr_inplaceI2S2SaIS0_ELN9__gnu_cxx12_Lock_policyE2EE_global_addr
400878 mov edx, offset
__typeid__ZTSSt23_Sp_counted_ptr_inplaceI2S2SaIS0_ELN9__gnu_cxx12_Lock_policyE2EE_global_addr
40087D cmp rdx, rcx
400880 jnz short loc_4008BE
400882 mov ecx, offset __typeid__ZTS4Base_global_addr
400887 cmp [rax+10h], rcx <-- same here, memory at rax+0x10 has never
been initialized, this equality is always false!
40088B jnz short loc_4008BE
40088D xorps xmm0, xmm0
400890 movups xmmword ptr [rax+18h], xmm0
400894 mov qword ptr [rax+10h], offset __typeid__ZTS4Base_global_addr
40089C mov ecx, offset __typeid__ZTS4Base_global_addr
4008A1 mov edx, offset __typeid__ZTS4Base_global_addr
4008A6 cmp rdx, rcx
4008A9 jnz short loc_4008BE
4008AB mov rcx, rax
4008AE add rcx, 10h
4008B2 mov [rbx], rcx
4008B5 mov [rbx+8], rax
4008B9 mov rax, rbx
4008BC pop rbx
4008BD retn
For the record, this does not happen using LLVM's libc++:
$ build/bin/clang++ -fsanitize=cfi -fvisibility=hidden -flto=full -O2 a.cpp
-fPIC -o a -std=c++11 -stdlib=libc++ && ./a
S2
$ build/bin/clang++ -fsanitize=cfi -fvisibility=hidden -flto=thin -O2 a.cpp
-fPIC -o a -std=c++11 -stdlib=libc++ && ./a
S2
Question is to know whether this is due to some bug in libstdc++ or a bug in
CFI. Note that using the official LLVM 5 release, the bug happens for both C++
libraries, which might point to an actual CFI bug.
For the record, this bug has been found while building Clang/LLVM using clang
with CFI. This kind of construction (using std::make_shared) exists for
instance in clang's RealFileSystem::dir_begin function (in
clang/lib/Basic/VirtualFileSystem.cpp).
Please let me know if you need further information.
Regards,</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>