drogonframework / drogon

Drogon: A C++14/17/20 based HTTP web application framework running on Linux/macOS/Unix/Windows
MIT License
11.52k stars 1.1k forks source link

Segmentation fault in RedisTransaction #1066

Closed monolidth closed 2 years ago

monolidth commented 2 years ago

Segmentation fault in RedisTransaction

Hi @an-tao, thanks for the awesome open-source project and the effort you put in this project. I really appreciate your project!

Summary I added a cache functionality in our project and use coroutines to fetch a cache result. However, if I run my current implementation for a while I face a segmentation fault triggered from a fail assertion.

Trace

backend: /usr/include/drogon/utils/coroutine.h:504: const T& drogon::CallbackAwaiter<T>::await_resume() const [with T = std::shared_ptr<drogon::nosql::RedisTransaction>]: Assertion `result_.has_value() == true || exception_ != nullptr' failed.

To Reproduce

1. Define handler
 drogon::app().registerHandler(...) -> Task<> {
                                      co_await handleRequest(...);
                                  });

Where handleRequest first try to fetch the result from the redis cache and if it not present it perform a network call and write the result back to the cache.

2. Implement cache

 try {
        auto transaction = co_await redisClient->newTransactionCoro();
        auto result = co_await transaction->execCommandCoro("get %s", key.c_str());
        co_await transaction->executeCoro();
        // ...
} catch(...) {
  // ...
}

3. Use the cache

auto cacheResult = co_await Cache::get_cache_data(symbol, endpoint);
if (!cacheResult.empty()) {
    auto _resp = HttpResponse::newHttpResponse();
    _resp->setBody(cacheResult);
    _resp->setStatusCode(drogon::k200OK);
    _resp->setContentTypeCode(drogon::CT_APPLICATION_JSON);
    callback(_resp);
    co_return;
}

Expected behavior The segmentation fault should not occur.

System specifications

OS: Archlinux GCC Version: 11.1.0 C-ares: c-ares-1.18.1

Drogon specifications

Version: 1.7.3
Git commit: 0431f38a4eeb0b88a8d31fa8e858f3e4598aa569
Compilation:
  Compiler: /usr/lib/ccache/bin/c++
  Compiler ID: GNU
  Compilation flags: -O3 -DNDEBUG -std=c++17 -I/usr/include
Libraries:
  postgresql: yes  (batch mode: no)
  mariadb: yes
  sqlite3: yes
  openssl: yes
  brotli: yes
  boost: no
  hiredis: yes
  c-ares: yes

Additional context I run the drogon framework in a docker container. Nevertheless the segmentation fault occur on my debug machine as well.

Just let me know if you need additionally information or a test stub.

Regards, William Todt

an-tao commented 2 years ago

@monolidth , thanks for the feedback, could you please make a demo code to reproduce this problem? I need to debug it in my local environment.

monolidth commented 2 years ago

Thank you for the immediate feedback. I will prepare a demo code as soon as possible.

monolidth commented 2 years ago

Cannot reproduce, it is so a random bug but will try.

an-tao commented 2 years ago

It's like a race condition somewhere, note that when the database coroutine resume, it's in the thread of the I/O thread of the DbClient, so please pay attention to the shared state which may be accessed in multiple threads.

monolidth commented 2 years ago

Send the demo code via email. Thank you!