Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Various thread safety issues with use of libcurl for HTTP downloads #11636

Closed
JGRennison opened this issue Dec 28, 2023 · 1 comment · Fixed by #11639
Closed

[Bug]: Various thread safety issues with use of libcurl for HTTP downloads #11636

JGRennison opened this issue Dec 28, 2023 · 1 comment · Fixed by #11639

Comments

@JGRennison
Copy link
Contributor

Version of OpenTTD

master, Linux

Expected result

No thread safety issues

Actual result

Various thread safety issues.

Broadly these are in two areas:

  • OnReceiveData/OnDownloadProgress in the HTTP thread directly modify things in the GUI window (e.g. screen dirty state)
  • NetworkBackgroundLoop and the HTTP thread interfere with each other (this seems likely to be the cause of the issues where content downloads fail: HTTP request failed: status_code: 200, error: Operation was aborted by an application callback)
WARNING: ThreadSanitizer: data race (pid=2068348)
  Read of size 4 at 0x556d2e7a1e10 by thread T7:
    #0 AddDirtyBlock(int, int, int, int) /home/jgr/openttd/trunk/src/gfx.cpp:1520 (openttd+0x1f0fc4a)
    #1 Window::SetDirty() const /home/jgr/openttd/trunk/src/window.cpp:946 (openttd+0x286834b)
    #2 BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(ContentInfo const*, int) /home/jgr/openttd/trunk/src/network/network_content_gui.cpp:184 (openttd+0x1987323)
    #3 NetworkContentDownloadStatusWindow::OnDownloadProgress(ContentInfo const*, int) /home/jgr/openttd/trunk/src/network/network_content_gui.cpp:304 (openttd+0x198a377)
    #4 ClientNetworkContentSocketHandler::OnDownloadProgress(ContentInfo const*, int) /home/jgr/openttd/trunk/src/network/network_content.cpp:1105 (openttd+0x19690a3)
    #5 ClientNetworkContentSocketHandler::OnReceiveData(char const*, unsigned long) /home/jgr/openttd/trunk/src/network/network_content.cpp:633 (openttd+0x19663d4)
    #6 operator() /home/jgr/openttd/trunk/src/network/core/http_curl.cpp:164 (openttd+0x17e0b24)
    #7 _FUN /home/jgr/openttd/trunk/src/network/core/http_curl.cpp:164 (openttd+0x17e0bcf)
    #8 <null> <null> (libcurl.so.4+0x5157a)
    #9 StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}::operator()(char const*, void (*&&)()) const /home/jgr/openttd/trunk/src/network/core/../../thread.h:64 (openttd+0x17e369e)
    #10 void std::__invoke_impl<void, StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>(std::__invoke_other, StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&&&)())#1}, char const*&&, void (*&&)()) /usr/include/c++/11/bits/invoke.h:61 (openttd+0x17e8c1c)
    #11 std::__invoke_result<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>::type std::__invoke<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>(void (*&&)(), char const*&&, void (*&&)()) /usr/include/c++/11/bits/invoke.h:96 (openttd+0x17e8ad4)
    #12 void std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> >::_M_invoke<0ul, 1ul, 2ul>(std::_Index_tuple<0ul, 1ul, 2ul>) /usr/include/c++/11/bits/std_thread.h:259 (openttd+0x17e8972)
    #13 std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> >::operator()() /usr/include/c++/11/bits/std_thread.h:266 (openttd+0x17e88de)
    #14 std::thread::_State_impl<std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> > >::_M_run() /usr/include/c++/11/bits/std_thread.h:211 (openttd+0x17e8890)
    #15 <null> <null> (libstdc++.so.6+0xdc252)

  Previous write of size 4 at 0x556d2e7a1e10 by thread T17 (mutexes: write M16179760279325752):
    #0 AddDirtyBlock(int, int, int, int) /home/jgr/openttd/trunk/src/gfx.cpp:1520 (openttd+0x1f0fc64)
    #1 MarkViewportDirty /home/jgr/openttd/trunk/src/viewport.cpp:1945 (openttd+0x2817124)
    #2 MarkAllViewportsDirty(int, int, int, int) /home/jgr/openttd/trunk/src/viewport.cpp:1972 (openttd+0x281727c)
    #3 Vehicle::UpdateViewport(bool) /home/jgr/openttd/trunk/src/vehicle.cpp:1670 (openttd+0x27ac4dd)
    #4 SpecializedVehicle<RoadVehicle, (VehicleType)1>::UpdateViewport(bool, bool) /home/jgr/openttd/trunk/src/vehicle_base.h:1252 (openttd+0x1f778f6)
    #5 GroundVehicle<RoadVehicle, (VehicleType)1>::UpdateInclination(bool, bool) /home/jgr/openttd/trunk/src/ground_vehicle.hpp:241 (openttd+0x1f76cc2)
    #6 IndividualRoadVehicleController(RoadVehicle*, RoadVehicle const*) /home/jgr/openttd/trunk/src/roadveh_cmd.cpp:1562 (openttd+0x245885b)
    #7 RoadVehController /home/jgr/openttd/trunk/src/roadveh_cmd.cpp:1603 (openttd+0x2458afd)
    #8 RoadVehicle::Tick() /home/jgr/openttd/trunk/src/roadveh_cmd.cpp:1652 (openttd+0x2458f0a)
    #9 CallVehicleTicks() /home/jgr/openttd/trunk/src/vehicle.cpp:972 (openttd+0x27a8494)
    #10 StateGameLoop() /home/jgr/openttd/trunk/src/openttd.cpp:1429 (openttd+0x23490a5)
    #11 GameLoop() /home/jgr/openttd/trunk/src/openttd.cpp:1550 (openttd+0x23498c0)
    #12 VideoDriver::GameLoop() /home/jgr/openttd/trunk/src/video/video_driver.cpp:39 (openttd+0x1cd3ca7)
    #13 VideoDriver::GameThread() /home/jgr/openttd/trunk/src/video/video_driver.cpp:46 (openttd+0x1cd3d18)
    #14 VideoDriver::GameThreadThunk(VideoDriver*) /home/jgr/openttd/trunk/src/video/video_driver.cpp:83 (openttd+0x1cd3e9e)
    #15 StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}::operator()(char const*, void (*&&)(VideoDriver*), VideoDriver*&&) const /home/jgr/openttd/trunk/src/video/../thread.h:64 (openttd+0x1cd5510)
    #16 void std::__invoke_impl<void, StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*>(std::__invoke_other, StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&&&)(VideoDriver*), VideoDriver*&&)#1}, char const*&&, void (*&&)(VideoDriver*), VideoDriver*&&) /usr/include/c++/11/bits/invoke.h:61 (openttd+0x1cd6880)
    #17 _ZSt8__invokeIZ14StartNewThreadIPFvP11VideoDriverEJS2_EEbPSt6threadPKcOT_DpOT0_EUlS8_OS4_OS2_E_JS8_S4_S2_EENSt15__invoke_resultIS9_JDpSB_EE4typeESA_SD_ /usr/include/c++/11/bits/invoke.h:96 (openttd+0x1cd66e3)
    #18 void std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> >::_M_invoke<0ul, 1ul, 2ul, 3ul>(std::_Index_tuple<0ul, 1ul, 2ul, 3ul>) /usr/include/c++/11/bits/std_thread.h:259 (openttd+0x1cd6524)
    #19 std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> >::operator()() /usr/include/c++/11/bits/std_thread.h:266 (openttd+0x1cd6474)
    #20 std::thread::_State_impl<std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> > >::_M_run() /usr/include/c++/11/bits/std_thread.h:211 (openttd+0x1cd6426)
    #21 <null> <null> (libstdc++.so.6+0xdc252)

  Location is global '_invalid_rect' of size 16 at 0x556d2e7a1e10 (openttd+0x000003e6de10)

  Mutex M16179760279325752 is already destroyed.

  Thread T7 'ottd:http' (tid=2068358, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x605b8)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xdc328)
    #2 bool StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)()) /home/jgr/openttd/trunk/src/network/core/../../thread.h:52 (openttd+0x17e37ca)
    #3 NetworkHTTPInitialize() /home/jgr/openttd/trunk/src/network/core/http_curl.cpp:236 (openttd+0x17e2419)
    #4 NetworkStartUp() /home/jgr/openttd/trunk/src/network/network.cpp:1259 (openttd+0x17edb13)
    #5 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:763 (openttd+0x234382b)
    #6 main /home/jgr/openttd/trunk/src/os/unix/unix_main.cpp:32 (openttd+0x128e470)

  Thread T17 'ottd:game' (tid=2068371, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x605b8)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xdc328)
    #2 bool StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&) /home/jgr/openttd/trunk/src/video/../thread.h:52 (openttd+0x1cd5658)
    #3 VideoDriver::StartGameThread() /home/jgr/openttd/trunk/src/video/video_driver.cpp:89 (openttd+0x1cd3fbd)
    #4 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:642 (openttd+0x1cc49ec)
    #5 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:817 (openttd+0x2343efa)
    #6 main /home/jgr/openttd/trunk/src/os/unix/unix_main.cpp:32 (openttd+0x128e470)

SUMMARY: ThreadSanitizer: data race /home/jgr/openttd/trunk/src/gfx.cpp:1520 in AddDirtyBlock(int, int, int, int)
==================
==================
WARNING: ThreadSanitizer: data race (pid=2068348)
  Write of size 1 at 0x7b80001706c0 by thread T7:
    #0 AddDirtyBlock(int, int, int, int) /home/jgr/openttd/trunk/src/gfx.cpp:1538 (openttd+0x1f0fdd4)
    #1 Window::SetDirty() const /home/jgr/openttd/trunk/src/window.cpp:946 (openttd+0x286834b)
    #2 BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(ContentInfo const*, int) /home/jgr/openttd/trunk/src/network/network_content_gui.cpp:184 (openttd+0x1987323)
    #3 NetworkContentDownloadStatusWindow::OnDownloadProgress(ContentInfo const*, int) /home/jgr/openttd/trunk/src/network/network_content_gui.cpp:304 (openttd+0x198a377)
    #4 ClientNetworkContentSocketHandler::OnDownloadProgress(ContentInfo const*, int) /home/jgr/openttd/trunk/src/network/network_content.cpp:1105 (openttd+0x19690a3)
    #5 ClientNetworkContentSocketHandler::OnReceiveData(char const*, unsigned long) /home/jgr/openttd/trunk/src/network/network_content.cpp:633 (openttd+0x19663d4)
    #6 operator() /home/jgr/openttd/trunk/src/network/core/http_curl.cpp:164 (openttd+0x17e0b24)
    #7 _FUN /home/jgr/openttd/trunk/src/network/core/http_curl.cpp:164 (openttd+0x17e0bcf)
    #8 <null> <null> (libcurl.so.4+0x5157a)
    #9 StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}::operator()(char const*, void (*&&)()) const /home/jgr/openttd/trunk/src/network/core/../../thread.h:64 (openttd+0x17e369e)
    #10 void std::__invoke_impl<void, StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>(std::__invoke_other, StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&&&)())#1}, char const*&&, void (*&&)()) /usr/include/c++/11/bits/invoke.h:61 (openttd+0x17e8c1c)
    #11 std::__invoke_result<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>::type std::__invoke<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>(void (*&&)(), char const*&&, void (*&&)()) /usr/include/c++/11/bits/invoke.h:96 (openttd+0x17e8ad4)
    #12 void std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> >::_M_invoke<0ul, 1ul, 2ul>(std::_Index_tuple<0ul, 1ul, 2ul>) /usr/include/c++/11/bits/std_thread.h:259 (openttd+0x17e8972)
    #13 std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> >::operator()() /usr/include/c++/11/bits/std_thread.h:266 (openttd+0x17e88de)
    #14 std::thread::_State_impl<std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> > >::_M_run() /usr/include/c++/11/bits/std_thread.h:211 (openttd+0x17e8890)
    #15 <null> <null> (libstdc++.so.6+0xdc252)

  Previous write of size 1 at 0x7b80001706c0 by main thread (mutexes: write M15898285302615136, write M16179760279325752):
    #0 DrawDirtyBlocks() /home/jgr/openttd/trunk/src/gfx.cpp:1466 (openttd+0x1f0f938)
    #1 UpdateWindows() /home/jgr/openttd/trunk/src/window.cpp:3082 (openttd+0x287447a)
    #2 VideoDriver::Tick() /home/jgr/openttd/trunk/src/video/video_driver.cpp:151 (openttd+0x1cd460e)
    #3 VideoDriver_SDL_Base::LoopOnce() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:627 (openttd+0x1cc498f)
    #4 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:645 (openttd+0x1cc49fa)
    #5 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:817 (openttd+0x2343efa)
    #6 main /home/jgr/openttd/trunk/src/os/unix/unix_main.cpp:32 (openttd+0x128e470)

  Location is heap block of size 3870 at 0x7b8000170000 allocated by main thread:
    #0 realloc ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:685 (libtsan.so.0+0x34179)
    #1 ReallocT<unsigned char> /home/jgr/openttd/trunk/src/spriteloader/../core/alloc_func.hpp:126 (openttd+0x1f13ab1)
    #2 ScreenSizeChanged() /home/jgr/openttd/trunk/src/gfx.cpp:1292 (openttd+0x1f0ebaa)
    #3 GameSizeChanged() /home/jgr/openttd/trunk/src/main_gui.cpp:587 (openttd+0x20e6477)
    #4 VideoDriver_SDL_Base::ClientSizeChanged(int, int, bool) /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:130 (openttd+0x1cc25d8)
    #5 VideoDriver_SDL_Base::CreateMainSurface(unsigned int, unsigned int, bool) /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:187 (openttd+0x1cc2ff8)
    #6 VideoDriver_SDL_Base::PollEvent() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:488 (openttd+0x1cc3ea7)
    #7 VideoDriver::Tick() /home/jgr/openttd/trunk/src/video/video_driver.cpp:135 (openttd+0x1cd44d2)
    #8 VideoDriver_SDL_Base::LoopOnce() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:627 (openttd+0x1cc498f)
    #9 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:645 (openttd+0x1cc49fa)
    #10 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:817 (openttd+0x2343efa)
    #11 main /home/jgr/openttd/trunk/src/os/unix/unix_main.cpp:32 (openttd+0x128e470)

  Mutex M15898285302615136 is already destroyed.

  Mutex M16179760279325752 is already destroyed.

  Thread T7 'ottd:http' (tid=2068358, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x605b8)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xdc328)
    #2 bool StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)()) /home/jgr/openttd/trunk/src/network/core/../../thread.h:52 (openttd+0x17e37ca)
    #3 NetworkHTTPInitialize() /home/jgr/openttd/trunk/src/network/core/http_curl.cpp:236 (openttd+0x17e2419)
    #4 NetworkStartUp() /home/jgr/openttd/trunk/src/network/network.cpp:1259 (openttd+0x17edb13)
    #5 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:763 (openttd+0x234382b)
    #6 main /home/jgr/openttd/trunk/src/os/unix/unix_main.cpp:32 (openttd+0x128e470)

SUMMARY: ThreadSanitizer: data race /home/jgr/openttd/trunk/src/gfx.cpp:1538 in AddDirtyBlock(int, int, int, int)
==================
==================
WARNING: ThreadSanitizer: data race (pid=2068348)
  Read of size 4 at 0x7b4c0001193c by main thread (mutexes: write M15898285302615136, write M16179760279325752):
    #0 BaseNetworkContentDownloadStatusWindow::DrawWidget(Rect const&, int) const /home/jgr/openttd/trunk/src/network/network_content_gui.cpp:143 (openttd+0x1986edf)
    #1 NWidgetLeaf::Draw(Window const*) /home/jgr/openttd/trunk/src/widget.cpp:3101 (openttd+0x286072b)
    #2 NWidgetContainer::Draw(Window const*) /home/jgr/openttd/trunk/src/widget.cpp:1359 (openttd+0x285427c)
    #3 NWidgetContainer::Draw(Window const*) /home/jgr/openttd/trunk/src/widget.cpp:1359 (openttd+0x285427c)
    #4 NWidgetBackground::Draw(Window const*) /home/jgr/openttd/trunk/src/widget.cpp:2389 (openttd+0x285c002)
    #5 NWidgetContainer::Draw(Window const*) /home/jgr/openttd/trunk/src/widget.cpp:1359 (openttd+0x285427c)
    #6 Window::DrawWidgets() const /home/jgr/openttd/trunk/src/widget.cpp:872 (openttd+0x2852653)
    #7 Window::OnPaint() /home/jgr/openttd/trunk/src/window_gui.h:544 (openttd+0x14cff98)
    #8 DrawOverlappedWindow /home/jgr/openttd/trunk/src/window.cpp:912 (openttd+0x2867e29)
    #9 DrawOverlappedWindowForAll(int, int, int, int) /home/jgr/openttd/trunk/src/window.cpp:935 (openttd+0x28681d4)
    #10 RedrawScreenRect(int, int, int, int) /home/jgr/openttd/trunk/src/gfx.cpp:1406 (openttd+0x1f0f6f7)
    #11 DrawDirtyBlocks() /home/jgr/openttd/trunk/src/gfx.cpp:1481 (openttd+0x1f0fa6f)
    #12 UpdateWindows() /home/jgr/openttd/trunk/src/window.cpp:3082 (openttd+0x287447a)
    #13 VideoDriver::Tick() /home/jgr/openttd/trunk/src/video/video_driver.cpp:151 (openttd+0x1cd460e)
    #14 VideoDriver_SDL_Base::LoopOnce() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:627 (openttd+0x1cc498f)
    #15 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:645 (openttd+0x1cc49fa)
    #16 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:817 (openttd+0x2343efa)
    #17 main /home/jgr/openttd/trunk/src/os/unix/unix_main.cpp:32 (openttd+0x128e470)

  Previous write of size 4 at 0x7b4c0001193c by thread T7:
    #0 BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(ContentInfo const*, int) /home/jgr/openttd/trunk/src/network/network_content_gui.cpp:181 (openttd+0x198730d)
    #1 NetworkContentDownloadStatusWindow::OnDownloadProgress(ContentInfo const*, int) /home/jgr/openttd/trunk/src/network/network_content_gui.cpp:304 (openttd+0x198a377)
    #2 ClientNetworkContentSocketHandler::OnDownloadProgress(ContentInfo const*, int) /home/jgr/openttd/trunk/src/network/network_content.cpp:1105 (openttd+0x19690a3)
    #3 ClientNetworkContentSocketHandler::OnReceiveData(char const*, unsigned long) /home/jgr/openttd/trunk/src/network/network_content.cpp:633 (openttd+0x19663d4)
    #4 operator() /home/jgr/openttd/trunk/src/network/core/http_curl.cpp:164 (openttd+0x17e0b24)
    #5 _FUN /home/jgr/openttd/trunk/src/network/core/http_curl.cpp:164 (openttd+0x17e0bcf)
    #6 <null> <null> (libcurl.so.4+0x5157a)
    #7 StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}::operator()(char const*, void (*&&)()) const /home/jgr/openttd/trunk/src/network/core/../../thread.h:64 (openttd+0x17e369e)
    #8 void std::__invoke_impl<void, StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>(std::__invoke_other, StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&&&)())#1}, char const*&&, void (*&&)()) /usr/include/c++/11/bits/invoke.h:61 (openttd+0x17e8c1c)
    #9 std::__invoke_result<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>::type std::__invoke<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>(void (*&&)(), char const*&&, void (*&&)()) /usr/include/c++/11/bits/invoke.h:96 (openttd+0x17e8ad4)
    #10 void std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> >::_M_invoke<0ul, 1ul, 2ul>(std::_Index_tuple<0ul, 1ul, 2ul>) /usr/include/c++/11/bits/std_thread.h:259 (openttd+0x17e8972)
    #11 std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> >::operator()() /usr/include/c++/11/bits/std_thread.h:266 (openttd+0x17e88de)
    #12 std::thread::_State_impl<std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> > >::_M_run() /usr/include/c++/11/bits/std_thread.h:211 (openttd+0x17e8890)
    #13 <null> <null> (libstdc++.so.6+0xdc252)

  Location is heap block of size 424 at 0x7b4c00011800 allocated by main thread:
    #0 calloc ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:672 (libtsan.so.0+0x31edc)
    #1 CallocT<unsigned char> /home/jgr/openttd/trunk/src/core/alloc_func.hpp:94 (openttd+0x14d7e2d)
    #2 ZeroedMemoryAllocator::operator new(unsigned long) /home/jgr/openttd/trunk/src/core/alloc_type.hpp:96 (openttd+0x14cf5e5)
    #3 NetworkContentListWindow::OnClick(Point, int, int) /home/jgr/openttd/trunk/src/network/network_content_gui.cpp:863 (openttd+0x198de81)
    #4 DispatchLeftClickEvent /home/jgr/openttd/trunk/src/window.cpp:736 (openttd+0x2867153)
    #5 MouseLoop /home/jgr/openttd/trunk/src/window.cpp:2857 (openttd+0x287331f)
    #6 HandleMouseEvents() /home/jgr/openttd/trunk/src/window.cpp:2954 (openttd+0x2873b2d)
    #7 VideoDriver_SDL_Base::PollEvent() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:417 (openttd+0x1cc3a15)
    #8 VideoDriver::Tick() /home/jgr/openttd/trunk/src/video/video_driver.cpp:135 (openttd+0x1cd44d2)
    #9 VideoDriver_SDL_Base::LoopOnce() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:627 (openttd+0x1cc498f)
    #10 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:645 (openttd+0x1cc49fa)
    #11 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:817 (openttd+0x2343efa)
    #12 main /home/jgr/openttd/trunk/src/os/unix/unix_main.cpp:32 (openttd+0x128e470)

  Mutex M15898285302615136 is already destroyed.

  Mutex M16179760279325752 is already destroyed.

  Thread T7 'ottd:http' (tid=2068358, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x605b8)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xdc328)
    #2 bool StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)()) /home/jgr/openttd/trunk/src/network/core/../../thread.h:52 (openttd+0x17e37ca)
    #3 NetworkHTTPInitialize() /home/jgr/openttd/trunk/src/network/core/http_curl.cpp:236 (openttd+0x17e2419)
    #4 NetworkStartUp() /home/jgr/openttd/trunk/src/network/network.cpp:1259 (openttd+0x17edb13)
    #5 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:763 (openttd+0x234382b)
    #6 main /home/jgr/openttd/trunk/src/os/unix/unix_main.cpp:32 (openttd+0x128e470)

SUMMARY: ThreadSanitizer: data race /home/jgr/openttd/trunk/src/network/network_content_gui.cpp:143 in BaseNetworkContentDownloadStatusWindow::DrawWidget(Rect const&, int) const
==================
==================
WARNING: ThreadSanitizer: data race (pid=2068348)
  Write of size 1 at 0x556d2e674711 by thread T17 (mutexes: write M16179760279325752):
    #0 ClientNetworkContentSocketHandler::CloseConnection(bool) /home/jgr/openttd/trunk/src/network/network_content.cpp:797 (openttd+0x196734d)
    #1 ClientNetworkContentSocketHandler::SendReceive() /home/jgr/openttd/trunk/src/network/network_content.cpp:817 (openttd+0x19674c1)
    #2 NetworkBackgroundLoop() /home/jgr/openttd/trunk/src/network/network.cpp:1026 (openttd+0x17ecfdf)
    #3 GameLoop() /home/jgr/openttd/trunk/src/openttd.cpp:1536 (openttd+0x2349762)
    #4 VideoDriver::GameLoop() /home/jgr/openttd/trunk/src/video/video_driver.cpp:39 (openttd+0x1cd3ca7)
    #5 VideoDriver::GameThread() /home/jgr/openttd/trunk/src/video/video_driver.cpp:46 (openttd+0x1cd3d18)
    #6 VideoDriver::GameThreadThunk(VideoDriver*) /home/jgr/openttd/trunk/src/video/video_driver.cpp:83 (openttd+0x1cd3e9e)
    #7 StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}::operator()(char const*, void (*&&)(VideoDriver*), VideoDriver*&&) const /home/jgr/openttd/trunk/src/video/../thread.h:64 (openttd+0x1cd5510)
    #8 void std::__invoke_impl<void, StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*>(std::__invoke_other, StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&&&)(VideoDriver*), VideoDriver*&&)#1}, char const*&&, void (*&&)(VideoDriver*), VideoDriver*&&) /usr/include/c++/11/bits/invoke.h:61 (openttd+0x1cd6880)
    #9 _ZSt8__invokeIZ14StartNewThreadIPFvP11VideoDriverEJS2_EEbPSt6threadPKcOT_DpOT0_EUlS8_OS4_OS2_E_JS8_S4_S2_EENSt15__invoke_resultIS9_JDpSB_EE4typeESA_SD_ /usr/include/c++/11/bits/invoke.h:96 (openttd+0x1cd66e3)
    #10 void std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> >::_M_invoke<0ul, 1ul, 2ul, 3ul>(std::_Index_tuple<0ul, 1ul, 2ul, 3ul>) /usr/include/c++/11/bits/std_thread.h:259 (openttd+0x1cd6524)
    #11 std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> >::operator()() /usr/include/c++/11/bits/std_thread.h:266 (openttd+0x1cd6474)
    #12 std::thread::_State_impl<std::thread::_Invoker<std::tuple<StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&)::{lambda(char const*, void (*&&)(VideoDriver*), VideoDriver*&&)#1}, char const*, void (*)(VideoDriver*), VideoDriver*> > >::_M_run() /usr/include/c++/11/bits/std_thread.h:211 (openttd+0x1cd6426)
    #13 <null> <null> (libstdc++.so.6+0xdc252)

  Previous read of size 1 at 0x556d2e674711 by thread T7:
    #0 ClientNetworkContentSocketHandler::IsCancelled() const /home/jgr/openttd/trunk/src/network/network_content.cpp:580 (openttd+0x1965f3c)
    #1 operator() /home/jgr/openttd/trunk/src/network/core/http_curl.cpp:177 (openttd+0x17e0c6b)
    #2 _FUN /home/jgr/openttd/trunk/src/network/core/http_curl.cpp:177 (openttd+0x17e0d08)
    #3 <null> <null> (libcurl.so.4+0x4ecb2)
    #4 StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}::operator()(char const*, void (*&&)()) const /home/jgr/openttd/trunk/src/network/core/../../thread.h:64 (openttd+0x17e369e)
    #5 void std::__invoke_impl<void, StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>(std::__invoke_other, StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&&&)())#1}, char const*&&, void (*&&)()) /usr/include/c++/11/bits/invoke.h:61 (openttd+0x17e8c1c)
    #6 std::__invoke_result<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>::type std::__invoke<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>(void (*&&)(), char const*&&, void (*&&)()) /usr/include/c++/11/bits/invoke.h:96 (openttd+0x17e8ad4)
    #7 void std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> >::_M_invoke<0ul, 1ul, 2ul>(std::_Index_tuple<0ul, 1ul, 2ul>) /usr/include/c++/11/bits/std_thread.h:259 (openttd+0x17e8972)
    #8 std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> >::operator()() /usr/include/c++/11/bits/std_thread.h:266 (openttd+0x17e88de)
    #9 std::thread::_State_impl<std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> > >::_M_run() /usr/include/c++/11/bits/std_thread.h:211 (openttd+0x17e8890)
    #10 <null> <null> (libstdc++.so.6+0xdc252)

  Location is global '_network_content_client' of size 416 at 0x556d2e674580 (openttd+0x000003d40711)

  Mutex M16179760279325752 is already destroyed.

  Thread T17 'ottd:game' (tid=2068371, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x605b8)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xdc328)
    #2 bool StartNewThread<void (*)(VideoDriver*), VideoDriver*>(std::thread*, char const*, void (*&&)(VideoDriver*), VideoDriver*&&) /home/jgr/openttd/trunk/src/video/../thread.h:52 (openttd+0x1cd5658)
    #3 VideoDriver::StartGameThread() /home/jgr/openttd/trunk/src/video/video_driver.cpp:89 (openttd+0x1cd3fbd)
    #4 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:642 (openttd+0x1cc49ec)
    #5 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:817 (openttd+0x2343efa)
    #6 main /home/jgr/openttd/trunk/src/os/unix/unix_main.cpp:32 (openttd+0x128e470)

  Thread T7 'ottd:http' (tid=2068358, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x605b8)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xdc328)
    #2 bool StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)()) /home/jgr/openttd/trunk/src/network/core/../../thread.h:52 (openttd+0x17e37ca)
    #3 NetworkHTTPInitialize() /home/jgr/openttd/trunk/src/network/core/http_curl.cpp:236 (openttd+0x17e2419)
    #4 NetworkStartUp() /home/jgr/openttd/trunk/src/network/network.cpp:1259 (openttd+0x17edb13)
    #5 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:763 (openttd+0x234382b)
    #6 main /home/jgr/openttd/trunk/src/os/unix/unix_main.cpp:32 (openttd+0x128e470)

SUMMARY: ThreadSanitizer: data race /home/jgr/openttd/trunk/src/network/network_content.cpp:797 in ClientNetworkContentSocketHandler::CloseConnection(bool)
==================
dbg: [net] HTTP request failed: status_code: 200, error: Operation was aborted by an application callback
==================
WARNING: ThreadSanitizer: data race (pid=2068348)
  Write of size 8 at 0x556d2e6745d8 by main thread (mutexes: write M15898285302615136, write M16179760279325752):
    #0 std::__cxx1998::vector<ContentCallback*, std::allocator<ContentCallback*> >::_M_erase(__gnu_cxx::__normal_iterator<ContentCallback**, std::__cxx1998::vector<ContentCallback*, std::allocator<ContentCallback*> > >) <null> (openttd+0x19956cd)
    #1 std::__cxx1998::vector<ContentCallback*, std::allocator<ContentCallback*> >::erase(__gnu_cxx::__normal_iterator<ContentCallback* const*, std::__cxx1998::vector<ContentCallback*, std::allocator<ContentCallback*> > >) /usr/include/c++/11/bits/stl_vector.h:1431 (openttd+0x19922c5)
    #2 std::__debug::vector<ContentCallback*, std::allocator<ContentCallback*> >::erase(__gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<ContentCallback* const*, std::__cxx1998::vector<ContentCallback*, std::allocator<ContentCallback*> > >, std::__debug::vector<ContentCallback*, std::allocator<ContentCallback*> >, std::random_access_iterator_tag>) /usr/include/c++/11/debug/vector:676 (openttd+0x198f10e)
    #3 ClientNetworkContentSocketHandler::RemoveCallback(ContentCallback*) /home/jgr/openttd/trunk/src/network/network_content.h:148 (openttd+0x1989617)
    #4 BaseNetworkContentDownloadStatusWindow::Close(int) /home/jgr/openttd/trunk/src/network/network_content_gui.cpp:113 (openttd+0x1986c97)
    #5 NetworkContentDownloadStatusWindow::Close(int) /home/jgr/openttd/trunk/src/network/network_content_gui.cpp:285 (openttd+0x198a208)
    #6 NetworkContentDownloadStatusWindow::OnClick(Point, int, int) /home/jgr/openttd/trunk/src/network/network_content_gui.cpp:293 (openttd+0x198a2fe)
    #7 DispatchLeftClickEvent /home/jgr/openttd/trunk/src/window.cpp:736 (openttd+0x2867153)
    #8 MouseLoop /home/jgr/openttd/trunk/src/window.cpp:2857 (openttd+0x287331f)
    #9 HandleMouseEvents() /home/jgr/openttd/trunk/src/window.cpp:2954 (openttd+0x2873b2d)
    #10 VideoDriver_SDL_Base::PollEvent() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:417 (openttd+0x1cc3a15)
    #11 VideoDriver::Tick() /home/jgr/openttd/trunk/src/video/video_driver.cpp:135 (openttd+0x1cd44d2)
    #12 VideoDriver_SDL_Base::LoopOnce() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:627 (openttd+0x1cc498f)
    #13 VideoDriver_SDL_Base::MainLoop() /home/jgr/openttd/trunk/src/video/sdl2_v.cpp:645 (openttd+0x1cc49fa)
    #14 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:817 (openttd+0x2343efa)
    #15 main /home/jgr/openttd/trunk/src/os/unix/unix_main.cpp:32 (openttd+0x128e470)

  Previous read of size 8 at 0x556d2e6745d8 by thread T7:
    #0 std::__cxx1998::vector<ContentCallback*, std::allocator<ContentCallback*> >::size() const /usr/include/c++/11/bits/stl_vector.h:919 (openttd+0x196ef72)
    #1 ClientNetworkContentSocketHandler::OnDownloadProgress(ContentInfo const*, int) /home/jgr/openttd/trunk/src/network/network_content.cpp:1106 (openttd+0x19690b3)
    #2 ClientNetworkContentSocketHandler::OnFailure() /home/jgr/openttd/trunk/src/network/network_content.cpp:591 (openttd+0x1966036)
    #3 HttpThread() /home/jgr/openttd/trunk/src/network/core/http_curl.cpp:197 (openttd+0x17e1a32)
    #4 StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}::operator()(char const*, void (*&&)()) const /home/jgr/openttd/trunk/src/network/core/../../thread.h:64 (openttd+0x17e369e)
    #5 void std::__invoke_impl<void, StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>(std::__invoke_other, StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&&&)())#1}, char const*&&, void (*&&)()) /usr/include/c++/11/bits/invoke.h:61 (openttd+0x17e8c1c)
    #6 std::__invoke_result<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>::type std::__invoke<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()>(void (*&&)(), char const*&&, void (*&&)()) /usr/include/c++/11/bits/invoke.h:96 (openttd+0x17e8ad4)
    #7 void std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> >::_M_invoke<0ul, 1ul, 2ul>(std::_Index_tuple<0ul, 1ul, 2ul>) /usr/include/c++/11/bits/std_thread.h:259 (openttd+0x17e8972)
    #8 std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> >::operator()() /usr/include/c++/11/bits/std_thread.h:266 (openttd+0x17e88de)
    #9 std::thread::_State_impl<std::thread::_Invoker<std::tuple<StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)())::{lambda(char const*, void (*&&)())#1}, char const*, void (*)()> > >::_M_run() /usr/include/c++/11/bits/std_thread.h:211 (openttd+0x17e8890)
    #10 <null> <null> (libstdc++.so.6+0xdc252)

  Location is global '_network_content_client' of size 416 at 0x556d2e674580 (openttd+0x000003d405d8)

  Mutex M15898285302615136 is already destroyed.

  Mutex M16179760279325752 is already destroyed.

  Thread T7 'ottd:http' (tid=2068358, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x605b8)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xdc328)
    #2 bool StartNewThread<void (*)()>(std::thread*, char const*, void (*&&)()) /home/jgr/openttd/trunk/src/network/core/../../thread.h:52 (openttd+0x17e37ca)
    #3 NetworkHTTPInitialize() /home/jgr/openttd/trunk/src/network/core/http_curl.cpp:236 (openttd+0x17e2419)
    #4 NetworkStartUp() /home/jgr/openttd/trunk/src/network/network.cpp:1259 (openttd+0x17edb13)
    #5 openttd_main(int, char**) /home/jgr/openttd/trunk/src/openttd.cpp:763 (openttd+0x234382b)
    #6 main /home/jgr/openttd/trunk/src/os/unix/unix_main.cpp:32 (openttd+0x128e470)

SUMMARY: ThreadSanitizer: data race (/home/jgr/openttd/trunk/build-tsan/openttd+0x19956cd) in std::__cxx1998::vector<ContentCallback*, std::allocator<ContentCallback*> >::_M_erase(__gnu_cxx::__normal_iterator<ContentCallback**, std::__cxx1998::vector<ContentCallback*, std::allocator<ContentCallback*> > >)
==================

Anecdotally it seems possible for this to clobber memory more broadly, but I haven't been able to reproduce that with memory sanitisers active.

Steps to reproduce

Download some HTTP content using libcurl with some kind of thread safety checker

@TrueBrain
Copy link
Member

TrueBrain commented Dec 28, 2023

Given we use winhttp for Windows, where you register a callback that can hit when-ever, it is also very likely a similar issue exists on Windows.

Guess we need to slap a thread-safe queue between the http-downloaders and their calls to the callback :)

Nice find btw; bit nasty I didn't test with valgrind :) (or any other sanitizer, ofc)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants