A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/microsoft/cpprestsdk/issues/1085 below:

Data race on _pplx_g_sched_t::get_scheduler() · Issue #1085 · microsoft/cpprestsdk · GitHub

Google's thread sanitizer is reporting a data race on _pplx_g_sched_t::get_scheduler() function which I discovered creating multiple websocket instances at the same time on Linux.

You can run this simpler snippet to reproduce:

#include <thread>
#include <cpprest/ws_client.h>

int main() {
  //pplx::get_ambient_scheduler();  // uncomment this line to fix the data race
  std::thread a([] () { pplx::get_ambient_scheduler(); });
  std::thread b([] () { pplx::get_ambient_scheduler(); });
  a.join();
  b.join();
  return 0;
}

This is sanitizer's output:

==================
WARNING: ThreadSanitizer: data race (pid=4653)
  Read of size 8 at 0x7f96cf428c50 by thread T2:
    #0 std::__shared_ptr<pplx::scheduler_interface, (__gnu_cxx::_Lock_policy)2>::operator bool() const /usr/include/c++/8.2.1/bits/shared_ptr_base.h:1291 (libcpprest.so.2.10+0xa787a2)
    #1 pplx::_pplx_g_sched_t::get_scheduler() /home/bambino/projects/tradehelm/libfix-adapter/vendor/cpprest/Release/src/pplx/pplx.cpp:77 (libcpprest.so.2.10+0xa784e4)
    #2 pplx::get_ambient_scheduler() /home/bambino/projects/tradehelm/libfix-adapter/vendor/cpprest/Release/src/pplx/pplx.cpp:125 (libcpprest.so.2.10+0xa77e36)
    #3 operator() /data/projects/pruebas/c++/pplx-ambient-scheduler.cpp:7 (a.out+0x33a9)
    #4 __invoke_impl<void, main()::<lambda()> > /usr/include/c++/8.2.1/bits/invoke.h:60 (a.out+0x3b4e)
    #5 __invoke<main()::<lambda()> > /usr/include/c++/8.2.1/bits/invoke.h:95 (a.out+0x366b)
    #6 _M_invoke<0> /usr/include/c++/8.2.1/thread:244 (a.out+0x4198)
    #7 operator() /usr/include/c++/8.2.1/thread:253 (a.out+0x40c3)
    #8 _M_run /usr/include/c++/8.2.1/thread:196 (a.out+0x4024)
    #9 execute_native_thread_routine /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:80 (libstdc++.so.6+0xbc062)

  Previous write of size 8 at 0x7f96cf428c50 by thread T1:
    #0 std::enable_if<std::__and_<std::__not_<std::__is_tuple_like<pplx::scheduler_interface*> >, std::is_move_constructible<pplx::scheduler_interface*>, std::is_move_assignable<pplx::scheduler_interface*> >::value, void>::type std::swap<pplx::scheduler_interface*>(pplx::scheduler_interface*&, pplx::scheduler_interface*&) /usr/include/c++/8.2.1/bits/move.h:195 (libcpprest.so.2.10+0xa78f48)
    #1 std::__shared_ptr<pplx::scheduler_interface, (__gnu_cxx::_Lock_policy)2>::swap(std::__shared_ptr<pplx::scheduler_interface, (__gnu_cxx::_Lock_policy)2>&) /usr/include/c++/8.2.1/bits/shared_ptr_base.h:1304 (libcpprest.so.2.10+0xa78da8)
    #2 std::enable_if<std::__sp_compatible_with<pplx::details::linux_scheduler*, pplx::scheduler_interface*>::value, std::__shared_ptr<pplx::scheduler_interface, (__gnu_cxx::_Lock_policy)2>&>::type std::__shared_ptr<pplx::scheduler_interface, (__gnu_cxx::_Lock_policy)2>::operator=<pplx::details::linux_scheduler>(std::__shared_ptr<pplx::details::linux_scheduler, (__gnu_cxx::_Lock_policy)2>&&) /usr/include/c++/8.2.1/bits/shared_ptr_base.h:1251 (libcpprest.so.2.10+0xa78bac)
    #3 std::enable_if<std::is_assignable<std::__shared_ptr<pplx::scheduler_interface, (__gnu_cxx::_Lock_policy)2>&, std::shared_ptr<pplx::details::linux_scheduler> >::value, std::shared_ptr<pplx::scheduler_interface>&>::type std::shared_ptr<pplx::scheduler_interface>::operator=<pplx::details::linux_scheduler>(std::shared_ptr<pplx::details::linux_scheduler>&&) /usr/include/c++/8.2.1/bits/shared_ptr.h:343 (libcpprest.so.2.10+0xa78947)
    #4 pplx::_pplx_g_sched_t::get_scheduler() /home/bambino/projects/tradehelm/libfix-adapter/vendor/cpprest/Release/src/pplx/pplx.cpp:82 (libcpprest.so.2.10+0xa7853c)
    #5 pplx::get_ambient_scheduler() /home/bambino/projects/tradehelm/libfix-adapter/vendor/cpprest/Release/src/pplx/pplx.cpp:125 (libcpprest.so.2.10+0xa77e36)
    #6 operator() /data/projects/pruebas/c++/pplx-ambient-scheduler.cpp:6 (a.out+0x3333)
    #7 __invoke_impl<void, main()::<lambda()> > /usr/include/c++/8.2.1/bits/invoke.h:60 (a.out+0x3910)
    #8 __invoke<main()::<lambda()> > /usr/include/c++/8.2.1/bits/invoke.h:95 (a.out+0x350d)
    #9 _M_invoke<0> /usr/include/c++/8.2.1/thread:244 (a.out+0x41f0)
    #10 operator() /usr/include/c++/8.2.1/thread:253 (a.out+0x412d)
    #11 _M_run /usr/include/c++/8.2.1/thread:196 (a.out+0x406e)
    #12 execute_native_thread_routine /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:80 (libstdc++.so.6+0xbc062)

  Location is global 'pplx::_pplx_g_sched' of size 32 at 0x7f96cf428c40 (libcpprest.so.2.10+0x000000d58c50)

  Thread T2 (tid=4656, running) created by main thread at:
    #0 pthread_create /build/gcc/src/gcc/libsanitizer/tsan/tsan_interceptors.cc:915 (libtsan.so.0+0x2bf03)
    #1 __gthread_create /build/gcc/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:662 (libstdc++.so.6+0xbc359)
    #2 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:135 (libstdc++.so.6+0xbc359)
    #3 main /data/projects/pruebas/c++/pplx-ambient-scheduler.cpp:7 (a.out+0x3435)

  Thread T1 (tid=4655, finished) created by main thread at:
    #0 pthread_create /build/gcc/src/gcc/libsanitizer/tsan/tsan_interceptors.cc:915 (libtsan.so.0+0x2bf03)
    #1 __gthread_create /build/gcc/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:662 (libstdc++.so.6+0xbc359)
    #2 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:135 (libstdc++.so.6+0xbc359)
    #3 main /data/projects/pruebas/c++/pplx-ambient-scheduler.cpp:6 (a.out+0x3422)

SUMMARY: ThreadSanitizer: data race /usr/include/c++/8.2.1/bits/shared_ptr_base.h:1291 in std::__shared_ptr<pplx::scheduler_interface, (__gnu_cxx::_Lock_policy)2>::operator bool() const
==================

However, I don't see the actual data race on said function:

    sched_ptr get_scheduler()
    {
        switch (m_state)
        {
            case post_ctor:
                // This is the 99.9% case.

                if (!m_scheduler)
                {
                    ::pplx::details::_Scoped_spin_lock lock(m_spinlock);
                    if (!m_scheduler)
                    {
                        m_scheduler = std::make_shared<::pplx::default_scheduler_t>();
                    }
                }

                return m_scheduler;
            default:
                // This case means the global m_scheduler is not available.
                // We spin off an individual scheduler instead.
                return std::make_shared<::pplx::default_scheduler_t>();
        }
    }

It's easy to avoid the WARNING reported by the sanitizer, making a call to pplx::get_ambient_scheduler() beforehand. In my application, I use a global variable which makes a call to the function and I wonder if something similar should be applied to cpprestsdk to ease the task to other developers seeing the same data-race.

An alternative might be to call get_scheduler in _pplx_g_sched_t's constructor. Something like this:

_pplx_g_sched_t() { m_state = post_ctor; get_scheduler(); }

Thoughts? Ping @BillyONeal


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4