git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 4/5] index-pack: work around LSan threading race with barrier

From
Jeff King <peff@peff.net>
Date
Dec 30, 2024, 04:29 UTC
Message-ID
<20241230042938.GD113400@coredump.intra.peff.net>
In-Reply-To
<20241230042325.GA112439@coredump.intra.peff.net>

We sometimes get false positives from our linux-leaks CI job because of a race in LSan itself. The problem is that one thread is still initializing its stack in LSan's code (and allocating memory to do so) while anothe thread calls die(), taking down the whole process and triggering a leak check.

The problem is described in more detail in 993d38a066 (index-pack: spawn threads atomically, 2024-01-05), which tried to fix it by pausing worker threads until all calls to pthread_create() had completed. But that's not enough to fix the problem, because the LSan setup code runs in the threads themselves. So even though pthread_create() has returned, we have no idea if all threads actually finished their setup before letting any of them do real work.

We can fix that by using a barrier inside the threads themselves, waiting for all of them to hit the start of their main function before any of them proceed.

You can test for the race by running:
  make SANITIZE=leak THREAD_BARRIER_PTHREAD=YesOnLinux
  cd t
  ./t5309-pack-delta-cycles.sh --stress

which fails quickly before this patch, and should run indefinitely without it.

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/index-pack.c | 6 ++++++
 1 file changed, 6 insertions(+)
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 0b62b2589f..27b120f26c 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -185,6 +185,8 @@ static pthread_mutex_t deepest_delta_mutex;
 
 static pthread_key_t key;
 
+static maybe_thread_barrier_t start_barrier;
+
 static inline void lock_mutex(pthread_mutex_t *mutex)
 {
 	if (threads_active)
@@ -209,6 +211,7 @@ static void init_thread(void)
 	if (show_stat)
 		pthread_mutex_init(&deepest_delta_mutex, NULL);
 	pthread_key_create(&key, NULL);
+	maybe_thread_barrier_init(&start_barrier, NULL, nr_threads);
 	CALLOC_ARRAY(thread_data, nr_threads);
 	for (i = 0; i < nr_threads; i++) {
 		thread_data[i].pack_fd = xopen(curr_pack, O_RDONLY);
@@ -231,6 +234,7 @@ static void cleanup_thread(void)
 	for (i = 0; i < nr_threads; i++)
 		close(thread_data[i].pack_fd);
 	pthread_key_delete(key);
+	maybe_thread_barrier_destroy(&start_barrier);
 	free(thread_data);
 }
 
@@ -1100,6 +1104,8 @@ static int compare_ref_delta_entry(const void *a, const void *b)
 
 static void *threaded_second_pass(void *data)
 {
+	if (threads_active)
+		maybe_thread_barrier_wait(&start_barrier);
 	if (data)
 		set_thread_data(data);
 	for (;;) {
-- 
bar
Previous: Patrick SteinhardtNext: Jeff King
Message 10 of 11 in “fixing thread races in linux-leaks CI”
  1. 0/5 fixing thread races in linux-leaks CIJeff King, Dec 30, 2024
  2. 1/5 test-lib: use individual lsan dir for --stress runsJeff King, Dec 30, 2024
  3. Jeff KingDec 30, 2024
  4. Junio C HamanoDec 30, 2024
  5. 2/5 Revert "index-pack: spawn threads atomically"Jeff King, Dec 30, 2024
  6. 3/5 thread-utils: introduce optional barrier typeJeff King, Dec 30, 2024
  7. Patrick SteinhardtDec 30, 2024
  8. Jeff KingJan 1, 2025
  9. Patrick SteinhardtJan 3, 2025
  10. 4/5 index-pack: work around LSan threading race with barrierJeff King, Dec 30, 2024
  11. 5/5 grep: work around LSan threading race with barrierJeff King, Dec 30, 2024

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.