From bacc61fd3e6fd61a59fb59bcc657be17a381520d Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Mon, 12 Feb 2024 18:06:56 -0700 Subject: Thread-safety improvements for bfd_check_format_matches A gdb bug found that bfd_check_format_matches has some data races when called from multiple threads. In particular, it changes the BFD error handler, which is a global. It also has a local static variable ("in_check_format") that is used for recursion detection. And, finally, it may emit warnings to the per-xvec warning array, which is a global. This patch removes all the races here. The first part of patch is to change _bfd_error_handler to directly handle the needs of bfd_check_format_matches. This way, the error handler does not need to be changed. This change lets us use the new per-thread global (error_handler_messages, replacing error_handler_bfd) to also remove the need for in_check_format -- a single variable suffices. Finally, the global per-xvec array is replaced with a new type that holds the error messages. The outermost such type is stack-allocated in bfd_check_format_matches. I tested this using the binutils test suite. I also built gdb with thread sanitizer and ran the test case that was noted as failing. Finally, Alan sent me the test file that caused the addition of the xvec warning code in the first place, and I confirmed that "nm-new" has the same behavior on this file both before and after this patch. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31264 Co-Authored-By: Alan Modra --- bfd/targets.c | 58 ---------------------------------------------------------- 1 file changed, 58 deletions(-) (limited to 'bfd/targets.c') diff --git a/bfd/targets.c b/bfd/targets.c index 532b646..0d5d73b 100644 --- a/bfd/targets.c +++ b/bfd/targets.c @@ -1454,9 +1454,6 @@ const bfd_target *const *const bfd_associated_vector = _bfd_associated_vector; number of entries that the array could possibly need. */ const size_t _bfd_target_vector_entries = ARRAY_SIZE (_bfd_target_vector); -/* A place to stash a warning from _bfd_check_format. */ -static struct per_xvec_message *per_xvec_warn[ARRAY_SIZE (_bfd_target_vector) - + 1]; /* This array maps configuration triplets onto BFD vectors. */ @@ -1476,61 +1473,6 @@ static const struct targmatch bfd_target_match[] = { { NULL, NULL } }; -/* -INTERNAL -.{* Cached _bfd_check_format messages are put in this. *} -.struct per_xvec_message -.{ -. struct per_xvec_message *next; -. char message[]; -.}; -. -INTERNAL_FUNCTION - _bfd_per_xvec_warn - -SYNOPSIS - struct per_xvec_message **_bfd_per_xvec_warn (const bfd_target *, size_t); - -DESCRIPTION - Return a location for the given target xvec to use for - warnings specific to that target. If TARG is NULL, returns - the array of per_xvec_message pointers, otherwise if ALLOC is - zero, returns a pointer to a pointer to the list of messages - for TARG, otherwise (both TARG and ALLOC non-zero), allocates - a new per_xvec_message with space for a string of ALLOC - bytes and returns a pointer to a pointer to it. May return a - pointer to a NULL pointer on allocation failure. -*/ - -struct per_xvec_message ** -_bfd_per_xvec_warn (const bfd_target *targ, size_t alloc) -{ - size_t idx; - - if (!targ) - return per_xvec_warn; - for (idx = 0; idx < ARRAY_SIZE (_bfd_target_vector); idx++) - if (_bfd_target_vector[idx] == targ) - break; - struct per_xvec_message **m = per_xvec_warn + idx; - if (!alloc) - return m; - int count = 0; - while (*m) - { - m = &(*m)->next; - count++; - } - /* Anti-fuzzer measure. Don't cache more than 5 messages. */ - if (count < 5) - { - *m = bfd_malloc (sizeof (**m) + alloc); - if (*m != NULL) - (*m)->next = NULL; - } - return m; -} - /* Find a target vector, given a name or configuration triplet. */ static const bfd_target * -- cgit v1.1