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
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Sep 14 02:10:10 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator:     Thinker K.F. Li
>Release:        FreeBSD 9.0-CURRENT i386
>Organization:
Allwitz Tech.
>Environment:
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


	
>Description:
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.

	
>How-To-Repeat:
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;

void
modify(void) {
    var = 100;
}

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

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

int
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");

    modify();
    show();

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

	
>Fix:

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 @@
 	free(dtv);
 	lock_release(rtld_bind_lock, &lockstate);
 	*dtvp = newdtv;
+	dtv = newdtv;
     }
 
     /* Dynamically allocate module TLS if necessary */
--- libexec-rtld_elf-rtld.c.diff ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list