Bug 31716 - race condition in libiberty/concat.c
Summary: race condition in libiberty/concat.c
Status: UNCONFIRMED
Alias: None
Product: gdb
Classification: Unclassified
Component: gdb (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks: 31751
  Show dependency treegraph
 
Reported: 2024-05-09 09:49 UTC by Bernd Edlinger
Modified: 2024-05-18 14:20 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Bernd Edlinger 2024-05-09 09:49:05 UTC
This was only observed in one test case:
gdb.ada/mi_task_arg.exp:

==================
WARNING: ThreadSanitizer: data race (pid=32111)
  Read of size 1 at 0x7b0c00000150 by thread T2:
    #0 strlen ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:386 (libtsan.so.2+0x5baee)
    #1 strlen ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:378 (libtsan.so.2+0x5baee)
    #2 vconcat_length ../../binutils-gdb/libiberty/concat.c:65 (gdb+0x98f75f)
    #3 concat ../../binutils-gdb/libiberty/concat.c:147 (gdb+0x98f75f)
    #4 try_open_dwop_file ../../binutils-gdb/gdb/dwarf2/read.c:8969 (gdb+0x36afc0)
    #5 open_dwp_file ../../binutils-gdb/gdb/dwarf2/read.c:9316 (gdb+0x36b0aa)
    #6 open_and_init_dwp_file ../../binutils-gdb/gdb/dwarf2/read.c:9368 (gdb+0x374c2f)
    #7 get_dwp_file ../../binutils-gdb/gdb/dwarf2/read.c:9452 (gdb+0x374c2f)
    #8 process_skeletonless_type_units ../../binutils-gdb/gdb/dwarf2/read.c:4793 (gdb+0x3840e7)
    #9 cooked_index_debug_info::done_reading() ../../binutils-gdb/gdb/dwarf2/read.c:4894 (gdb+0x3840e7)
    #10 operator() ../../binutils-gdb/gdb/dwarf2/read.c:4949 (gdb+0x384ae4)
    #11 __invoke_impl<void, cooked_index_debug_info::do_reading()::<lambda()>&> /usr/include/c++/12/bits/invoke.h:61 (gdb+0x384ae4)
    #12 __invoke_r<void, cooked_index_debug_info::do_reading()::<lambda()>&> /usr/include/c++/12/bits/invoke.h:111 (gdb+0x384ae4)
    #13 _M_invoke /usr/include/c++/12/bits/std_function.h:290 (gdb+0x384ae4)
    #14 std::function<void ()>::operator()() const /usr/include/c++/12/bits/std_function.h:591 (gdb+0x9cfa86)
    #15 gdb::task_group::impl::~impl() ../../binutils-gdb/gdbsupport/task-group.cc:38 (gdb+0x9cfa86)
    #16 std::_Sp_counted_ptr<gdb::task_group::impl*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/include/c++/12/bits/shared_ptr_base.h:428 (gdb+0x9cfa86)
    #17 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release_last_use() /usr/include/c++/12/bits/shared_ptr_base.h:175 (gdb+0x9ceca8)
    #18 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/12/bits/shared_ptr_base.h:361 (gdb+0x9ceca8)
    #19 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/12/bits/shared_ptr_base.h:1071 (gdb+0x9ceca8)
    #20 std::__shared_ptr<gdb::task_group::impl, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/12/bits/shared_ptr_base.h:1524 (gdb+0x9ceca8)
    #21 std::shared_ptr<gdb::task_group::impl>::~shared_ptr() /usr/include/c++/12/bits/shared_ptr.h:175 (gdb+0x9ceca8)
    #22 ~<lambda> ../../binutils-gdb/gdbsupport/task-group.cc:65 (gdb+0x9ceca8)
    #23 _M_destroy /usr/include/c++/12/bits/std_function.h:175 (gdb+0x9ceca8)
    #24 _M_manager /usr/include/c++/12/bits/std_function.h:203 (gdb+0x9ceca8)
    #25 _M_manager /usr/include/c++/12/bits/std_function.h:282 (gdb+0x9ceca8)
    #26 std::_Function_base::~_Function_base() /usr/include/c++/12/bits/std_function.h:244 (gdb+0x31b613)
    #27 std::function<void ()>::~function() /usr/include/c++/12/bits/std_function.h:334 (gdb+0x31b613)
    #28 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_Impl::~_Impl() /usr/include/c++/12/future:1489 (gdb+0x31b613)
    #29 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::~_Task_state() /usr/include/c++/12/future:1455 (gdb+0x31b613)
    #30 void std::__new_allocator<int>::destroy<std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()> >(std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>*) /usr/include/c++/12/bits/new_allocator.h:181 (gdb+0x31b613)
    #31 void std::allocator_traits<std::allocator<int> >::destroy<std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()> >(std::allocator<int>&, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>*) /usr/include/c++/12/bits/alloc_traits.h:535 (gdb+0x31b613)
    #32 std::_Sp_counted_ptr_inplace<std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>, std::allocator<int>, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/include/c++/12/bits/shared_ptr_base.h:613 (gdb+0x31b613)
    #33 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release_last_use() /usr/include/c++/12/bits/shared_ptr_base.h:175 (gdb+0x9d6129)
    #34 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/12/bits/shared_ptr_base.h:361 (gdb+0x9d6129)
    #35 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/12/bits/shared_ptr_base.h:1071 (gdb+0x9d6129)
    #36 std::__shared_ptr<std::__future_base::_Task_state_base<void ()>, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/12/bits/shared_ptr_base.h:1524 (gdb+0x9d6129)
    #37 std::shared_ptr<std::__future_base::_Task_state_base<void ()> >::~shared_ptr() /usr/include/c++/12/bits/shared_ptr.h:175 (gdb+0x9d6129)
    #38 std::packaged_task<void ()>::~packaged_task() /usr/include/c++/12/future:1571 (gdb+0x9d6129)
    #39 std::_Optional_payload_base<std::packaged_task<void ()> >::_M_destroy() /usr/include/c++/12/optional:287 (gdb+0x9d6129)
    #40 std::_Optional_payload_base<std::packaged_task<void ()> >::_M_reset() /usr/include/c++/12/optional:318 (gdb+0x9d6129)
    #41 std::_Optional_payload<std::packaged_task<void ()>, false, false, false>::~_Optional_payload() /usr/include/c++/12/optional:439 (gdb+0x9d6129)
    #42 std::_Optional_base<std::packaged_task<void ()>, false, false>::~_Optional_base() /usr/include/c++/12/optional:510 (gdb+0x9d6129)
    #43 std::optional<std::packaged_task<void ()> >::~optional() /usr/include/c++/12/optional:705 (gdb+0x9d6129)
    #44 gdb::thread_pool::thread_function() ../../binutils-gdb/gdbsupport/thread-pool.cc:246 (gdb+0x9d6129)
    #45 void std::__invoke_impl<void, void (gdb::thread_pool::*)(), gdb::thread_pool*>(std::__invoke_memfun_deref, void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/12/bits/invoke.h:74 (gdb+0x9d70cb)
    #46 std::__invoke_result<void (gdb::thread_pool::*)(), gdb::thread_pool*>::type std::__invoke<void (gdb::thread_pool::*)(), gdb::thread_pool*>(void (gdb::thread_pool::*&&)(), gdb::thread_pool*&&) /usr/include/c++/12/bits/invoke.h:96 (gdb+0x9d70cb)
    #47 void std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/12/bits/std_thread.h:252 (gdb+0x9d70cb)
    #48 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/12/bits/std_thread.h:259 (gdb+0x9d70cb)
    #49 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/12/bits/std_thread.h:210 (gdb+0x9d70cb)
    #50 <null> <null> (libstdc++.so.6+0xd44a2)

  Previous write of size 1 at 0x7b0c00000150 by main thread:
    #0 memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827 (libtsan.so.2+0x5dda6)
    #1 memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:819 (libtsan.so.2+0x5dda6)
    #2 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) <null> (libstdc++.so.6+0x13fc5a)
    #3 do_set_command(char const*, int, cmd_list_element*) ../../binutils-gdb/gdb/cli/cli-setshow.c:402 (gdb+0x28b24f)
    #4 execute_command(char const*, int) ../../binutils-gdb/gdb/top.c:561 (gdb+0x72556a)
    #5 mi_execute_cli_command(char const*, bool, char const*) ../../binutils-gdb/gdb/mi/mi-main.c:2174 (gdb+0x558166)
    #6 mi_command_cli::invoke(mi_parse*) const ../../binutils-gdb/gdb/mi/mi-cmds.c:90 (gdb+0x54f800)
    #7 mi_cmd_execute ../../binutils-gdb/gdb/mi/mi-main.c:2148 (gdb+0x55b838)
    #8 captured_mi_execute_command ../../binutils-gdb/gdb/mi/mi-main.c:1831 (gdb+0x55c8dd)
    #9 mi_execute_command(char const*, int) ../../binutils-gdb/gdb/mi/mi-main.c:1955 (gdb+0x55c8dd)
    #10 mi_execute_command_wrapper ../../binutils-gdb/gdb/mi/mi-interp.c:221 (gdb+0x550e99)
    #11 mi_execute_command_input_handler ../../binutils-gdb/gdb/mi/mi-interp.c:243 (gdb+0x550e99)
    #12 gdb_readline_no_editing_callback(void*) ../../binutils-gdb/gdb/event-top.c:873 (gdb+0x3d8840)
    #13 stdin_event_handler ../../binutils-gdb/gdb/ui.c:154 (gdb+0x74dadf)
    #14 handle_file_event ../../binutils-gdb/gdbsupport/event-loop.cc:551 (gdb+0x9c42c5)
    #15 gdb_wait_for_event ../../binutils-gdb/gdbsupport/event-loop.cc:672 (gdb+0x9c49ca)
    #16 gdb_do_one_event(int) ../../binutils-gdb/gdbsupport/event-loop.cc:263 (gdb+0x9c53eb)
    #17 start_event_loop ../../binutils-gdb/gdb/main.c:401 (gdb+0x521e29)
    #18 captured_command_loop ../../binutils-gdb/gdb/main.c:465 (gdb+0x521e29)
    #19 captured_main ../../binutils-gdb/gdb/main.c:1339 (gdb+0x525cc4)
    #20 gdb_main(captured_main_args*) ../../binutils-gdb/gdb/main.c:1358 (gdb+0x525cc4)
    #21 main ../../binutils-gdb/gdb/gdb.c:38 (gdb+0x114b04)

  Location is heap block of size 42 at 0x7b0c00000150 allocated by main thread:
    #0 operator new(unsigned long) ../../../../src/libsanitizer/tsan/tsan_new_delete.cpp:64 (libtsan.so.2+0x87323)
    #1 void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*>(char const*, char const*, std::forward_iterator_tag) /usr/include/c++/12/bits/basic_string.tcc:225 (gdb+0x521ccc)
    #2 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> >(char const*, std::allocator<char> const&) /usr/include/c++/12/bits/basic_string.h:642 (gdb+0x522234)
    #3 relocate_path ../../binutils-gdb/gdb/main.c:142 (gdb+0x522234)
    #4 relocate_gdb_directory[abi:cxx11](char const*, bool) ../../binutils-gdb/gdb/main.c:156 (gdb+0x523385)
    #5 captured_main_1 ../../binutils-gdb/gdb/main.c:722 (gdb+0x523e15)
    #6 captured_main ../../binutils-gdb/gdb/main.c:1329 (gdb+0x525cba)
    #7 gdb_main(captured_main_args*) ../../binutils-gdb/gdb/main.c:1358 (gdb+0x525cba)
    #8 main ../../binutils-gdb/gdb/gdb.c:38 (gdb+0x114b04)

  Thread T2 'gdb worker' (tid=32119, running) created by main thread at:
    #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1001 (libtsan.so.2+0x5e686)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xd4578)
    #2 update_thread_pool_size() ../../binutils-gdb/gdb/maint.c:865 (gdb+0x52e4b2)
    #3 captured_main_1 ../../binutils-gdb/gdb/main.c:1055 (gdb+0x524628)
    #4 captured_main ../../binutils-gdb/gdb/main.c:1329 (gdb+0x525cba)
    #5 gdb_main(captured_main_args*) ../../binutils-gdb/gdb/main.c:1358 (gdb+0x525cba)
    #6 main ../../binutils-gdb/gdb/gdb.c:38 (gdb+0x114b04)

SUMMARY: ThreadSanitizer: data race ../../binutils-gdb/libiberty/concat.c:65 in vconcat_length
==================
ThreadSanitizer: reported 1 warnings
Comment 1 Bernd Edlinger 2024-05-09 09:51:23 UTC
I dont know why, but FYI the same test
did not report an issue with gcc-14.0.1
Comment 2 Tom Tromey 2024-05-13 17:38:46 UTC
The problem code is:

	  search_path_holder.reset (concat (".", dirname_separator_string,
					    debug_file_directory.c_str (),
					    (char *) NULL));


debug_file_directory is a global that can be modified
using "set debug-file-directory".

Probably the DWARF reader can capture this global early and use
the captured value in try_open_dwop_file.  This would give
the same semantics as today.
Comment 3 Tom Tromey 2024-05-13 17:42:17 UTC
openp also expands $cwd, so we'll need a special capture for
that as well.
Comment 4 Bernd Edlinger 2024-05-18 14:20:28 UTC
Also this race condition is no longer reported with this patch applied:
https://sourceware.org/pipermail/gdb-patches/2024-May/209267.html