Skip to content

Occasional crash in client when server disconnects (std::logic_error: uninitialized stream object) #979

Closed
@zpalmtree

Description

@zpalmtree

I've got this library working well in my client, however, I'm having a rare exception thrown which I can't handle, when the server terminates. After closing the server, occasionally, a few seconds after, the client will terminate with:

terminate called after throwing an instance of 'std::logic_error'
  what():  uninitialized stream object

This appears to be thrown from here: https://github.com/Microsoft/cpprestsdk/blob/2a19d84af30567ad6c1ce6d14ab13f89bb618d74/Release/include/cpprest/streams.h

Note that I am not running cpprestsdk on the server - It's a custom stack.

Now, I have no issue with it throwing if the server disconnects, that's to be expected. However, it's an exception thrown in another thread, so I am unable to catch it.

Most of the time, I'll get one of these exceptions:

Caught exception: Failed to read HTTP status line
Caught exception: Failed to write request body
Caught exception: Failed to connect to any resolved endpoint

All good - I can just put a catch around my .wait() or .get() and handle them.

However, with the std::logic_error, we can see from the backtrace that it is thrown in another thread, so there is no way for us to catch it (I think):

(gdb) bt
#0  0x00007f5660c67d7f in raise () from /usr/lib/libc.so.6
#1  0x00007f5660c52672 in abort () from /usr/lib/libc.so.6
#2  0x00007f566101e58e in __gnu_cxx::__verbose_terminate_handler () at /build/gcc/src/gcc/libstdc++-v3/libsupc++/vterminate.cc:95
#3  0x00007f5661024dfa in __cxxabiv1::__terminate (handler=<optimized out>) at /build/gcc/src/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:47
#4  0x00007f5661024e57 in std::terminate () at /build/gcc/src/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:57
#5  0x000055c7ff06be9f in __clang_call_terminate () at /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/basic_string.h:657
#6  0x000055c7ff35d441 in (anonymous namespace)::threadpool_impl::thread_start (arg=0x55c7ff764770 <(anonymous namespace)::initialize_shared_threadpool(unsigned long)::storage>)
    at /home/zach/Code/turtlecoin/turtlecoin/external/cpprestsdk/Release/src/pplx/threadpool.cpp:99
#7  0x000055c7ff35d3e8 in (anonymous namespace)::threadpool_impl::add_thread()::{lambda()#1}::operator()() const (this=0x55c8009e25d8)
    at /home/zach/Code/turtlecoin/turtlecoin/external/cpprestsdk/Release/src/pplx/threadpool.cpp:81
#8  0x000055c7ff35d3c9 in boost::asio::detail::posix_thread::func<(anonymous namespace)::threadpool_impl::add_thread()::{lambda()#1}>::run() (this=0x55c8009e25d0)
    at /usr/include/boost/asio/detail/posix_thread.hpp:86
#9  0x000055c7ff361c39 in boost::asio::detail::boost_asio_detail_posix_thread_function (arg=0x55c8009e25d0) at /usr/include/boost/asio/detail/impl/posix_thread.ipp:74
#10 0x00007f566112ba9d in start_thread () from /usr/lib/libpthread.so.0
#11 0x00007f5660d2bb23 in clone () from /usr/lib/libc.so.6

Am I doing something wrong, or is this a fault in the library? Here's a slightly simplified version of what I'm doing:

void Proxy::backgroundRefresh()
{
    while (!m_shouldStop)
    {
        try
        {
            getDaemonInfo().wait();
        }
        catch (const std::exception &e)
        {
            std::cout << "Caught exception: " << e.what() << std::endl;
        }

        Utilities::sleepUnlessStopping(std::chrono::seconds(10), m_shouldStop);
    }
}

pplx::task<void> Proxy::getDaemonInfo()
{
    return m_httpClient->request(methods::GET, "/getinfo").then(
    [](http_response response)
    {
        return response.extract_string(true);
    })
    .then([this](std::string body)
    {
        // do some stuff
    });
}

I'm running this code, and in another thread calling another function, which does basically the same thing. Is it possible this is due to me using multiple threads? It seems strange that disconnecting the server would cause the crash, whilst it does not crash at any other point.

The other function:

std::vector<WalletTypes::WalletBlockInfo> Proxy::getWalletSyncData(
    const std::vector<Crypto::Hash> blockHashCheckpoints,
    uint64_t startHeight,
    uint64_t startTimestamp) const
{
    http_request req(methods::POST);
    req.set_request_uri("/getwalletsyncdata");

    json j = {
        {"blockHashCheckpoints", blockHashCheckpoints},
        {"startHeight", startHeight},
        {"startTimestamp", startTimestamp}
    };

    req.set_body(j.dump());

    try
    {
        return m_httpClient->request(req).then(
        [](http_response response)
        {
            return response.extract_string(true);
        })
        .then([](std::string body) -> std::vector<WalletTypes::WalletBlockInfo>
        {
            try
            {
                json j = json::parse(body);

                if (j.at("status").get<std::string>() != "OK")
                {
                     return {};
                }

                return j.at("items").get<std::vector<WalletTypes::WalletBlockInfo>>();
             }
             catch (const json::exception &e)
             {
                std::cout << "Caught exception: " << e.what() << std::endl;
             }

             return {};
        }).get();
    }
    catch (const std::exception &e)
    {
         std::cout << "Caught exception: " << e.what() << std::endl;
         return {};
    }
}

Possibly related to #857 - but I see that's been patched.

System info: Linux
Compiler: Clang-7
Library version: v2.10.8

Thanks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions