misc/160721: TLS is inconsistent

Thinker K.F. Li thinker at codemud.net
Wed Sep 14 02:10:11 UTC 2011

>Number:         160721
>Category:       misc
>Synopsis:       TLS is inconsistent
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Sep 14 02:10:10 UTC 2011
>Originator:     Thinker K.F. Li
>Release:        FreeBSD 9.0-CURRENT i386
Allwitz Tech.
System: FreeBSD eeebox.branda.to 9.0-CURRENT FreeBSD 9.0-CURRENT #1: Sun Jun 5 17:08:32 CST 2011 thinker at eeebox.branda.to:/usr/src/sys/i386/compile/eeebox i386

Compiler generated code will call ___tls_get_addr() of ld-elf.so
for TLS variable.  It is supposed to return the same address, every time,
for the same passed address and thread, but it does not.

Compile following code with commands

 1. cc -shared -o test-tls-1.so -pthread -fpic test-tls-1.c
 2. cc -o test-tls -pthread test-tls.c

test-tls is supposed to print "100" on stdout, but it print out "50",
instead.  If you dig into opcodes, you will find that ___tls_get_addr()
return two different base addresses for modify() and for show() respective.
This issue is only making troubles for programs accessing TLS after dlopen().

--- test-tls-1.c begins here ---
#include <stdio.h>

__thread int var = 50;

modify(void) {
    var = 100;

show(void) {
    printf("%d\n", var);
--- test-tls-1.c ends here ---

--- test-tls.c begins here ---
#include <stdio.h>
#include <dlfcn.h>

main(int argc, char * const *argv) {
    void (*modify)(void);
    void (*modify)(void);
    void *sohdl;

    sohdl = dlopen("./test-tls-1.so", RTLD_NOW);
    modify = (void (*)(void))dlsym(sohdl, "modify");
    show = (void (*)(void))dlsym(sohdl, "show");


    return 0;
--- test-tls.c ends here ---


Apply following patch on the root of source tree can fix this issue.


--- libexec-rtld_elf-rtld.c.diff begins here ---
--- libexec/rtld-elf/rtld.c.orig	2011-09-13 14:25:17.000000000 +0800
+++ libexec/rtld-elf/rtld.c	2011-09-13 14:25:43.000000000 +0800
@@ -3371,6 +3371,7 @@
 	lock_release(rtld_bind_lock, &lockstate);
 	*dtvp = newdtv;
+	dtv = newdtv;
     /* Dynamically allocate module TLS if necessary */
--- libexec-rtld_elf-rtld.c.diff ends here ---


More information about the freebsd-bugs mailing list