transport-helper: fix TSAN race in transfer_debug()
Currently, transfer_debug() lazily initializes a static variable based on GIT_TRANSLOOP_DEBUG. Since the function may be called from multiple worker threads, this initialization is racy and is therefore suppressed in .tsan-suppressions. Initialize the variable in bidirectional_transfer_loop() before any worker threads or processes are created. This patch removes the race and allows dropping the corresponding TSAN suppression. Signed-off-by: Pushkar Singh <pushkarkumarsingh1970@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Pushkar Singh committed
Jun 9, 2026 at 13:47 UTC
85704eda1820b350a9916b17d6d25fa33f68207d
2 files changed
+8
-12
.tsan-suppressions
-1
@@ -7,7 +7,6 @@
7
# A static variable is written to racily, but we always write the same value, so
8
# in practice it (hopefully!) doesn't matter.
9
race:^want_color$
10
-race:^transfer_debug$
10
11
# A boolean value, which tells whether the replace_map has been initialized or
12
# not, is read racily with an update. As this variable is written to only once,
transport-helper.c
+8
-11
@@ -1343,24 +1343,18 @@ int transport_helper_init(struct transport *transport, const char *name)
1343
/* This should be enough to hold debugging message. */
1344
#define PBUFFERSIZE 8192
1345
1346
+static int transfer_debug_enabled = -1;
1347
+
1348
/* Print bidirectional transfer loop debug message. */
1349
__attribute__((format (printf, 1, 2)))
1350
static void transfer_debug(const char *fmt, ...)
1351
{
1350
- /*
1351
- * NEEDSWORK: This function is sometimes used from multiple threads, and
1352
- * we end up using debug_enabled racily. That "should not matter" since
1353
- * we always write the same value, but it's still wrong. This function
1354
- * is listed in .tsan-suppressions for the time being.
1355
- */
1356
-
1352
va_list args;
1353
char msgbuf[PBUFFERSIZE];
1359
- static int debug_enabled = -1;
1354
1361
- if (debug_enabled < 0)
1362
- debug_enabled = getenv("GIT_TRANSLOOP_DEBUG") ? 1 : 0;
1363
- if (!debug_enabled)
1355
+ if (transfer_debug_enabled < 0)
1356
+ BUG("somebody forgot to check GIT_TRANSLOOP_DEBUG!");
1357
+ if (!transfer_debug_enabled)
1358
return;
1359
1360
va_start(args, fmt);
@@ -1630,6 +1624,9 @@ int bidirectional_transfer_loop(int input, int output)
1624
{
1625
struct bidirectional_transfer_state state;
1626
1627
+ if (transfer_debug_enabled < 0)
1628
+ transfer_debug_enabled = getenv("GIT_TRANSLOOP_DEBUG") ? 1 : 0;
1629
+
1630
/* Fill the state fields. */
1631
state.ptg.src = input;
1632
state.ptg.dest = 1;