lewissbaker / cppcoro

A library of C++ coroutine abstractions for the coroutines TS
MIT License
3.43k stars 472 forks source link

Nested Coroutine Valgrind Error #65

Closed oneleggedredcow closed 6 years ago

oneleggedredcow commented 6 years ago

I was attempting to write a nested coroutine, and kept getting errors. Here's a simple test case of what I was trying to do:

#include <iostream>

#include "generator.hpp"

cppcoro::generator<int> nested() {
  for (int i = 0; i < 10; i++) {
    co_yield i;
  }
}

cppcoro::generator<int> outer() {
  for (auto inner : nested()) {
    co_yield inner;
  }
}

int main() {
  for (const auto& value : outer()) {
    std::cout << value << std::endl;
  }
  return 0;
}

Running that program through valgrind yields the following errors:

==22418== Memcheck, a memory error detector
==22418== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==22418== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==22418== Command: ./test
==22418== 
0
1
2
3
4
5
6
7
8
9
==22418== Invalid read of size 4
==22418==    at 0x401E36: nested() [clone .destroy] (test.cxx:0)
==22418==    by 0x403250: destroy (coroutine:130)
==22418==    by 0x403250: cppcoro::generator<int>::~generator() (generator.hpp:163)
==22418==    by 0x4025A9: outer() [clone .resume] (test.cxx:12)
==22418==    by 0x4033D6: resume (coroutine:123)
==22418==    by 0x4033D6: cppcoro::detail::generator_iterator<int>::operator++() (generator.hpp:108)
==22418==    by 0x401818: main (test.cxx:18)
==22418==  Address 0x60b4280 is 208 bytes inside a block of size 264 free'd
==22418==    at 0x4C30D18: free (vg_replace_malloc.c:530)
==22418==    by 0x401E31: nested() [clone .destroy] (test.cxx:5)
==22418==    by 0x403250: destroy (coroutine:130)
==22418==    by 0x403250: cppcoro::generator<int>::~generator() (generator.hpp:163)
==22418==    by 0x4025A9: outer() [clone .resume] (test.cxx:12)
==22418==    by 0x4033D6: resume (coroutine:123)
==22418==    by 0x4033D6: cppcoro::detail::generator_iterator<int>::operator++() (generator.hpp:108)
==22418==    by 0x401818: main (test.cxx:18)
==22418==  Block was alloc'd at
==22418==    at 0x4C2FB6B: malloc (vg_replace_malloc.c:299)
==22418==    by 0x4EC1B79: operator new(unsigned long) (in /usr/lib64/libc++.so.1.0)
==22418==    by 0x400C73: nested() (test.cxx:5)
==22418==    by 0x40228B: outer() [clone .resume] (test.cxx:12)
==22418==    by 0x4032BC: resume (coroutine:123)
==22418==    by 0x4032BC: cppcoro::generator<int>::begin() (generator.hpp:177)
==22418==    by 0x401762: main (test.cxx:18)
==22418== 
==22418== Invalid read of size 4
==22418==    at 0x402B0A: outer() [clone .destroy] (test.cxx:0)
==22418==    by 0x403250: destroy (coroutine:130)
==22418==    by 0x403250: cppcoro::generator<int>::~generator() (generator.hpp:163)
==22418==    by 0x40179E: main (test.cxx:18)
==22418==  Address 0x60b4110 is 208 bytes inside a block of size 296 free'd
==22418==    at 0x4C30D18: free (vg_replace_malloc.c:530)
==22418==    by 0x402B05: outer() [clone .destroy] (test.cxx:11)
==22418==    by 0x403250: destroy (coroutine:130)
==22418==    by 0x403250: cppcoro::generator<int>::~generator() (generator.hpp:163)
==22418==    by 0x40179E: main (test.cxx:18)
==22418==  Block was alloc'd at
==22418==    at 0x4C2FB6B: malloc (vg_replace_malloc.c:299)
==22418==    by 0x4EC1B79: operator new(unsigned long) (in /usr/lib64/libc++.so.1.0)
==22418==    by 0x4010F3: outer() (test.cxx:11)
==22418==    by 0x401751: main (test.cxx:18)
==22418== 
==22418== 
==22418== HEAP SUMMARY:
==22418==     in use at exit: 0 bytes in 0 blocks
==22418==   total heap usage: 3 allocs, 3 frees, 1,584 bytes allocated
==22418== 
==22418== All heap blocks were freed -- no leaks are possible
==22418== 
==22418== For counts of detected and suppressed errors, rerun with: -v
==22418== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

Here's the line used to compile the program:

clang++ -std=c++17 -fcoroutines-ts -stdlib=libc++ -g test.cxx -o test

And here's my clang version:

clang version 5.0.1 (tags/RELEASE_501/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

So, what am I doing wrong?

lewissbaker commented 6 years ago

I have seen something similar under MSVC too, but I attribute that to a compiler bug as it only occurs under optimised builds.

Have you tried using a nightly build of clang 6? I know there were some bugs with the clang 5 implementation of coroutines and there have been some fixes added to mainline since clang 5 was branched that may not have been backported. eg. You could be seeing https://bugs.llvm.org/show_bug.cgi?id=34289

oneleggedredcow commented 6 years ago

Awesome! That did the trick. Thanks!