ITADN

Data race in get_current_date()

#2618Closedklaussilveira 创建于 2026-06-12
K
klaussilveiracommented
Specifically, in here: https://github.com/stephenberry/glaze/blob/main/include/glaze/net/http_server.hpp#L2354 get_current_date() caches the formatted HTTP Date header in thread_local storage, refreshing it once per second per worker thread, but on the POSIX path it formats the time with std::gmtime(&time_t_now), which returns a pointer to a single process-wide static struct tm. If two ASIO worker threads happen to cross, both will call the gmtime concurrently and write that shared buffer. I caught this with TSAN: ``` WARNING: ThreadSanitizer: data race (pid=5972) Write of size 8 at 0x7f635fdd43e0 by thread T5: #0 gmtime ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1325 (libtsan.so.2+0x5b64c) (BuildId: 99ef88596cb10a8ccf307fe1a9070f66a44b1624) #1 glz::http_server<false>::get_current_date[abi:cxx11]() <null> (server+0xde4452) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #2 glz::http_server<false>::send_response_with_conn(std::shared_ptr<glz::http_server<false>::connection_state>, glz::response&) <null> (server+0xdc36e6) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #3 glz::http_server<false>::process_full_request_with_conn(std::shared_ptr<glz::http_server<false>::connection_state>) <null> (server+0xda55a8) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #4 glz::http_server<false>::finish_request(std::shared_ptr<glz::http_server<false>::connection_state>, glz::http_server<false>::parse_result const&) <null> (server+0xd8a8bd) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #5 glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}::operator()(std::error_code, unsigned long) const <null> (server+0xd8b2c2) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #6 asio::detail::read_until_delim_string_op_v2<asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>, asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char> >, glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}>::operator()(std::error_code, unsigned long, int) <null> (server+0xe1c11f) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #7 asio::detail::binder2<asio::detail::read_until_delim_string_op_v2<asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>, asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char> >, glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}>, std::error_code, unsigned long>::operator()() <null> (server+0xe97b70) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #8 void asio::detail::handler_work<asio::detail::read_until_delim_string_op_v2<asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>, asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char> >, glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}>, asio::any_io_executor, void>::complete<asio::detail::binder2<asio::detail::read_until_delim_string_op_v2<asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>, asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char> >, glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}>, std::error_code, unsigned long> >(asio::detail::binder2<asio::detail::read_until_delim_string_op_v2<asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>, asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char> >, glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}>, std::error_code, unsigned long>&, asio::detail::read_until_delim_string_op_v2<asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>, asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char> >, glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}>&) <null> (server+0xe91bc0) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #9 asio::detail::reactive_socket_recv_op<asio::mutable_buffers_1, asio::detail::read_until_delim_string_op_v2<asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>, asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char> >, glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}>, asio::any_io_executor>::do_complete(void*, asio::detail::scheduler_operation*, std::error_code const&, unsigned long) <null> (server+0xe8a72b) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #10 asio::detail::scheduler_operation::complete(void*, std::error_code const&, unsigned long) <null> (server+0xca74dc) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #11 asio::detail::epoll_reactor::descriptor_state::do_complete(void*, asio::detail::scheduler_operation*, std::error_code const&, unsigned long) <null> (server+0xcb56d0) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #12 asio::detail::scheduler_operation::complete(void*, std::error_code const&, unsigned long) <null> (server+0xca74dc) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #13 asio::detail::scheduler::do_run_one(asio::detail::conditionally_enabled_mutex::scoped_lock&, asio::detail::scheduler_thread_info&, std::error_code const&) <null> (server+0xcba345) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #14 asio::detail::scheduler::run(std::error_code&) <null> (server+0xcb8c7a) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #15 asio::io_context::run() <null> (server+0xcbb9fc) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #16 glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}::operator()() const <null> (server+0xd18afb) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #17 void std::__invoke_impl<void, glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}>(std::__invoke_other, glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}&&) <null> (server+0xec44c4) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #18 std::__invoke_result<glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}>::type std::__invoke<glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}>(glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}&&) <null> (server+0xec38df) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #19 void std::thread::_Invoker<std::tuple<glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) <null> (server+0xec20a9) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #20 std::thread::_Invoker<std::tuple<glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}> >::operator()() <null> (server+0xec0480) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #21 std::thread::_State_impl<std::thread::_Invoker<std::tuple<glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}> > >::_M_run() <null> (server+0xebb4f1) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #22 execute_native_thread_routine <null> (server+0x1985603) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) Previous write of size 8 at 0x7f635fdd43e0 by thread T8: #0 gmtime ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1325 (libtsan.so.2+0x5b64c) (BuildId: 99ef88596cb10a8ccf307fe1a9070f66a44b1624) #1 glz::http_server<false>::get_current_date[abi:cxx11]() <null> (server+0xde4452) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #2 glz::http_server<false>::send_response_with_conn(std::shared_ptr<glz::http_server<false>::connection_state>, glz::response&) <null> (server+0xdc36e6) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #3 glz::http_server<false>::process_full_request_with_conn(std::shared_ptr<glz::http_server<false>::connection_state>) <null> (server+0xda55a8) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #4 glz::http_server<false>::finish_request(std::shared_ptr<glz::http_server<false>::connection_state>, glz::http_server<false>::parse_result const&) <null> (server+0xd8a8bd) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #5 glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}::operator()(std::error_code, unsigned long) const <null> (server+0xd8b2c2) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #6 asio::detail::read_until_delim_string_op_v2<asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>, asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char> >, glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}>::operator()(std::error_code, unsigned long, int) <null> (server+0xe1c11f) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #7 asio::detail::binder2<asio::detail::read_until_delim_string_op_v2<asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>, asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char> >, glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}>, std::error_code, unsigned long>::operator()() <null> (server+0xe97b70) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #8 void asio::detail::handler_work<asio::detail::read_until_delim_string_op_v2<asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>, asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char> >, glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}>, asio::any_io_executor, void>::complete<asio::detail::binder2<asio::detail::read_until_delim_string_op_v2<asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>, asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char> >, glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}>, std::error_code, unsigned long> >(asio::detail::binder2<asio::detail::read_until_delim_string_op_v2<asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>, asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char> >, glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}>, std::error_code, unsigned long>&, asio::detail::read_until_delim_string_op_v2<asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>, asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char> >, glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}>&) <null> (server+0xe91bc0) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #9 asio::detail::reactive_socket_recv_op<asio::mutable_buffers_1, asio::detail::read_until_delim_string_op_v2<asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>, asio::dynamic_string_buffer<char, std::char_traits<char>, std::allocator<char> >, glz::http_server<false>::do_read_headers(std::shared_ptr<glz::http_server<false>::connection_state>)::{lambda(std::error_code, unsigned long)#1}>, asio::any_io_executor>::do_complete(void*, asio::detail::scheduler_operation*, std::error_code const&, unsigned long) <null> (server+0xe8a72b) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #10 asio::detail::scheduler_operation::complete(void*, std::error_code const&, unsigned long) <null> (server+0xca74dc) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #11 asio::detail::epoll_reactor::descriptor_state::do_complete(void*, asio::detail::scheduler_operation*, std::error_code const&, unsigned long) <null> (server+0xcb56d0) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #12 asio::detail::scheduler_operation::complete(void*, std::error_code const&, unsigned long) <null> (server+0xca74dc) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #13 asio::detail::scheduler::do_run_one(asio::detail::conditionally_enabled_mutex::scoped_lock&, asio::detail::scheduler_thread_info&, std::error_code const&) <null> (server+0xcba345) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #14 asio::detail::scheduler::run(std::error_code&) <null> (server+0xcb8c7a) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #15 asio::io_context::run() <null> (server+0xcbb9fc) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #16 glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}::operator()() const <null> (server+0xd18afb) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #17 void std::__invoke_impl<void, glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}>(std::__invoke_other, glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}&&) <null> (server+0xec44c4) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #18 std::__invoke_result<glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}>::type std::__invoke<glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}>(glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}&&) <null> (server+0xec38df) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #19 void std::thread::_Invoker<std::tuple<glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) <null> (server+0xec20a9) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #20 std::thread::_Invoker<std::tuple<glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}> >::operator()() <null> (server+0xec0480) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #21 std::thread::_State_impl<std::thread::_Invoker<std::tuple<glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}> > >::_M_run() <null> (server+0xebb4f1) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #22 execute_native_thread_routine <null> (server+0x1985603) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) Location is global '<null>' at 0x000000000000 (libc.so.6+0x1ec3e0) Thread T5 (tid=5978, running) created by main thread at: #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1022 (libtsan.so.2+0x568a6) (BuildId: 99ef88596cb10a8ccf307fe1a9070f66a44b1624) #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (server+0x19856d8) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #2 decltype (::new ((void*)(0)) std::thread((declval<glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}>)())) std::construct_at<std::thread, glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}>(std::thread*, glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}&&) <null> (server+0xd6e5d7) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #3 std::thread& std::vector<std::thread, std::allocator<std::thread> >::emplace_back<glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}>(glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}&&) <null> (server+0xd388d3) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #4 glz::http_server<false>::start(std::optional<unsigned long>) <null> (server+0xd18f80) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #5 main /app/src/main.cc:268 (server+0xc83200) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) Thread T8 (tid=5981, running) created by main thread at: #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1022 (libtsan.so.2+0x568a6) (BuildId: 99ef88596cb10a8ccf307fe1a9070f66a44b1624) #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (server+0x19856d8) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #2 decltype (::new ((void*)(0)) std::thread((declval<glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}>)())) std::construct_at<std::thread, glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}>(std::thread*, glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}&&) <null> (server+0xd6e5d7) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #3 std::thread& std::vector<std::thread, std::allocator<std::thread> >::emplace_back<glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}>(glz::http_server<false>::start(std::optional<unsigned long>)::{lambda()#1}&&) <null> (server+0xd388d3) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #4 glz::http_server<false>::start(std::optional<unsigned long>) <null> (server+0xd18f80) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) #5 main /app/src/main.cc:268 (server+0xc83200) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) SUMMARY: ThreadSanitizer: data race (/app/build/bin/server+0xde4452) (BuildId: b5dd00c1304d4188c226b5b365155fabd75bc595) in glz::http_server<false>::get_current_date[abi:cxx11]() ```
关闭于 2026-06-12 1 条评论