[Bug 287829] lldb prints the wrong value of errno in multi-threaded processes

From: <bugzilla-noreply_at_freebsd.org>
Date: Thu, 26 Jun 2025 11:12:46 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=287829

            Bug ID: 287829
           Summary: lldb prints the wrong value of errno in multi-threaded
                    processes
           Product: Base System
           Version: 14.2-RELEASE
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: bin
          Assignee: bugs@FreeBSD.org
          Reporter: becker.greg@att.net
 Attachment #261631 text/plain
         mime type:

Created attachment 261631
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=261631&action=edit
Simple C program to reproduce the problem

lldb does not print the value of errno correctly in multi-threaded processes,
and behavior differs between branches (releng/14.2, stable/14, main).

The primary problem is that 'p errno' seems to print thread 1's errno and not
the errno for the thread that lldb is currently looking at (say via the t
command or otherwise stopped in a particular thread).

With 14.2-RELEASE one can run 'p *(int *)__error()' to get the correct value,
but this no longer works reliably with stable/14, and does not work at all with
main/15.

Additionally, one cannot print the value of a thread-local variable as lldb
says "no TLS data currently exists for this thread".  This problem looks
somewhat similar to https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=241773.

Here is a walk through of the problem with the attached reproducer:


branch releng/14.2 (4.2-RELEASE-p3)

$ lldb a.out
(lldb) target create "a.out"
Current executable set to '/home/greg/a.out' (x86_64).
(lldb) r
Process 405 launched: '/home/greg/a.out' (x86_64)
main: gvar 8, tlvar 6, errno 3
ptstart: 1: gvar 8, tlvar 5, errno 0
ptstart: 2: gvar 8, tlvar 5, errno 14

Process 405 stopped
* thread #2, name = 'a.out', stop reason = signal SIGABRT
    frame #0: 0x00000008219bf1ba libc.so.7`__sys_thr_kill + 10
libc.so.7`__sys_thr_kill:
->  0x8219bf1ba <+10>: jb     0x8219bd318
    0x8219bf1c0 <+16>: retq   
    0x8219bf1c1:       int3   
    0x8219bf1c2:       int3   

(lldb) bt
* thread #2, name = 'a.out', stop reason = signal SIGABRT
  * frame #0: 0x00000008219bf1ba libc.so.7`__sys_thr_kill + 10
    frame #1: 0x00000008219385d4 libc.so.7`__raise + 52
    frame #2: 0x00000008219ebb59 libc.so.7`abort + 73
    frame #3: 0x00000000002018b4 a.out`ptstart(arg=0x0000000000000000) at
x.c:16:5
    frame #4: 0x0000000823156b05 libthr.so.3`___lldb_unnamed_symbol565 + 309

(lldb) f 3
frame #3: 0x00000000002018b4 a.out`ptstart(arg=0x0000000000000000) at x.c:16:5
   13       printf("%s: gvar %d, tlvar %d, errno %d\n", __func__, gvar, tlvar,
errno);
   14   
   15       errno = 3;
-> 16       abort();
   17   
   18       pthread_exit(NULL);
   19   }

(lldb) p tlvar
error: Couldn't materialize: couldn't get the value of variable tlvar: No TLS
data currently exists for this thread.
error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression

(lldb) p errno
(void *) 0x0000000000000002  <-- wrong, thread 1's errno

(lldb) p *(int *)__error()
(int) 14                     <-- correct

---

branch stable/14 bf73594fe0bd3d56b1035478cbbbdf58c05fe80e
branch stable/14 fad4064226b2aa3de6a6c83adb7e0e0108e69bd3

$ lldb a.out
(lldb) target create "a.out"
Current executable set to '/home/greg/a.out' (x86_64).
(lldb) r
Process 7525 launched: '/home/greg/a.out' (x86_64)
main: gvar 8, tlvar 6, errno 3
ptstart: 1: gvar 8, tlvar 5, errno 0
ptstart: 2: gvar 8, tlvar 5, errno 14

Process 7525 stopped
* thread #2, name = 'a.out', stop reason = signal SIGABRT
    frame #0: 0x0000000821dc54ca libc.so.7`__sys_thr_kill at thr_kill.S:4
   1    /* @generated by libc/sys/Makefile.inc */
   2    #include "compat.h"
   3    #include "SYS.h"
-> 4    RSYSCALL(thr_kill)
   5            .section .note.GNU-stack,"",%progbits

(lldb) bt
* thread #2, name = 'a.out', stop reason = signal SIGABRT
  * frame #0: 0x0000000821dc54ca libc.so.7`__sys_thr_kill at thr_kill.S:4
    frame #1: 0x0000000821d3c444 libc.so.7`__raise(s=6) at raise.c:50:10
    frame #2: 0x0000000821df1f79 libc.so.7`abort at abort.c:64:8
    frame #3: 0x00000000002018d4 a.out`ptstart(arg=0x0000000000000000) at
x.c:16:5
    frame #4: 0x0000000822a72c72
libthr.so.3`thread_start(curthread=0x0000322e9cc21810) at thr_create.c:289:16

(lldb) f 3
frame #3: 0x00000000002018d4 a.out`ptstart(arg=0x0000000000000000) at x.c:16:5
   13       printf("%s: gvar %d, tlvar %d, errno %d\n", __func__, gvar, tlvar,
errno);
   14   
   15       errno = 3;
-> 16       abort();
   17   
   18       pthread_exit(NULL);
   19   }

(lldb) p tlvar
error: Couldn't materialize: couldn't get the value of variable tlvar: no TLS
data currently exists for this thread
error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression

(lldb) p errno              <-- wrong, thread 1's errno
(int) 2

(lldb) p *(int *)__error()
(int) 0                     <-- wrong, just plain wrong


Interestinly, if I rerun the test and do not run the bt and f commands
and just try to print errno right away I get the following:

(lldb) p errno              <-- wrong, thread 1's errno
(int) 2

(lldb) p *(int *)__error()  <-- correct
(int) 14

---

branch main d86c5811cdb384b3ba565187f8dc7e7e51b6466e

 cc -Wall -O0 -g3 x.c -lpthread

$ lldb a.out
(lldb) target create "a.out"
Current executable set to '/home/greg/a.out' (x86_64).
(lldb) r
Process 17454 launched: '/home/greg/a.out' (x86_64)
main: gvar 8, tlvar 6, errno 0
ptstart: 1: gvar 8, tlvar 5, errno 0
ptstart: 2: gvar 8, tlvar 5, errno 14

Process 17454 stopped
* thread #2, name = 'a.out', stop reason = signal SIGABRT
    frame #0: 0x000000082326595a libsys.so.7`__sys_thr_kill at thr_kill.S:4
   1    /* @generated by libc/sys/Makefile.inc */
   2    #include "compat.h"
   3    #include "SYS.h"
-> 4    RSYSCALL(thr_kill)
   5            .section .note.GNU-stack,"",%progbits

(lldb) bt
* thread #2, name = 'a.out', stop reason = signal SIGABRT
  * frame #0: 0x000000082326595a libsys.so.7`__sys_thr_kill at thr_kill.S:4
    frame #1: 0x0000000822e1b734 libc.so.7`__raise(s=6) at raise.c:48:10
    frame #2: 0x0000000822ed0589 libc.so.7`abort at abort.c:61:8
    frame #3: 0x0000000000201824 a.out`ptstart(arg=0x0000000000000000) at
x.c:16:5
    frame #4: 0x0000000822d19f4b
libthr.so.3`thread_start(curthread=0x00003da43d043810) at thr_create.c:299:16

(lldb) f 3
frame #3: 0x0000000000201824 a.out`ptstart(arg=0x0000000000000000) at x.c:16:5
   13       printf("%s: gvar %d, tlvar %d, errno %d\n", __func__, gvar, tlvar,
errno);
   14   
   15       errno = 3;
-> 16       abort();
   17   
   18       pthread_exit(NULL);
   19   }

(lldb) p tlvar
error: Couldn't materialize: couldn't get the value of variable tlvar: no TLS
data currently exists for this thread
error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression

(lldb) p errno
(void *) 0x0016e39000000002    <-- wrong, but lower bits look like thread 1's
errno

(lldb) p *(int *)__error()     <-- wrong, thread 1's errno
(int) 2

-- 
You are receiving this mail because:
You are the assignee for the bug.