From: Olivier Houchard Date: Thu, 12 Nov 2026 11:58:20 +0000 (+0100) Subject: BUG/MEDIUM: threads: don't read lock history entries that don't fit in ulong X-Git-Tag: v3.5-dev12~24 X-Git-Url: https://git.kaiwu.me/%7B@url%7D?a=commitdiff_plain;h=e51c393f8fd5cb2898f7a241a0d38b4be61cefaf;p=haproxy.git BUG/MEDIUM: threads: don't read lock history entries that don't fit in ulong The per-thread lock history is stored in the "ulong lock_history" field, with 8 bits per lock operation. On 32-bit systems only 4 entries fit, but the dump code in ha_thread_dump_one() always read 8 of them, shifting the value by up to 56, which is undefined behavior with a 32-bit operand. Recent clang versions may generate bad code that will lead to a crash when using "show threads" on 32bits machines. Let's keep the field an ulong and only iterate over the entries that fit in it. On 64-bit nothing changes, and on 32-bit the last 4 entries are dumped, which is all the field stores anyway. This should be backported up to 3.2. --- diff --git a/src/debug.c b/src/debug.c index 69c1383b6..553ffe2d4 100644 --- a/src/debug.c +++ b/src/debug.c @@ -392,9 +392,10 @@ void ha_thread_dump_one(struct buffer *buf, int is_caller) if (th_ctx->lock_history) { int lkh, lkl, lbl; int done; + int slots = sizeof(th_ctx->lock_history); /* number of 8-bit entries */ chunk_appendf(buf, " lock_hist:"); - for (lkl = 7; lkl >= 0; lkl--) { + for (lkl = slots - 1; lkl >= 0; lkl--) { lkh = (th_ctx->lock_history >> (lkl * 8)) & 0xff; if (!lkh) continue; @@ -406,14 +407,14 @@ void ha_thread_dump_one(struct buffer *buf, int is_caller) done = 0; for (lbl = 0; lbl < LOCK_LABELS; lbl++) { /* find the latest occurrence of each label */ - for (lkl = 0; lkl < 8; lkl++) { + for (lkl = 0; lkl < slots; lkl++) { lkh = (th_ctx->lock_history >> (lkl * 8)) & 0xff; if (!lkh) continue; if ((lkh >> 2) == lbl) break; } - if (lkl == 8) // not found + if (lkl == slots) // not found continue; if ((lkh & 3) == _LK_UN) continue;