[llvm-bugs] [Bug 51515] New: [coroutines] [aarch64] ASAN stack-use-after-return when using initializer_list in the loop

via llvm-bugs llvm-bugs at lists.llvm.org
Tue Aug 17 14:48:45 PDT 2021


https://bugs.llvm.org/show_bug.cgi?id=51515

            Bug ID: 51515
           Summary: [coroutines] [aarch64] ASAN stack-use-after-return
                    when using initializer_list in the loop
           Product: clang
           Version: 12.0
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: C++2a
          Assignee: unassignedclangbugs at nondot.org
          Reporter: pa.solodovnikov at scylladb.com
                CC: blitzrakete at gmail.com, erik.pilkington at gmail.com,
                    llvm-bugs at lists.llvm.org, richard-llvm at metafoo.co.uk

Created attachment 25152
  --> https://bugs.llvm.org/attachment.cgi?id=25152&action=edit
Preprocessed source

The following program will report stack-use-after-return, when compiled with
Clang 12.0.0 (12.0.1, 13.0.0 and trunk, as well) and ASAN enabled:

        #include <initializer_list>

        ...

        class resumable {
        public:
                struct promise_type;
                using coro_handle =
std::experimental::coroutine_handle<promise_type>;

                resumable(coro_handle& handle) : handle(handle) {}
                resumable(resumable&&) = delete;

                ~resumable() {
                        handle.destroy();
                }

                bool resume() {
                        if (!handle.done()) {
                                handle.resume();
                        }
                        return !handle.done();
                }
        private:
                coro_handle handle;
        };

        struct resumable::promise_type {
                using coro_handle =
std::experimental::coroutine_handle<promise_type>;

                auto get_return_object() {
                        return coro_handle::from_promise(*this);
                }

                auto initial_suspend() { return
std::experimental::suspend_always(); }
                auto final_suspend() noexcept { return
std::experimental::suspend_always(); }
                void return_void() {}
                void unhandled_exception() {
                        throw;
                }
        };

        struct test_init_list {
              int item;

              test_init_list(std::initializer_list<int> items)  {
                  item = *items.begin();
              }
        };

        resumable foo() {
                for (int _ : {1, 2}) {
                    (void)_;
                    test_init_list x {0}; // <-- Crashes after the first
suspension
                    co_await std::experimental::suspend_always();
                }
        }

        int main() {
                auto p = foo();
                while (p.resume());
                return 0;
        }

Steps to reproduce:

        # build
        /usr/bin/clang++ -std=c++20 -fsanitize=address -Wall -Werror -Og -g -o
clang_coro_init_list_bug.cc.o -c clang_coro_init_list_bug.cc
        # link
        /usr/bin/clang++ clang_coro_init_list_bug.cc.o -o
clang_coro_init_list_bug -fsanitize=address
        # execute with ASAN

  
ASAN_OPTIONS='disable_coredump=0:abort_on_error=0:detect_stack_use_after_return=1'
./clang_coro_init_list_bug

Execution result:

=================================================================
==24==ERROR: AddressSanitizer: stack-use-after-return on address 0xffff8630e0e0
at pc 0x0000004eeed0 bp 0xffffdc7a11c0 sp 0xffffdc7a11d8
READ of size 4 at 0xffff8630e0e0 thread T0
    #0 0x4eeecc  (/home/pa.solodovnikov/clang_coro_init_list_bug_pp+0x4eeecc)
    #1 0x4ee964  (/home/pa.solodovnikov/clang_coro_init_list_bug_pp+0x4ee964)
    #2 0x4ef170  (/home/pa.solodovnikov/clang_coro_init_list_bug_pp+0x4ef170)
    #3 0x4eef58  (/home/pa.solodovnikov/clang_coro_init_list_bug_pp+0x4eef58)
    #4 0x4ee698  (/home/pa.solodovnikov/clang_coro_init_list_bug_pp+0x4ee698)
    #5 0xffff899a2b18  (/lib64/libc.so.6+0x24b18)
    #6 0x421d8c  (/home/pa.solodovnikov/clang_coro_init_list_bug_pp+0x421d8c)

Address 0xffff8630e0e0 is located in stack of thread T0 at offset 32 in frame
    #0 0x4ee71c  (/home/pa.solodovnikov/clang_coro_init_list_bug_pp+0x4ee71c)

  This frame has 1 object(s):
    [32, 36) 'ref.tmp14' <== Memory access at offset 32 is inside this variable
HINT: this may be a false positive if your program uses some custom stack
unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-return
(/home/pa.solodovnikov/clang_coro_init_list_bug_pp+0x4eeecc) 
Shadow bytes around the buggy address:
  0x200ff0c61bc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x200ff0c61bd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x200ff0c61be0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x200ff0c61bf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x200ff0c61c00: f1 f1 f1 f1 00 f3 f3 f3 f5 f5 f5 f5 f5 f5 f5 f5
=>0x200ff0c61c10: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5[f5]f5 f5 f5
  0x200ff0c61c20: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x200ff0c61c30: f1 f1 f1 f1 04 f3 f3 f3 f1 f1 f1 f1 00 00 f3 f3
  0x200ff0c61c40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x200ff0c61c50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x200ff0c61c60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==24==ABORTING

Decoded stack trace:

[Backtrace #0]
test_init_list at /home/pa.solodovnikov/clang_coro_init_list_bug.cc:129
foo() at /home/pa.solodovnikov/clang_coro_init_list_bug.cc:136
std::experimental::coroutine_handle<resumable::promise_type>::resume() const at
/home/pa.solodovnikov/clang_coro_init_list_bug.cc:38
resumable::resume() at /home/pa.solodovnikov/clang_coro_init_list_bug.cc:102
main at /home/pa.solodovnikov/clang_coro_init_list_bug.cc:143
__libc_start_main at ??:?
_start at ??:?

This points to the following place in the code, where initializer list data is
accessed:

              test_init_list(std::initializer_list<int> items)  {
                  item = *items.begin();
              }

List initialization is broken after the first coroutine suspension. I have
added debug printouts around the crash site:

      test_init_list(std::initializer_list<int> items)  {
          std::cout << "initializer list address: " << &items << std::endl;
          std::cout << "initializer list data pointer: " << std::data(items) <<
std::endl;
          item = *items.begin();
      }

This shows, that the address to the underlying storage is the same (obviously
points to garbage after a coroutine is resumed):

        initializer list address: 0xffff85fbd120
        initializer list data pointer: 0xffff85fbd0e0
        initializer list address: 0xffff85fbd220
        initializer list data pointer: 0xffff85fbd0e0

The problem only happens with the following combination: aarch64 target, ASAN
enabled (-fsanitize=address), -Og optimization level (-Oz or -Os are also
affected). Tested with libstdc++ 11.2.1.

When built with GCC 11.2.1, the code compiles and executes without errors.

I have also attached a preprocessed version of source code.

-- 
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/20210817/a45d574b/attachment-0001.html>


More information about the llvm-bugs mailing list