* [pushed 0/4] [gdb/symtab] Fix more index-cache data races
@ 2023-08-04 13:06 Tom de Vries
2023-08-04 13:06 ` [pushed 1/4] [gdb/symtab] Fix data race on dwarf2_per_cu_data::{mark,is_debug_types} Tom de Vries
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Tom de Vries @ 2023-08-04 13:06 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
PR symtab/30718 reports two more data races when using the index-cache.
This series contains:
- two fixes, one for each data race,
- a test-case patch that addresses a problem that made it difficult to
reproduce the data races in the gdb.base/index-cache.exp test-case, and
- a test-case patch that adds the regression test for this PR.
Because the fixes are similar to the recently committed patches:
- [gdb/symtab] Fix data race on
dwarf2_per_cu_data::{m_header_read_in,is_debug_type}
- [gdb/symtab] Fix race on dwarf2_per_cu_data::{queued,is_debug_type}
I consider them obvious.
Tested on x86_64-linux.
Tom de Vries (4):
[gdb/symtab] Fix data race on
dwarf2_per_cu_data::{mark,is_debug_types}
[gdb/symtab] Fix data race on
dwarf2_per_cu_data::{files_read,is_debug_types}
[gdb/testsuite] Move "maint wait-for-index-cache" ALAP in
gdb.base/index-cache.exp
[gdb/testsuite] Extend gdb.base/index-cache.exp further
gdb/dwarf2/read.h | 20 ++++++------
gdb/testsuite/gdb.base/index-cache.exp | 45 +++++++++++++++-----------
2 files changed, 37 insertions(+), 28 deletions(-)
base-commit: b44293099e215d6558a8d91b5eaab137218d2e27
--
2.35.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [pushed 1/4] [gdb/symtab] Fix data race on dwarf2_per_cu_data::{mark,is_debug_types}
2023-08-04 13:06 [pushed 0/4] [gdb/symtab] Fix more index-cache data races Tom de Vries
@ 2023-08-04 13:06 ` Tom de Vries
2023-08-04 13:06 ` [pushed 2/4] [gdb/symtab] Fix data race on dwarf2_per_cu_data::{files_read,is_debug_types} Tom de Vries
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Tom de Vries @ 2023-08-04 13:06 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
With gdb build with -fsanitize=thread, and the exec from test-case
gdb.base/index-cache.exp, I run into:
...
$ rm -f ~/.cache/gdb/*; \
gdb -q -batch -iex "set index-cache enabled on" index-cache \
-ex "print foobar"
...
WARNING: ThreadSanitizer: data race (pid=23970)
Write of size 1 at 0x7b200000410d by main thread:
#0 dw_expand_symtabs_matching_file_matcher(dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>) gdb/dwarf2/read.c:3077 (gdb+0x7ac54e)
#1 cooked_index_functions::expand_symtabs_matching(objfile*, gdb::function_view<bool (char const*, bool)>, lookup_name_info const*, gdb::function_view<bool (char const*)>, gdb::function_view<bool (compunit_symtab*)>, enum_flags<block_search_flag_values>, domain_enum, search_domain) gdb/dwarf2/read.c:16812 (gdb+0x7d039f)
#2 objfile::map_symtabs_matching_filename(char const*, char const*, gdb::function_view<bool (symtab*)>) gdb/symfile-debug.c:219 (gdb+0xda5aee)
#3 iterate_over_symtabs(char const*, gdb::function_view<bool (symtab*)>) gdb/symtab.c:648 (gdb+0xdc439d)
#4 lookup_symtab(char const*) gdb/symtab.c:662 (gdb+0xdc44a2)
#5 classify_name gdb/c-exp.y:3083 (gdb+0x61afec)
#6 c_yylex gdb/c-exp.y:3251 (gdb+0x61dd13)
#7 c_yyparse() build/gdb/c-exp.c.tmp:1988 (gdb+0x61f07e)
#8 c_parse(parser_state*) gdb/c-exp.y:3417 (gdb+0x62d864)
#9 language_defn::parser(parser_state*) const gdb/language.c:598 (gdb+0x9771c5)
#10 parse_exp_in_context gdb/parse.c:414 (gdb+0xb10a9b)
#11 parse_expression(char const*, innermost_block_tracker*, enum_flags<parser_flag>) gdb/parse.c:462 (gdb+0xb110ae)
#12 process_print_command_args gdb/printcmd.c:1321 (gdb+0xb4bf0c)
#13 print_command_1 gdb/printcmd.c:1335 (gdb+0xb4ca2a)
#14 print_command gdb/printcmd.c:1468 (gdb+0xb4cd5a)
#15 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x65b078)
#16 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x65ed53)
#17 execute_command(char const*, int) gdb/top.c:575 (gdb+0xe3a76a)
#18 catch_command_errors gdb/main.c:518 (gdb+0xa1837d)
#19 execute_cmdargs gdb/main.c:617 (gdb+0xa1853f)
#20 captured_main_1 gdb/main.c:1289 (gdb+0xa1aa58)
#21 captured_main gdb/main.c:1310 (gdb+0xa1b95a)
#22 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xa1b95a)
#23 main gdb/gdb.c:39 (gdb+0x42506a)
Previous read of size 1 at 0x7b200000410d by thread T1:
#0 write_gdbindex gdb/dwarf2/index-write.c:1214 (gdb+0x75bb30)
#1 write_dwarf_index(dwarf2_per_bfd*, char const*, char const*, char const*, dw_index_kind) gdb/dwarf2/index-write.c:1469 (gdb+0x75f803)
#2 index_cache::store(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/index-cache.c:173 (gdb+0x755a36)
#3 cooked_index::maybe_write_index(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/cooked-index.c:642 (gdb+0x71c96d)
#4 operator() gdb/dwarf2/cooked-index.c:471 (gdb+0x71c96d)
#5 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x71c96d)
#6 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x72a57c)
#7 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x72a5db)
#8 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x72a5db)
#9 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x72a5db)
#10 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x72a5db)
#11 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x72a5db)
#12 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x724954)
#13 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x724954)
#14 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x72434a)
#15 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x72434a)
#16 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x72434a)
#17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x72434a)
#18 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x72434a)
#19 pthread_once <null> (libtsan.so.0+0x4457c)
#20 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72532b)
#21 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x72532b)
#22 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x174568d)
#23 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x174568d)
#24 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x174568d)
#25 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x174568d)
#26 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++/7/bits/invoke.h:73 (gdb+0x1748040)
#27 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++/7/bits/invoke.h:95 (gdb+0x1748040)
#28 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x1748040)
#29 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x1748040)
#30 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x1748040)
#31 <null> <null> (libstdc++.so.6+0xdcac2)
...
SUMMARY: ThreadSanitizer: data race gdb/dwarf2/read.c:3077 in dw_expand_symtabs_matching_file_matcher(dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>)
...
The race happens when issuing the "file $exec" command.
The race is between:
- a worker thread writing the index cache, and in the process reading
dwarf2_per_cu_data::is_debug_type, and
- the main thread writing to dwarf2_per_cu_data::mark.
The two bitfields dwarf2_per_cu_data::mark and
dwarf2_per_cu_data::is_debug_type share the same bitfield container.
Fix this by making dwarf2_per_cu_data::mark a packed<unsigned int, 1>.
Tested on x86_64-linux.
PR symtab/30718
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30718
---
gdb/dwarf2/read.h | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index 5f7d2dcd895..44bc3ce88a0 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -104,10 +104,10 @@ struct dwarf2_per_cu_data
is_dwz (false),
reading_dwo_directly (false),
tu_read (false),
- mark (false),
files_read (false),
queued (false),
m_header_read_in (false),
+ mark (false),
scanned (false)
{
}
@@ -150,10 +150,6 @@ struct dwarf2_per_cu_data
This flag is only valid if is_debug_types is true. */
unsigned int tu_read : 1;
- /* A temporary mark bit used when iterating over all CUs in
- expand_symtabs_matching. */
- unsigned int mark : 1;
-
/* True if we've tried to read the file table. There will be no
point in trying to read it again next time. */
bool files_read : 1;
@@ -176,6 +172,10 @@ struct dwarf2_per_cu_data
it private at the moment. */
mutable packed<bool, 1> m_header_read_in;
+ /* A temporary mark bit used when iterating over all CUs in
+ expand_symtabs_matching. */
+ packed<unsigned int, 1> mark;
+
private:
/* The unit type of this CU. */
std::atomic<packed<dwarf_unit_type, 1>> m_unit_type {(dwarf_unit_type)0};
--
2.35.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [pushed 2/4] [gdb/symtab] Fix data race on dwarf2_per_cu_data::{files_read,is_debug_types}
2023-08-04 13:06 [pushed 0/4] [gdb/symtab] Fix more index-cache data races Tom de Vries
2023-08-04 13:06 ` [pushed 1/4] [gdb/symtab] Fix data race on dwarf2_per_cu_data::{mark,is_debug_types} Tom de Vries
@ 2023-08-04 13:06 ` Tom de Vries
2023-08-04 13:06 ` [pushed 3/4] [gdb/testsuite] Move "maint wait-for-index-cache" ALAP in gdb.base/index-cache.exp Tom de Vries
2023-08-04 13:06 ` [pushed 4/4] [gdb/testsuite] Extend gdb.base/index-cache.exp further Tom de Vries
3 siblings, 0 replies; 5+ messages in thread
From: Tom de Vries @ 2023-08-04 13:06 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
With gdb build with -fsanitize=thread, and the exec from test-case
gdb.base/index-cache.exp, I run into:
...
$ rm -f ~/.cache/gdb/*; \
gdb -q -batch -iex "set index-cache enabled on" index-cache \
-ex "print foobar"
...
WARNING: ThreadSanitizer: data race (pid=25018)
Write of size 1 at 0x7b200000410d by main thread:
#0 dw2_get_file_names_reader gdb/dwarf2/read.c:2033 (gdb+0x7ab023)
#1 dw2_get_file_names gdb/dwarf2/read.c:2130 (gdb+0x7ab023)
#2 dw_expand_symtabs_matching_file_matcher(dwarf2_per_objfile*, gdb::function_view<bool (char const*, bool)>) gdb/dwarf2/read.c:3105 (gdb+0x7ac6e9)
#3 cooked_index_functions::expand_symtabs_matching(objfile*, gdb::function_view<bool (char const*, bool)>, lookup_name_info const*, gdb::function_view<bool (char const*)>, gdb::function_view<bool (compunit_symtab*)>, enum_flags<block_search_flag_values>, domain_enum, search_domain) gdb/dwarf2/read.c:16812 (gdb+0x7d040f)
#4 objfile::map_symtabs_matching_filename(char const*, char const*, gdb::function_view<bool (symtab*)>) gdb/symfile-debug.c:219 (gdb+0xda5b6e)
#5 iterate_over_symtabs(char const*, gdb::function_view<bool (symtab*)>) gdb/symtab.c:648 (gdb+0xdc441d)
#6 lookup_symtab(char const*) gdb/symtab.c:662 (gdb+0xdc4522)
#7 classify_name gdb/c-exp.y:3083 (gdb+0x61afec)
#8 c_yylex gdb/c-exp.y:3251 (gdb+0x61dd13)
#9 c_yyparse() build/gdb/c-exp.c.tmp:1988 (gdb+0x61f07e)
#10 c_parse(parser_state*) gdb/c-exp.y:3417 (gdb+0x62d864)
#11 language_defn::parser(parser_state*) const gdb/language.c:598 (gdb+0x977245)
#12 parse_exp_in_context gdb/parse.c:414 (gdb+0xb10b1b)
#13 parse_expression(char const*, innermost_block_tracker*, enum_flags<parser_flag>) gdb/parse.c:462 (gdb+0xb1112e)
#14 process_print_command_args gdb/printcmd.c:1321 (gdb+0xb4bf8c)
#15 print_command_1 gdb/printcmd.c:1335 (gdb+0xb4caaa)
#16 print_command gdb/printcmd.c:1468 (gdb+0xb4cdda)
#17 do_simple_func gdb/cli/cli-decode.c:95 (gdb+0x65b078)
#18 cmd_func(cmd_list_element*, char const*, int) gdb/cli/cli-decode.c:2735 (gdb+0x65ed53)
#19 execute_command(char const*, int) gdb/top.c:575 (gdb+0xe3a7ea)
#20 catch_command_errors gdb/main.c:518 (gdb+0xa183fd)
#21 execute_cmdargs gdb/main.c:617 (gdb+0xa185bf)
#22 captured_main_1 gdb/main.c:1289 (gdb+0xa1aad8)
#23 captured_main gdb/main.c:1310 (gdb+0xa1b9da)
#24 gdb_main(captured_main_args*) gdb/main.c:1339 (gdb+0xa1b9da)
#25 main gdb/gdb.c:39 (gdb+0x42506a)
Previous read of size 1 at 0x7b200000410d by thread T2:
#0 write_gdbindex gdb/dwarf2/index-write.c:1214 (gdb+0x75bb30)
#1 write_dwarf_index(dwarf2_per_bfd*, char const*, char const*, char const*, dw_index_kind) gdb/dwarf2/index-write.c:1469 (gdb+0x75f803)
#2 index_cache::store(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/index-cache.c:173 (gdb+0x755a36)
#3 cooked_index::maybe_write_index(dwarf2_per_bfd*, index_cache_store_context const&) gdb/dwarf2/cooked-index.c:642 (gdb+0x71c96d)
#4 operator() gdb/dwarf2/cooked-index.c:471 (gdb+0x71c96d)
#5 _M_invoke /usr/include/c++/7/bits/std_function.h:316 (gdb+0x71c96d)
#6 std::function<void ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x72a57c)
#7 void std::__invoke_impl<void, std::function<void ()>&>(std::__invoke_other, std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:60 (gdb+0x72a5db)
#8 std::__invoke_result<std::function<void ()>&>::type std::__invoke<std::function<void ()>&>(std::function<void ()>&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x72a5db)
#9 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}::operator()() const /usr/include/c++/7/future:1421 (gdb+0x72a5db)
#10 std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void>::operator()() const /usr/include/c++/7/future:1362 (gdb+0x72a5db)
#11 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run()::{lambda()#1}, void> >::_M_invoke(std::_Any_data const&) /usr/include/c++/7/bits/std_function.h:302 (gdb+0x72a5db)
#12 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/include/c++/7/bits/std_function.h:706 (gdb+0x724954)
#13 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) /usr/include/c++/7/future:561 (gdb+0x724954)
#14 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:73 (gdb+0x72434a)
#15 std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/bits/invoke.h:95 (gdb+0x72434a)
#16 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const /usr/include/c++/7/mutex:672 (gdb+0x72434a)
#17 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::operator()() const /usr/include/c++/7/mutex:677 (gdb+0x72434a)
#18 std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#2}::_FUN() /usr/include/c++/7/mutex:677 (gdb+0x72434a)
#19 pthread_once <null> (libtsan.so.0+0x4457c)
#20 __gthread_once /usr/include/c++/7/x86_64-suse-linux/bits/gthr-default.h:699 (gdb+0x72532b)
#21 void std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) /usr/include/c++/7/mutex:684 (gdb+0x72532b)
#22 std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>, bool) /usr/include/c++/7/future:401 (gdb+0x174570d)
#23 std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>::_M_run() /usr/include/c++/7/future:1423 (gdb+0x174570d)
#24 std::packaged_task<void ()>::operator()() /usr/include/c++/7/future:1556 (gdb+0x174570d)
#25 gdb::thread_pool::thread_function() gdbsupport/thread-pool.cc:242 (gdb+0x174570d)
#26 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++/7/bits/invoke.h:73 (gdb+0x17480c0)
#27 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++/7/bits/invoke.h:95 (gdb+0x17480c0)
#28 decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/include/c++/7/thread:234 (gdb+0x17480c0)
#29 std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> >::operator()() /usr/include/c++/7/thread:243 (gdb+0x17480c0)
#30 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (gdb::thread_pool::*)(), gdb::thread_pool*> > >::_M_run() /usr/include/c++/7/thread:186 (gdb+0x17480c0)
#31 <null> <null> (libstdc++.so.6+0xdcac2)
...
SUMMARY: ThreadSanitizer: data race gdb/dwarf2/read.c:2033 in dw2_get_file_names_reader
...
The race happens when issuing the "file $exec" command.
The race is between:
- a worker thread writing the index cache, and in the process reading
dwarf2_per_cu_data::is_debug_type, and
- the main thread writing to dwarf2_per_cu_data::files_read.
The two bitfields dwarf2_per_cu_data::files_read and
dwarf2_per_cu_data::is_debug_type share the same bitfield container.
Fix this by making dwarf2_per_cu_data::files_read a packed<bool, 1>.
Tested on x86_64-linux.
PR symtab/30718
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30718
---
gdb/dwarf2/read.h | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index 44bc3ce88a0..9dfc435e861 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -104,10 +104,10 @@ struct dwarf2_per_cu_data
is_dwz (false),
reading_dwo_directly (false),
tu_read (false),
- files_read (false),
queued (false),
m_header_read_in (false),
mark (false),
+ files_read (false),
scanned (false)
{
}
@@ -150,10 +150,6 @@ struct dwarf2_per_cu_data
This flag is only valid if is_debug_types is true. */
unsigned int tu_read : 1;
- /* True if we've tried to read the file table. There will be no
- point in trying to read it again next time. */
- bool files_read : 1;
-
/* Wrap the following in struct packed instead of bitfields to avoid
data races when the bitfields end up on the same memory location
(per C++ memory model). */
@@ -176,6 +172,10 @@ struct dwarf2_per_cu_data
expand_symtabs_matching. */
packed<unsigned int, 1> mark;
+ /* True if we've tried to read the file table. There will be no
+ point in trying to read it again next time. */
+ packed<bool, 1> files_read;
+
private:
/* The unit type of this CU. */
std::atomic<packed<dwarf_unit_type, 1>> m_unit_type {(dwarf_unit_type)0};
--
2.35.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [pushed 3/4] [gdb/testsuite] Move "maint wait-for-index-cache" ALAP in gdb.base/index-cache.exp
2023-08-04 13:06 [pushed 0/4] [gdb/symtab] Fix more index-cache data races Tom de Vries
2023-08-04 13:06 ` [pushed 1/4] [gdb/symtab] Fix data race on dwarf2_per_cu_data::{mark,is_debug_types} Tom de Vries
2023-08-04 13:06 ` [pushed 2/4] [gdb/symtab] Fix data race on dwarf2_per_cu_data::{files_read,is_debug_types} Tom de Vries
@ 2023-08-04 13:06 ` Tom de Vries
2023-08-04 13:06 ` [pushed 4/4] [gdb/testsuite] Extend gdb.base/index-cache.exp further Tom de Vries
3 siblings, 0 replies; 5+ messages in thread
From: Tom de Vries @ 2023-08-04 13:06 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
In test-case gdb.base/index-cache.exp proc run_test_with_flags contains:
...
clean_restart ${testfile}
# The tests generally want to check the cache, so make sure it
# has completed its work.
gdb_test_no_output "maintenance wait-for-index-cache"
...
This however hides data races between:
- index-cache writing (due to file $exec), and
- symbol lookups (due to subsequent ptype commands).
Fix this by:
- moving the "maintenance wait-for-index-cache" to proc check_cache_stats, and
- moving all calls to proc check_cache_stats ALAP.
Tested on x86_64-linux.
---
gdb/testsuite/gdb.base/index-cache.exp | 36 +++++++++++++-------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/gdb/testsuite/gdb.base/index-cache.exp b/gdb/testsuite/gdb.base/index-cache.exp
index c26c4f94e65..1379a040445 100644
--- a/gdb/testsuite/gdb.base/index-cache.exp
+++ b/gdb/testsuite/gdb.base/index-cache.exp
@@ -65,6 +65,10 @@ proc ls_host { dir } {
# values.
proc check_cache_stats { expected_hits expected_misses } {
+ # This test wants to check the cache, so make sure it has completed
+ # its work.
+ gdb_test_no_output "maintenance wait-for-index-cache"
+
set re [multi_line \
" Cache hits .this session.: $expected_hits" \
"Cache misses .this session.: $expected_misses" \
@@ -84,10 +88,6 @@ proc run_test_with_flags { cache_dir cache_enabled code } {
clean_restart ${testfile}
- # The tests generally want to check the cache, so make sure it
- # has completed its work.
- gdb_test_no_output "maintenance wait-for-index-cache"
-
uplevel 1 $code
}
}
@@ -146,13 +146,13 @@ proc_with_prefix test_cache_disabled { cache_dir test_prefix } {
set nfiles_created [expr [llength $files_after] - [llength $files_before]]
gdb_assert "$nfiles_created == 0" "no files were created"
- check_cache_stats 0 0
-
# Trigger expansion of symtab containing main, if not already done.
gdb_test "ptype main" "^type = int \\(void\\)"
# Trigger expansion of symtab not containing main.
gdb_test "ptype foo" "^type = int \\(void\\)"
+
+ check_cache_stats 0 0
}
}
}
@@ -193,17 +193,17 @@ proc_with_prefix test_cache_enabled_miss { cache_dir } {
remote_exec host rm "-f $cache_dir/$expected_created_file"
- if { $expecting_index_cache_use } {
- check_cache_stats 0 1
- } else {
- check_cache_stats 0 0
- }
-
# Trigger expansion of symtab containing main, if not already done.
gdb_test "ptype main" "^type = int \\(void\\)"
# Trigger expansion of symtab not containing main.
gdb_test "ptype foo" "^type = int \\(void\\)"
+
+ if { $expecting_index_cache_use } {
+ check_cache_stats 0 1
+ } else {
+ check_cache_stats 0 0
+ }
}
}
@@ -228,17 +228,17 @@ proc_with_prefix test_cache_enabled_hit { cache_dir } {
set nfiles_created [expr [llength $files_after] - [llength $files_before]]
gdb_assert "$nfiles_created == 0" "no files were created"
- if { $expecting_index_cache_use } {
- check_cache_stats 1 0
- } else {
- check_cache_stats 0 0
- }
-
# Trigger expansion of symtab containing main, if not already done.
gdb_test "ptype main" "^type = int \\(void\\)"
# Trigger expansion of symtab not containing main.
gdb_test "ptype foo" "^type = int \\(void\\)"
+
+ if { $expecting_index_cache_use } {
+ check_cache_stats 1 0
+ } else {
+ check_cache_stats 0 0
+ }
}
}
--
2.35.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [pushed 4/4] [gdb/testsuite] Extend gdb.base/index-cache.exp further
2023-08-04 13:06 [pushed 0/4] [gdb/symtab] Fix more index-cache data races Tom de Vries
` (2 preceding siblings ...)
2023-08-04 13:06 ` [pushed 3/4] [gdb/testsuite] Move "maint wait-for-index-cache" ALAP in gdb.base/index-cache.exp Tom de Vries
@ 2023-08-04 13:06 ` Tom de Vries
3 siblings, 0 replies; 5+ messages in thread
From: Tom de Vries @ 2023-08-04 13:06 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
Add lookup of a non-existing symbol to test-case gdb.base/index-cache.exp.
This serves as regression test for PR symtab/30718.
PR symtab/30718
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30718
---
gdb/testsuite/gdb.base/index-cache.exp | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/gdb/testsuite/gdb.base/index-cache.exp b/gdb/testsuite/gdb.base/index-cache.exp
index 1379a040445..22f7a542df2 100644
--- a/gdb/testsuite/gdb.base/index-cache.exp
+++ b/gdb/testsuite/gdb.base/index-cache.exp
@@ -152,6 +152,9 @@ proc_with_prefix test_cache_disabled { cache_dir test_prefix } {
# Trigger expansion of symtab not containing main.
gdb_test "ptype foo" "^type = int \\(void\\)"
+ # Look for non-existent function.
+ gdb_test "ptype foobar" "^No symbol \"foobar\" in current context\\."
+
check_cache_stats 0 0
}
}
@@ -199,6 +202,9 @@ proc_with_prefix test_cache_enabled_miss { cache_dir } {
# Trigger expansion of symtab not containing main.
gdb_test "ptype foo" "^type = int \\(void\\)"
+ # Look for non-existent function.
+ gdb_test "ptype foobar" "^No symbol \"foobar\" in current context\\."
+
if { $expecting_index_cache_use } {
check_cache_stats 0 1
} else {
@@ -234,6 +240,9 @@ proc_with_prefix test_cache_enabled_hit { cache_dir } {
# Trigger expansion of symtab not containing main.
gdb_test "ptype foo" "^type = int \\(void\\)"
+ # Look for non-existent function.
+ gdb_test "ptype foobar" "^No symbol \"foobar\" in current context\\."
+
if { $expecting_index_cache_use } {
check_cache_stats 1 0
} else {
--
2.35.3
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2023-08-04 13:06 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-04 13:06 [pushed 0/4] [gdb/symtab] Fix more index-cache data races Tom de Vries
2023-08-04 13:06 ` [pushed 1/4] [gdb/symtab] Fix data race on dwarf2_per_cu_data::{mark,is_debug_types} Tom de Vries
2023-08-04 13:06 ` [pushed 2/4] [gdb/symtab] Fix data race on dwarf2_per_cu_data::{files_read,is_debug_types} Tom de Vries
2023-08-04 13:06 ` [pushed 3/4] [gdb/testsuite] Move "maint wait-for-index-cache" ALAP in gdb.base/index-cache.exp Tom de Vries
2023-08-04 13:06 ` [pushed 4/4] [gdb/testsuite] Extend gdb.base/index-cache.exp further Tom de Vries
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).