[llvm-bugs] [Bug 38313] New: [coroutines] Compiler is incorrectly calculating the address of a parameter reference passed to promise_type::operator new()
via llvm-bugs
llvm-bugs at lists.llvm.org
Wed Jul 25 13:28:03 PDT 2018
https://bugs.llvm.org/show_bug.cgi?id=38313
Bug ID: 38313
Summary: [coroutines] Compiler is incorrectly calculating the
address of a parameter reference passed to
promise_type::operator new()
Product: clang
Version: trunk
Hardware: PC
OS: All
Status: NEW
Severity: enhancement
Priority: P
Component: LLVM Codegen
Assignee: unassignedclangbugs at nondot.org
Reporter: lewissbaker at gmail.com
CC: llvm-bugs at lists.llvm.org
Using build of clang from trunk (rev 336842).
- libc++ rev 336382 with diff from D46140 applied
- llvm rev 336841
A test-case added in https://reviews.llvm.org/D46140 that checks that I can
pass a `std::experimental::pmr::polymorphic_allocator` into a coroutine and
have it use that allocator to allocate the coroutine frame is failing with an
access-violation under debug builds.
Run: `lit -v --param=compile_flags='-O0'
libcxx/test/std/experimental/task/task.basic/task_custom_allocator.pass.cpp`
Test passes if I change `-O0` to `-O2`.
The (simplified) client code from `task_custom_allocator.pass.cpp` looks
something like this:
```c++
template<typename Allocator>
coro::task<void> f(std::allocator_arg_t, [[maybe_unused]] Allocator alloc)
{
co_return;
}
void test_mixed_custom_allocator_type_erasure()
{
std::vector<coro::task<>> tasks;
tasks.push_back(f(
std::allocator_arg,
std::experimental::pmr::polymorphic_allocator<char>{
std::experimental::pmr::new_delete_resource() }));
for (auto& t : tasks)
{
coro::sync_wait(t);
}
}
```
The implementation of the `task<T>::promise_type` has an overload of `operator
new` that looks like this:
```c++
template<typename _Alloc, typename... _Args>
static operator new(std::allocator_arg_t, _Alloc& __allocator, _Args&...)
{
using _CharAlloc =
typename allocator_traits<_Alloc>::template rebind_alloc<char>;
_CharAlloc __charAllocator{__allocator};
void* __pointer = __charAllocator.allocate(
__get_padded_frame_size_with_allocator<_CharAlloc>(__size));
...
}
```
The compiler is required to generate code that passes lvalue references to
parameters passed to the coroutine function into the `operator new()` call.
What I'm seeing is that the code generated under debug builds (`-fcoroutine-ts
-O0`) is incorrectly calculating the address of the `alloc` parameter of `f()`
when passing it into the call to `operator new()`.
The assembly for the start of the coroutine function, `f()`, looks like:
```
task_custom_allocator.pass.cpp.exe`f<std::experimental::fundamentals_v1::pmr::polymorphic_allocator<char>
>:
-> 0x100004170 <+0>: pushq %rbp
0x100004171 <+1>: movq %rsp, %rbp
0x100004174 <+4>: subq $0x110, %rsp ; imm = 0x110
0x10000417b <+11>: movq %rdi, %rax
0x10000417e <+14>: xorl %ecx, %ecx
0x100004180 <+16>: movl %ecx, %edx
0x100004182 <+18>: movb $0x1, %r8b
0x100004185 <+21>: testb $0x1, %r8b
0x100004189 <+25>: movq %rax, -0x70(%rbp)
0x10000418d <+29>: movq %rsi, -0x78(%rbp)
0x100004191 <+33>: movq %rdi, -0x80(%rbp)
0x100004195 <+37>: movq %rdx, -0x88(%rbp)
0x10000419c <+44>: jne 0x1000041b5 ; <+69> at
task_custom_allocator.pass.cpp
0x1000041a2 <+50>: movq -0x88(%rbp), %rax
0x1000041a9 <+57>: movq %rax, -0x90(%rbp)
0x1000041b0 <+64>: jmp 0x1000041da ; <+106> at
task_custom_allocator.pass.cpp:99
0x1000041b5 <+69>: movl $0xf0, %eax
0x1000041ba <+74>: movl %eax, %edi
0x1000041bc <+76>: leaq -0x40(%rbp), %rsi
0x1000041c0 <+80>: callq 0x10001012a ; symbol stub for:
void* std::experimental::coroutines_v1::__task_promise_base::operator
new<std::experimental::fundamentals_v1::pmr::polymorphic_allocator<char>
>(unsigned long, std::__1::allocator_arg_t,
std::experimental::fundamentals_v1::pmr::polymorphic_allocator<char>&)
0x1000041c5 <+85>: movq %rax, -0x98(%rbp)
<snip>
```
Here, the calling convention has the polymorphic allocator being passed in
register `rsi` which then is stored at the location `-0x78(%rbp)`.
Then, when it generates the call to `operator new()` it passes in the address
of the `alloc` parameter as `-0x40(%ebp)`. The contents at this address is the
null pointer and so when the `operator new` implementation subsequently
attempts to call `.allocate()` it hits an access violation dereferencing the
pointer.
--
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20180725/89adb2cb/attachment.html>
More information about the llvm-bugs
mailing list