Module Name:    src
Committed By:   joerg
Date:           Thu Jul 13 14:10:38 UTC 2017

Modified Files:
        src/libexec/ld.elf_so: tls.c

Log Message:
Fix two bugs related to promotion of DSO TLS blocks into the static
thread allocation:
(1) Set the DTV vector up whenever an offset into the static allocation
is assigned, even if the block itself is not initialized. This has been
seen in libstdc++.
(2) Do not free a DTV block if it is part of the static thread
allocation.


To generate a diff of this commit:
cvs rdiff -u -r1.10 -r1.11 src/libexec/ld.elf_so/tls.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/libexec/ld.elf_so/tls.c
diff -u src/libexec/ld.elf_so/tls.c:1.10 src/libexec/ld.elf_so/tls.c:1.11
--- src/libexec/ld.elf_so/tls.c:1.10	Sun Dec 14 23:49:17 2014
+++ src/libexec/ld.elf_so/tls.c	Thu Jul 13 14:10:38 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: tls.c,v 1.10 2014/12/14 23:49:17 chs Exp $	*/
+/*	$NetBSD: tls.c,v 1.11 2017/07/13 14:10:38 joerg Exp $	*/
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: tls.c,v 1.10 2014/12/14 23:49:17 chs Exp $");
+__RCSID("$NetBSD: tls.c,v 1.11 2017/07/13 14:10:38 joerg Exp $");
 
 #include <sys/param.h>
 #include <sys/ucontext.h>
@@ -134,7 +134,7 @@ _rtld_tls_allocate_locked(void)
 	SET_DTV_GENERATION(tcb->tcb_dtv, _rtld_tls_dtv_generation);
 
 	for (obj = _rtld_objlist; obj != NULL; obj = obj->next) {
-		if (obj->tlsinitsize && obj->tls_done) {
+		if (obj->tls_done) {
 #ifdef __HAVE_TLS_VARIANT_I
 			q = p + obj->tlsoffset;
 #else
@@ -142,7 +142,8 @@ _rtld_tls_allocate_locked(void)
 #endif
 			dbg(("obj %p dtv %p tlsoffset %zu",
 			    obj, q, obj->tlsoffset));
-			memcpy(q, obj->tlsinit, obj->tlsinitsize);
+			if (obj->tlsinitsize)
+				memcpy(q, obj->tlsinit, obj->tlsinitsize);
 			tcb->tcb_dtv[obj->tlsindex] = q;
 		}
 	}
@@ -167,21 +168,25 @@ void
 _rtld_tls_free(struct tls_tcb *tcb)
 {
 	size_t i, max_index;
-	uint8_t *p;
+	uint8_t *p, *p_end;
 	sigset_t mask;
 
 	_rtld_exclusive_enter(&mask);
 
-	max_index = DTV_MAX_INDEX(tcb->tcb_dtv);
-	for (i = 1; i <= max_index; ++i)
-		xfree(tcb->tcb_dtv[i]);
-	xfree(tcb->tcb_dtv - 1);
-
 #ifdef __HAVE_TLS_VARIANT_I
 	p = (uint8_t *)tcb;
 #else
 	p = (uint8_t *)tcb - _rtld_tls_static_space;
 #endif
+	p_end = p + _rtld_tls_static_space;
+
+	max_index = DTV_MAX_INDEX(tcb->tcb_dtv);
+	for (i = 1; i <= max_index; ++i) {
+		if ((uint8_t *)tcb->tcb_dtv[i] < p ||
+		    (uint8_t *)tcb->tcb_dtv[i] >= p_end)
+			xfree(tcb->tcb_dtv[i]);
+	}
+	xfree(tcb->tcb_dtv - 1);
 	xfree(p);
 
 	_rtld_exclusive_exit(&mask);

Reply via email to