]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: threads: don't read lock history entries that don't fit in ulong
authorOlivier Houchard <ohouchard@haproxy.com>
Thu, 12 Nov 2026 11:58:20 +0000 (12:58 +0100)
committerOlivier Houchard <cognet@ci0.org>
Thu, 12 Nov 2026 16:30:41 +0000 (17:30 +0100)
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.

src/debug.c

index 69c1383b69b4a92fca98bcd583160af491b6e69b..553ffe2d4f21cd514ae0f6a05b7e0f47bf5dafb0 100644 (file)
@@ -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;