3rdparty / eventuals-grpc

C++ asynchronous interface for gRPC based on https://github.com/3rdparty/eventuals.
Apache License 2.0
20 stars 5 forks source link

use-after-free on RPCs #71

Closed CodingCanuck closed 2 years ago

CodingCanuck commented 2 years ago

EventualsGrpcTest.CancelledByClient exhibits a use-after-free on this line: https://github.com/3rdparty/eventuals-grpc/blob/b40df00734f5ecdb3f680d255b7226dcf3648701/test/cancelled-by-client.cc#L71

Which evaluates the eventual constructed here: https://github.com/3rdparty/eventuals-grpc/blob/b40df00734f5ecdb3f680d255b7226dcf3648701/test/cancelled-by-client.cc#L63-L69

This is easily reproducible with asan (which is added in https://github.com/3rdparty/eventuals-grpc/pull/70 : that's being auto-merged now so it should land soon):

bazel test --config=asan //test:grpc

Sample failure log showing a use-after-free:

[==========] Running 19 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 19 tests from EventualsGrpcTest
[ RUN      ] EventualsGrpcTest.ServeValidate
[       OK ] EventualsGrpcTest.ServeValidate (12 ms)
[ RUN      ] EventualsGrpcTest.BuildAndStart
[       OK ] EventualsGrpcTest.BuildAndStart (2 ms)
[ RUN      ] EventualsGrpcTest.CancelledByClient
=================================================================
==1930439==ERROR: AddressSanitizer: heap-use-after-free on address 0x623000000dd0 at pc 0x555fe27c0435 bp 0x7ffc41cd3690 sp 0x7ffc41cd3688
WRITE of size 8 at 0x623000000dd0 thread T0
    #0 0x555fe27c0434 in grpc::ClientAsyncReaderWriter<helloworld::HelloRequest, helloworld::HelloReply>::~ClientAsyncReaderWriter() external/com_github_grpc_grpc/include/grpcpp/impl/codegen/async_stream.h:511
    #1 0x555fe27c0434 in grpc::ClientAsyncReaderWriter<helloworld::HelloRequest, helloworld::HelloReply>::~ClientAsyncReaderWriter() external/com_github_grpc_grpc/include/grpcpp/impl/codegen/async_stream.h:511
    #2 0x555fe27c0434 in std::default_delete<grpc::ClientAsyncReaderWriter<helloworld::HelloRequest, helloworld::HelloReply> >::operator()(grpc::ClientAsyncReaderWriter<helloworld::HelloRequest, helloworld::HelloReply>*) const /usr/include/c++/11/bits/unique_ptr.h:85
    #3 0x555fe27c0434 in std::unique_ptr<grpc::ClientAsyncReaderWriter<helloworld::HelloRequest, helloworld::HelloReply>, std::default_delete<grpc::ClientAsyncReaderWriter<helloworld::HelloRequest, helloworld::HelloReply> > >::~unique_ptr() /usr/include/c++/11/bits/unique_ptr.h:361
    #4 0x555fe27c0434 in eventuals::grpc::ClientCall<helloworld::HelloRequest, helloworld::HelloReply>::~ClientCall() eventuals/grpc/client.h:119
    #5 0x555fe2786648 in ~<lambda> external/com_github_3rdparty_eventuals/eventuals/let.h:44
    #6 0x555fe2786648 in ~Continuation external/com_github_3rdparty_eventuals/eventuals/closure.h:21
    #7 0x555fe2786648 in _M_destroy /usr/include/c++/11/optional:260
    #8 0x555fe2786648 in _M_reset /usr/include/c++/11/optional:280
    #9 0x555fe2786648 in ~_Optional_payload /usr/include/c++/11/optional:401
    #10 0x555fe2786648 in ~_Optional_base /usr/include/c++/11/optional:472
    #11 0x555fe2786648 in ~optional /usr/include/c++/11/optional:662
    #12 0x555fe2786648 in ~Continuation external/com_github_3rdparty_eventuals/eventuals/then.h:119
    #13 0x555fe2786648 in ~Continuation external/com_github_3rdparty_eventuals/eventuals/then.h:119
    #14 0x555fe27a9561 in ~Continuation external/com_github_3rdparty_eventuals/eventuals/scheduler.h:95
    #15 0x555fe27a9561 in _M_destroy /usr/include/c++/11/optional:260
    #16 0x555fe27a9561 in _M_reset /usr/include/c++/11/optional:280
    #17 0x555fe27a9561 in ~_Optional_payload /usr/include/c++/11/optional:401
    #18 0x555fe27a9561 in ~_Optional_base /usr/include/c++/11/optional:472
    #19 0x555fe27a9561 in ~optional /usr/include/c++/11/optional:662
    #20 0x555fe27a9561 in ~Reschedulable external/com_github_3rdparty_eventuals/eventuals/scheduler.h:269
    #21 0x555fe27a9561 in ~Continuation external/com_github_3rdparty_eventuals/eventuals/eventual.h:32
    #22 0x555fe27a9561 in ~_Head_base /usr/include/c++/11/tuple:187
    #23 0x555fe27a9561 in ~_Tuple_impl /usr/include/c++/11/tuple:416
    #24 0x555fe27a9561 in ~_Tuple_impl /usr/include/c++/11/tuple:258
    #25 0x555fe27a9561 in ~tuple /usr/include/c++/11/tuple:985
    #26 0x555fe27a9561 in operator*<eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > > > external/com_github_3rdparty_eventuals/eventuals/terminal.h:266
    #27 0x555fe27a9561 in EventualsGrpcTest_CancelledByClient_Test::TestBody() test/cancelled-by-client.cc:71
    #28 0x555fe3c6ed37 in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) external/com_github_google_googletest/googletest/src/gtest.cc:2607
    #29 0x555fe3c6ed37 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) external/com_github_google_googletest/googletest/src/gtest.cc:2643
    #30 0x555fe3c4c942 in testing::Test::Run() external/com_github_google_googletest/googletest/src/gtest.cc:2682
    #31 0x555fe3c4d032 in testing::TestInfo::Run() external/com_github_google_googletest/googletest/src/gtest.cc:2861
    #32 0x555fe3c4dff2 in testing::TestSuite::Run() external/com_github_google_googletest/googletest/src/gtest.cc:3015
    #33 0x555fe3c4f92b in testing::internal::UnitTestImpl::RunAllTests() external/com_github_google_googletest/googletest/src/gtest.cc:5855
    #34 0x555fe3c6fc3d in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) external/com_github_google_googletest/googletest/src/gtest.cc:2607
    #35 0x555fe3c6fc3d in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) external/com_github_google_googletest/googletest/src/gtest.cc:2643
    #36 0x555fe3c4d317 in testing::UnitTest::Run() external/com_github_google_googletest/googletest/src/gtest.cc:5438
    #37 0x555fe3be9d0f in RUN_ALL_TESTS() external/com_github_google_googletest/googletest/include/gtest/gtest.h:2490
    #38 0x555fe3be9d0f in main external/com_github_google_googletest/googlemock/src/gmock_main.cc:70
    #39 0x7f01d94187ec in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x277ec)
    #40 0x555fe2676869 in _start (/home/alexmc/.cache/bazel/_bazel_alexmc/e5e83162f61030880de4b3e9d73ac179/execroot/com_github_3rdparty_eventuals_grpc/bazel-out/k8-dbg/bin/test/grpc+0x319869)

0x623000000dd0 is located 3280 bytes inside of 6503-byte region [0x623000000100,0x623000001a67)
freed by thread T0 here:
    #0 0x7f01d9a184d7 in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:127
    #1 0x555fe3b45d7d in gpr_free external/com_github_grpc_grpc/src/core/lib/gpr/alloc.cc:52
    #2 0x555fe3b45e49 in gpr_free_aligned external/com_github_grpc_grpc/src/core/lib/gpr/alloc.cc:75
    #3 0x555fe3b4d21d in grpc_core::Arena::Destroy() external/com_github_grpc_grpc/src/core/lib/gprpp/arena.cc:80
    #4 0x555fe37f20c4 in release_call external/com_github_grpc_grpc/src/core/lib/surface/call.cc:541
    #5 0x555fe38a2fb3 in exec_ctx_run external/com_github_grpc_grpc/src/core/lib/iomgr/exec_ctx.cc:43
    #6 0x555fe38a2fb3 in grpc_core::ExecCtx::Flush() external/com_github_grpc_grpc/src/core/lib/iomgr/exec_ctx.cc:165
    #7 0x555fe37fb0fd in grpc_core::ExecCtx::~ExecCtx() external/com_github_grpc_grpc/src/core/lib/iomgr/exec_ctx.h:126
    #8 0x555fe37fb0fd in grpc_call_unref external/com_github_grpc_grpc/src/core/lib/surface/call.cc:621
    #9 0x555fe2fb5c18 in grpc::ClientContext::~ClientContext() external/com_github_grpc_grpc/src/cpp/client/client_context.cc:71
    #10 0x555fe27a9544 in std::_Optional_payload_base<grpc::ClientContext>::_M_destroy() /usr/include/c++/11/optional:260
    #11 0x555fe27a9544 in std::_Optional_payload_base<grpc::ClientContext>::_M_reset() /usr/include/c++/11/optional:280
    #12 0x555fe27a9544 in std::_Optional_payload<grpc::ClientContext, false, false, false>::~_Optional_payload() /usr/include/c++/11/optional:401
    #13 0x555fe27a9544 in std::_Optional_base<grpc::ClientContext, false, false>::~_Optional_base() /usr/include/c++/11/optional:472
    #14 0x555fe27a9544 in std::optional<grpc::ClientContext>::~optional() /usr/include/c++/11/optional:662
    #15 0x555fe27a9544 in eventuals::_Context<grpc::ClientContext>::~_Context() external/com_github_3rdparty_eventuals/eventuals/context.h:15
    #16 0x555fe27a9544 in ~Continuation external/com_github_3rdparty_eventuals/eventuals/eventual.h:32
    #17 0x555fe27a9544 in ~_Head_base /usr/include/c++/11/tuple:187
    #18 0x555fe27a9544 in ~_Tuple_impl /usr/include/c++/11/tuple:416
    #19 0x555fe27a9544 in ~_Tuple_impl /usr/include/c++/11/tuple:258
    #20 0x555fe27a9544 in ~tuple /usr/include/c++/11/tuple:985
    #21 0x555fe27a9544 in operator*<eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > > > external/com_github_3rdparty_eventuals/eventuals/terminal.h:266
    #22 0x555fe27a9544 in EventualsGrpcTest_CancelledByClient_Test::TestBody() test/cancelled-by-client.cc:71
    #23 0x555fe3c6ed37 in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) external/com_github_google_googletest/googletest/src/gtest.cc:2607
    #24 0x555fe3c6ed37 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) external/com_github_google_googletest/googletest/src/gtest.cc:2643
    #25 0x555fe3c4c942 in testing::Test::Run() external/com_github_google_googletest/googletest/src/gtest.cc:2682
    #26 0x555fe3c4d032 in testing::TestInfo::Run() external/com_github_google_googletest/googletest/src/gtest.cc:2861
    #27 0x555fe3c4dff2 in testing::TestSuite::Run() external/com_github_google_googletest/googletest/src/gtest.cc:3015
    #28 0x555fe3c4f92b in testing::internal::UnitTestImpl::RunAllTests() external/com_github_google_googletest/googletest/src/gtest.cc:5855
    #29 0x555fe3c6fc3d in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) external/com_github_google_googletest/googletest/src/gtest.cc:2607
    #30 0x555fe3c6fc3d in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) external/com_github_google_googletest/googletest/src/gtest.cc:2643
    #31 0x555fe3c4d317 in testing::UnitTest::Run() external/com_github_google_googletest/googletest/src/gtest.cc:5438
    #32 0x555fe3be9d0f in RUN_ALL_TESTS() external/com_github_google_googletest/googletest/include/gtest/gtest.h:2490
    #33 0x555fe3be9d0f in main external/com_github_google_googletest/googlemock/src/gmock_main.cc:70
    #34 0x7f01d94187ec in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x277ec)

previously allocated by thread T0 here:
    #0 0x7f01d9a187cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x555fe3b45d33 in gpr_malloc external/com_github_grpc_grpc/src/core/lib/gpr/alloc.cc:32
    #2 0x555fe3b45dc6 in gpr_malloc_aligned external/com_github_grpc_grpc/src/core/lib/gpr/alloc.cc:68
    #3 0x555fe3b4d0cb in ArenaStorage external/com_github_grpc_grpc/src/core/lib/gprpp/arena.cc:46
    #4 0x555fe3b4d0cb in grpc_core::Arena::CreateWithAlloc(unsigned long, unsigned long) external/com_github_grpc_grpc/src/core/lib/gprpp/arena.cc:72
    #5 0x555fe37fe279 in grpc_call_create(grpc_call_create_args const*, grpc_call**) external/com_github_grpc_grpc/src/core/lib/surface/call.cc:367
    #6 0x555fe37e1832 in grpc_channel_create_call_internal external/com_github_grpc_grpc/src/core/lib/surface/channel.cc:374
    #7 0x555fe37e4524 in grpc_channel_create_call external/com_github_grpc_grpc/src/core/lib/surface/channel.cc:387
    #8 0x555fe2fe919b in grpc::Channel::CreateCallInternal(grpc::internal::RpcMethod const&, grpc::ClientContext*, grpc::CompletionQueue*, unsigned long) external/com_github_grpc_grpc/src/cpp/client/channel_cc.cc:135
    #9 0x555fe2fea702 in grpc::Channel::CreateCall(grpc::internal::RpcMethod const&, grpc::ClientContext*, grpc::CompletionQueue*) external/com_github_grpc_grpc/src/cpp/client/channel_cc.cc:161
    #10 0x555fe279bf6d in grpc::internal::ClientAsyncReaderWriterFactory<helloworld::HelloRequest, helloworld::HelloReply>::Create(grpc::ChannelInterface*, grpc::CompletionQueue*, grpc::internal::RpcMethod const&, grpc::ClientContext*, bool, void*) external/com_github_grpc_grpc/include/grpcpp/impl/codegen/async_stream.h:497
    #11 0x555fe279bf6d in grpc::TemplatedGenericStub<helloworld::HelloRequest, helloworld::HelloReply>::CallInternal(grpc::ChannelInterface*, grpc::ClientContext*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, grpc::StubOptions, grpc::CompletionQueue*, bool, void*) external/com_github_grpc_grpc/include/grpcpp/generic/generic_stub.h:167
    #12 0x555fe279bf6d in grpc::TemplatedGenericStub<helloworld::HelloRequest, helloworld::HelloReply>::PrepareCall(grpc::ClientContext*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, grpc::CompletionQueue*) external/com_github_grpc_grpc/include/grpcpp/generic/generic_stub.h:58
    #13 0x555fe279bf6d in operator()<eventuals::_Reschedule::Continuation<eventuals::_Then::Adaptor<eventuals::_Then::Continuation<eventuals::_Terminal::Continuation<std::promise<grpc::Status>, eventuals::Terminate<eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > > >(eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > >)::<lambda(auto:75&, auto:76&& ...)>, eventuals::Terminate<eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > > >(eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > >)::<lambda(auto:77&, auto:78&& ...)>, eventuals::Terminate<eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > > >(eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > >)::<lambda(auto:79&)> >, eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)>, eventuals::grpc::ClientCall<helloworld::HelloRequest, helloworld::HelloReply>, true> >, eventuals::grpc::ClientCall<helloworld::HelloRequest, helloworld::HelloReply> > > eventuals/grpc/client.h:319
    #14 0x555fe279bf6d in Start<> external/com_github_3rdparty_eventuals/eventuals/eventual.h:61
    #15 0x555fe279bf6d in Start<grpc::ClientContext*> external/com_github_3rdparty_eventuals/eventuals/then.h:134
    #16 0x555fe27a8615 in operator() external/com_github_3rdparty_eventuals/eventuals/scheduler.h:100
    #17 0x555fe27a8615 in Continue<eventuals::_Reschedule::Continuation<eventuals::_Then::Continuation<eventuals::_Then::Continuation<eventuals::_Terminal::Continuation<std::promise<grpc::Status>, eventuals::Terminate<eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > > >(eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > >)::<lambda(auto:75&, auto:76&& ...)>, eventuals::Terminate<eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > > >(eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > >)::<lambda(auto:77&, auto:78&& ...)>, eventuals::Terminate<eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > > >(eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > >)::<lambda(auto:79&)> >, eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)>, eventuals::grpc::ClientCall<helloworld::HelloRequest, helloworld::HelloReply>, true>, eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)>, grpc::ClientContext*, true>, grpc::ClientContext*>::Start<grpc::ClientContext*>(grpc::ClientContext*&&)::<lambda()>, eventuals::_Reschedule::Continuation<eventuals::_Then::Continuation<eventuals::_Then::Continuation<eventuals::_Terminal::Continuation<std::promise<grpc::Status>, eventuals::Terminate<eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > > >(eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > >)::<lambda(auto:75&, auto:76&& ...)>, eventuals::Terminate<eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > > >(eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()
    #18 0x555fe27a8615 in Start<grpc::ClientContext*> external/com_github_3rdparty_eventuals/eventuals/scheduler.h:98
    #19 0x555fe27a8615 in operator()<eventuals::_Context<grpc::ClientContext>, eventuals::_Reschedule::Continuation<eventuals::_Then::Continuation<eventuals::_Then::Continuation<eventuals::_Terminal::Continuation<std::promise<grpc::Status>, eventuals::Terminate<eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > > >(eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > >)::<lambda(auto:75&, auto:76&& ...)>, eventuals::Terminate<eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > > >(eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > >)::<lambda(auto:77&, auto:78&& ...)>, eventuals::Terminate<eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > > >(eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > >)::<lambda(auto:79&)> >, eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)>, eventuals::grpc::ClientCall<helloworld::HelloRequest, helloworld::HelloReply>, true>, eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)>, grpc::ClientContext*, true>, grpc::ClientContext*> > eventuals/grpc/client.h:240
    #20 0x555fe27a8615 in Start<> external/com_github_3rdparty_eventuals/eventuals/eventual.h:56
    #21 0x555fe27a8615 in operator*<eventuals::Composed<eventuals::Composed<eventuals::_Eventual::Builder<eventuals::_Context<grpc::ClientContext>, eventuals::grpc::Client::Context()::<lambda(auto:43&, auto:44&)>, eventuals::Undefined, eventuals::Undefined, false, grpc::ClientContext*>, eventuals::_Then::Composable<eventuals::grpc::Client::Call<helloworld::HelloRequest, helloworld::HelloReply>(std::string, std::optional<std::__cxx11::basic_string<char> >)::<lambda(grpc::ClientContext*)> > >, eventuals::_Then::Composable<eventuals::Let<EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)> >(EventualsGrpcTest_CancelledByClient_Test::TestBody()::<lambda()>::<lambda(auto:102&)>)::<lambda(auto:100)> > > > external/com_github_3rdparty_eventuals/eventuals/terminal.h:263
    #22 0x555fe27a8615 in EventualsGrpcTest_CancelledByClient_Test::TestBody() test/cancelled-by-client.cc:71
    #23 0x555fe3c6ed37 in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) external/com_github_google_googletest/googletest/src/gtest.cc:2607
    #24 0x555fe3c6ed37 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) external/com_github_google_googletest/googletest/src/gtest.cc:2643
    #25 0x555fe3c4c942 in testing::Test::Run() external/com_github_google_googletest/googletest/src/gtest.cc:2682
    #26 0x555fe3c4d032 in testing::TestInfo::Run() external/com_github_google_googletest/googletest/src/gtest.cc:2861
    #27 0x555fe3c4dff2 in testing::TestSuite::Run() external/com_github_google_googletest/googletest/src/gtest.cc:3015
    #28 0x555fe3c4f92b in testing::internal::UnitTestImpl::RunAllTests() external/com_github_google_googletest/googletest/src/gtest.cc:5855
    #29 0x555fe3c6fc3d in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) external/com_github_google_googletest/googletest/src/gtest.cc:2607
    #30 0x555fe3c6fc3d in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) external/com_github_google_googletest/googletest/src/gtest.cc:2643
    #31 0x555fe3c4d317 in testing::UnitTest::Run() external/com_github_google_googletest/googletest/src/gtest.cc:5438
    #32 0x555fe3be9d0f in RUN_ALL_TESTS() external/com_github_google_googletest/googletest/include/gtest/gtest.h:2490
    #33 0x555fe3be9d0f in main external/com_github_google_googletest/googlemock/src/gmock_main.cc:70
    #34 0x7f01d94187ec in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x277ec)

SUMMARY: AddressSanitizer: heap-use-after-free external/com_github_grpc_grpc/include/grpcpp/impl/codegen/async_stream.h:511 in grpc::ClientAsyncReaderWriter<helloworld::HelloRequest, helloworld::HelloReply>::~ClientAsyncReaderWriter()
Shadow bytes around the buggy address:
  0x0c467fff8160: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c467fff8170: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c467fff8180: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c467fff8190: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c467fff81a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x0c467fff81b0: fd fd fd fd fd fd fd fd fd fd[fd]fd fd fd fd fd
  0x0c467fff81c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c467fff81d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c467fff81e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c467fff81f0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c467fff8200: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
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
==1930439==ABORTING
CodingCanuck commented 2 years ago

@benh in case you want to poke at this: it looks like the use-after-free we were discussing might be coming from eventuals-grpc (or even eventuals).

benh commented 2 years ago

Awesome stuff @CodingCanuck!

I have a hypothesis here that ::grpc::ClientContext can not be deleted before ::grpc::ClientAsyncReaderWriter (although I can't confirm via documentation and the API is only suggestive of this requirement but not definitive).

Unfortunately trying the temporary hack of allocating ::grpc::ClientContext on the heap and never deleting it does not fix the branch that @while-false and I were working on, so while this definitely needs to be fixed I'm not sure it's our smoking gun yet!

I'll dig deeper into @while-false's branch tomorrow as well as propose a fix for this issue.

So glad to have asan turned on!

CodingCanuck commented 2 years ago

Relevant: https://github.com/grpc/grpc/issues/16877 and https://github.com/grpc/grpc/pull/17386/files

So you're correct, clientContext cannot be deleted before ClientAsyncReaderWriter.

CodingCanuck commented 2 years ago

Given this, it sounds like the problem / fix should be in this scope: https://github.com/3rdparty/eventuals-grpc/blob/0f66b899e72ce34f6242b7b432a5ea1d9ab61b85/eventuals/grpc/client.h#L370-L383

Ben, is there any documentation on how eventuals' destruction order works? I'm guessing that for this:

  template <typename Request, typename Response>
    return Context()
        | Then([this,
                name = std::move(name),
                host = std::move(host)](
                   ::grpc::ClientContext* context) mutable {
             return Call<Request, Response>(
                 std::move(name),
                 context,
                 std::move(host));
           });

The issue is that the memory in which the result of Context() is stored is destroyed first, and after that the memory in which the result of Call() is allocated is destroyed second. It seems we should invert that, in a similar fashion to how constructors are called least-to-most derived yet destructors are called in the reversed most-to-least derived order.

Edit: I think my understanding is insufficient / wrong here. operator| already seems to create a struct with two fields where the left-hand thing is stored before the right-hand thing (and thus the right-hand thing will be destructed first), so I don't understand how the Call is being destroyed before the Context is. (I'm guessing my misunderstanding in how Then() works, where maybe the Call() there has a lifetime separate to the Context() and Then() lifetimes)