]>
Commit | Line | Data |
---|---|---|
bb330e25 AF |
1 | # |
2 | # Based on this upstream commit: | |
3 | # | |
4 | # commit d8dd00805b8f3a011735d7a407097fb1c408d867 | |
5 | # Author: H.J. Lu <hjl.tools@gmail.com> | |
6 | # Date: Fri Nov 28 07:54:07 2014 -0800 | |
7 | # | |
8 | # Resize DTV if the current DTV isn't big enough | |
9 | # | |
10 | # This patch changes _dl_allocate_tls_init to resize DTV if the current DTV | |
11 | # isn't big enough. Tested on X86-64, x32 and ia32. | |
12 | # | |
13 | # [BZ #13862] | |
14 | # * elf/dl-tls.c: Include <atomic.h>. | |
15 | # (oom): Remove #ifdef SHARED/#endif. | |
16 | # (_dl_static_dtv, _dl_initial_dtv): Moved before ... | |
17 | # (_dl_resize_dtv): This. Extracted from _dl_update_slotinfo. | |
18 | # (_dl_allocate_tls_init): Resize DTV if the current DTV isn't | |
19 | # big enough. | |
20 | # (_dl_update_slotinfo): Call _dl_resize_dtv to resize DTV. | |
21 | # * nptl/Makefile (tests): Add tst-stack4. | |
22 | # (modules-names): Add tst-stack4mod. | |
23 | # ($(objpfx)tst-stack4): New. | |
24 | # (tst-stack4mod.sos): Likewise. | |
25 | # ($(objpfx)tst-stack4.out): Likewise. | |
26 | # ($(tst-stack4mod.sos)): Likewise. | |
27 | # (clean): Likewise. | |
28 | # * nptl/tst-stack4.c: New file. | |
29 | # * nptl/tst-stack4mod.c: Likewise. | |
30 | # | |
31 | diff -urN glibc-2.12-2-gc4ccff1/elf/dl-tls.c glibc-2.12-2-gc4ccff1.mod/elf/dl-tls.c | |
32 | --- glibc-2.12-2-gc4ccff1/elf/dl-tls.c 2015-02-18 14:15:28.078461873 -0500 | |
33 | +++ glibc-2.12-2-gc4ccff1.mod/elf/dl-tls.c 2015-02-18 14:38:37.630374771 -0500 | |
34 | @@ -24,6 +24,7 @@ | |
35 | #include <stdlib.h> | |
36 | #include <unistd.h> | |
37 | #include <sys/param.h> | |
38 | +#include <atomic.h> | |
39 | ||
40 | #include <tls.h> | |
41 | #include <dl-tls.h> | |
42 | @@ -35,14 +36,12 @@ | |
43 | ||
44 | ||
45 | /* Out-of-memory handler. */ | |
46 | -#ifdef SHARED | |
47 | static void | |
48 | __attribute__ ((__noreturn__)) | |
49 | oom (void) | |
50 | { | |
51 | _dl_fatal_printf ("cannot allocate memory for thread-local data: ABORT\n"); | |
52 | } | |
53 | -#endif | |
54 | ||
55 | ||
56 | size_t | |
57 | @@ -392,6 +391,52 @@ | |
58 | return result; | |
59 | } | |
60 | ||
61 | +static dtv_t * | |
62 | +_dl_resize_dtv (dtv_t *dtv) | |
63 | +{ | |
64 | + /* Resize the dtv. */ | |
65 | + dtv_t *newp; | |
66 | + /* Load GL(dl_tls_max_dtv_idx) atomically since it may be written to by | |
67 | + other threads concurrently. -- We don't have the required atomic | |
68 | + infrastructure to load dl_tls_max_dtv_idx atomically, but on all the | |
69 | + architectures we care about it should load atomically. If this had | |
70 | + an atomic_load_acquire we would still be missing the releases for | |
71 | + the writes. */ | |
72 | + size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS; | |
73 | + size_t oldsize = dtv[-1].counter; | |
74 | + | |
75 | +#if SHARED | |
76 | + if (dtv == GL(dl_initial_dtv)) | |
77 | + { | |
78 | + /* This is the initial dtv that was either statically allocated in | |
79 | + __libc_setup_tls or allocated during rtld startup using the | |
80 | + dl-minimal.c malloc instead of the real malloc. We can't free | |
81 | + it, we have to abandon the old storage. */ | |
82 | + | |
83 | + newp = malloc ((2 + newsize) * sizeof (dtv_t)); | |
84 | + if (newp == NULL) | |
85 | + oom (); | |
86 | + memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t)); | |
87 | + } | |
88 | + else | |
89 | +#endif | |
90 | + { | |
91 | + newp = realloc (&dtv[-1], | |
92 | + (2 + newsize) * sizeof (dtv_t)); | |
93 | + if (newp == NULL) | |
94 | + oom (); | |
95 | + } | |
96 | + | |
97 | + newp[0].counter = newsize; | |
98 | + | |
99 | + /* Clear the newly allocated part. */ | |
100 | + memset (newp + 2 + oldsize, '\0', | |
101 | + (newsize - oldsize) * sizeof (dtv_t)); | |
102 | + | |
103 | + /* Return the generation counter. */ | |
104 | + return &newp[1]; | |
105 | +} | |
106 | + | |
107 | ||
108 | void * | |
109 | internal_function | |
110 | @@ -406,6 +451,16 @@ | |
111 | size_t total = 0; | |
112 | size_t maxgen = 0; | |
113 | ||
114 | + /* Check if the current dtv is big enough. */ | |
115 | + if (dtv[-1].counter < GL(dl_tls_max_dtv_idx)) | |
116 | + { | |
117 | + /* Resize the dtv. */ | |
118 | + dtv = _dl_resize_dtv (dtv); | |
119 | + | |
120 | + /* Install this new dtv in the thread data structures. */ | |
121 | + INSTALL_DTV (result, &dtv[-1]); | |
122 | + } | |
123 | + | |
124 | /* We have to prepare the dtv for all currently loaded modules using | |
125 | TLS. For those which are dynamically loaded we add the values | |
126 | indicating deferred allocation. */ | |
127 | @@ -637,41 +692,10 @@ | |
128 | assert (total + cnt == modid); | |
129 | if (dtv[-1].counter < modid) | |
130 | { | |
131 | - /* Reallocate the dtv. */ | |
132 | - dtv_t *newp; | |
133 | - size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS; | |
134 | - size_t oldsize = dtv[-1].counter; | |
135 | - | |
136 | - assert (map->l_tls_modid <= newsize); | |
137 | - | |
138 | - if (dtv == GL(dl_initial_dtv)) | |
139 | - { | |
140 | - /* This is the initial dtv that was allocated | |
141 | - during rtld startup using the dl-minimal.c | |
142 | - malloc instead of the real malloc. We can't | |
143 | - free it, we have to abandon the old storage. */ | |
144 | - | |
145 | - newp = malloc ((2 + newsize) * sizeof (dtv_t)); | |
146 | - if (newp == NULL) | |
147 | - oom (); | |
148 | - memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t)); | |
149 | - } | |
150 | - else | |
151 | - { | |
152 | - newp = realloc (&dtv[-1], | |
153 | - (2 + newsize) * sizeof (dtv_t)); | |
154 | - if (newp == NULL) | |
155 | - oom (); | |
156 | - } | |
157 | - | |
158 | - newp[0].counter = newsize; | |
159 | - | |
160 | - /* Clear the newly allocated part. */ | |
161 | - memset (newp + 2 + oldsize, '\0', | |
162 | - (newsize - oldsize) * sizeof (dtv_t)); | |
163 | + /* Resize the dtv. */ | |
164 | + dtv = _dl_resize_dtv (dtv); | |
165 | ||
166 | - /* Point dtv to the generation counter. */ | |
167 | - dtv = &newp[1]; | |
168 | + assert (modid <= dtv[-1].counter); | |
169 | ||
170 | /* Install this new dtv in the thread data | |
171 | structures. */ | |
172 | diff -urN glibc-2.12-2-gc4ccff1/nptl/Makefile glibc-2.12-2-gc4ccff1.mod/nptl/Makefile | |
173 | --- glibc-2.12-2-gc4ccff1/nptl/Makefile 2015-02-18 14:15:28.073462028 -0500 | |
174 | +++ glibc-2.12-2-gc4ccff1.mod/nptl/Makefile 2015-02-18 14:15:49.817786667 -0500 | |
175 | @@ -245,7 +245,7 @@ | |
176 | tst-exec1 tst-exec2 tst-exec3 tst-exec4 \ | |
177 | tst-exit1 tst-exit2 tst-exit3 \ | |
178 | tst-stdio1 tst-stdio2 \ | |
179 | - tst-stack1 tst-stack2 tst-stack3 \ | |
180 | + tst-stack1 tst-stack2 tst-stack3 tst-stack4 \ | |
181 | tst-unload \ | |
182 | tst-dlsym1 \ | |
183 | tst-sysconf \ | |
184 | @@ -304,7 +304,7 @@ | |
185 | ||
186 | modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \ | |
187 | tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \ | |
188 | - tst-tls5modd tst-tls5mode tst-tls5modf \ | |
189 | + tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \ | |
190 | tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod | |
191 | extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) tst-cleanup4aux.o | |
192 | test-extras += $(modules-names) | |
193 | @@ -459,6 +459,19 @@ | |
194 | $(common-objpfx)malloc/mtrace $(objpfx)tst-stack3.mtrace > $@ | |
195 | generated += tst-stack3-mem tst-stack3.mtrace | |
196 | ||
197 | +$(objpfx)tst-stack4: $(libdl) $(shared-thread-library) | |
198 | +tst-stack4mod.sos=$(shell for i in 0 1 2 3 4 5 6 7 8 9 10 \ | |
199 | + 11 12 13 14 15 16 17 18 19; do \ | |
200 | + for j in 0 1 2 3 4 5 6 7 8 9 10 \ | |
201 | + 11 12 13 14 15 16 17 18 19; do \ | |
202 | + echo $(objpfx)tst-stack4mod-$$i-$$j.so; \ | |
203 | + done; done) | |
204 | +$(objpfx)tst-stack4.out: $(tst-stack4mod.sos) | |
205 | +$(tst-stack4mod.sos): $(objpfx)tst-stack4mod.so | |
206 | + cp -f $< $@ | |
207 | +clean: | |
208 | + rm -f $(tst-stack4mod.sos) | |
209 | + | |
210 | $(objpfx)tst-cleanup4: $(objpfx)tst-cleanup4aux.o $(shared-thread-library) | |
211 | $(objpfx)tst-cleanupx4: $(objpfx)tst-cleanup4aux.o $(shared-thread-library) | |
212 | ||
213 | diff -urN glibc-2.12-2-gc4ccff1/nptl/tst-stack4.c glibc-2.12-2-gc4ccff1.mod/nptl/tst-stack4.c | |
214 | --- glibc-2.12-2-gc4ccff1/nptl/tst-stack4.c 1969-12-31 19:00:00.000000000 -0500 | |
215 | +++ glibc-2.12-2-gc4ccff1.mod/nptl/tst-stack4.c 2015-02-18 14:15:49.817786667 -0500 | |
216 | @@ -0,0 +1,159 @@ | |
217 | +/* Test DTV size oveflow when pthread_create reuses old DTV and TLS is | |
218 | + used by dlopened shared object. | |
219 | + Copyright (C) 2014 Free Software Foundation, Inc. | |
220 | + This file is part of the GNU C Library. | |
221 | + | |
222 | + The GNU C Library is free software; you can redistribute it and/or | |
223 | + modify it under the terms of the GNU Lesser General Public | |
224 | + License as published by the Free Software Foundation; either | |
225 | + version 2.1 of the License, or (at your option) any later version. | |
226 | + | |
227 | + The GNU C Library is distributed in the hope that it will be useful, | |
228 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
229 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
230 | + Lesser General Public License for more details. | |
231 | + | |
232 | + You should have received a copy of the GNU Lesser General Public | |
233 | + License along with the GNU C Library; if not, see | |
234 | + <http://www.gnu.org/licenses/>. */ | |
235 | + | |
236 | +#include <stdio.h> | |
237 | +#include <stdint.h> | |
238 | +#include <dlfcn.h> | |
239 | +#include <assert.h> | |
240 | +#include <pthread.h> | |
241 | + | |
242 | +/* The choices of thread count, and file counts are arbitary. | |
243 | + The point is simply to run enough threads that an exiting | |
244 | + thread has it's stack reused by another thread at the same | |
245 | + time as new libraries have been loaded. */ | |
246 | +#define DSO_SHARED_FILES 20 | |
247 | +#define DSO_OPEN_THREADS 20 | |
248 | +#define DSO_EXEC_THREADS 2 | |
249 | + | |
250 | +/* Used to make sure that only one thread is calling dlopen and dlclose | |
251 | + at a time. */ | |
252 | +pthread_mutex_t g_lock; | |
253 | + | |
254 | +typedef void (*function) (void); | |
255 | + | |
256 | +void * | |
257 | +dso_invoke(void *dso_fun) | |
258 | +{ | |
259 | + function *fun_vec = (function *) dso_fun; | |
260 | + int dso; | |
261 | + | |
262 | + for (dso = 0; dso < DSO_SHARED_FILES; dso++) | |
263 | + (*fun_vec[dso]) (); | |
264 | + | |
265 | + pthread_exit (NULL); | |
266 | +} | |
267 | + | |
268 | +void * | |
269 | +dso_process (void * p) | |
270 | +{ | |
271 | + void *handle[DSO_SHARED_FILES]; | |
272 | + function fun_vec[DSO_SHARED_FILES]; | |
273 | + char dso_path[DSO_SHARED_FILES][100]; | |
274 | + int dso; | |
275 | + uintptr_t t = (uintptr_t) p; | |
276 | + | |
277 | + /* Open DSOs and get a function. */ | |
278 | + for (dso = 0; dso < DSO_SHARED_FILES; dso++) | |
279 | + { | |
280 | + sprintf (dso_path[dso], "tst-stack4mod-%i-%i.so", t, dso); | |
281 | + | |
282 | + pthread_mutex_lock (&g_lock); | |
283 | + | |
284 | + handle[dso] = dlopen (dso_path[dso], RTLD_NOW); | |
285 | + assert (handle[dso]); | |
286 | + | |
287 | + fun_vec[dso] = (function) dlsym (handle[dso], "function"); | |
288 | + assert (fun_vec[dso]); | |
289 | + | |
290 | + pthread_mutex_unlock (&g_lock); | |
291 | + } | |
292 | + | |
293 | + /* Spawn workers. */ | |
294 | + pthread_t thread[DSO_EXEC_THREADS]; | |
295 | + int i, ret; | |
296 | + uintptr_t result = 0; | |
297 | + for (i = 0; i < DSO_EXEC_THREADS; i++) | |
298 | + { | |
299 | + pthread_mutex_lock (&g_lock); | |
300 | + ret = pthread_create (&thread[i], NULL, dso_invoke, (void *) fun_vec); | |
301 | + if (ret != 0) | |
302 | + { | |
303 | + printf ("pthread_create failed: %d\n", ret); | |
304 | + result = 1; | |
305 | + } | |
306 | + pthread_mutex_unlock (&g_lock); | |
307 | + } | |
308 | + | |
309 | + if (!result) | |
310 | + for (i = 0; i < DSO_EXEC_THREADS; i++) | |
311 | + { | |
312 | + ret = pthread_join (thread[i], NULL); | |
313 | + if (ret != 0) | |
314 | + { | |
315 | + printf ("pthread_join failed: %d\n", ret); | |
316 | + result = 1; | |
317 | + } | |
318 | + } | |
319 | + | |
320 | + /* Close all DSOs. */ | |
321 | + for (dso = 0; dso < DSO_SHARED_FILES; dso++) | |
322 | + { | |
323 | + pthread_mutex_lock (&g_lock); | |
324 | + dlclose (handle[dso]); | |
325 | + pthread_mutex_unlock (&g_lock); | |
326 | + } | |
327 | + | |
328 | + /* Exit. */ | |
329 | + pthread_exit ((void *) result); | |
330 | +} | |
331 | + | |
332 | +static int | |
333 | +do_test (void) | |
334 | +{ | |
335 | + pthread_t thread[DSO_OPEN_THREADS]; | |
336 | + int i,j; | |
337 | + int ret; | |
338 | + int result = 0; | |
339 | + | |
340 | + pthread_mutex_init (&g_lock, NULL); | |
341 | + | |
342 | + /* 100 is arbitrary here and is known to trigger PR 13862. */ | |
343 | + for (j = 0; j < 100; j++) | |
344 | + { | |
345 | + for (i = 0; i < DSO_OPEN_THREADS; i++) | |
346 | + { | |
347 | + ret = pthread_create (&thread[i], NULL, dso_process, | |
348 | + (void *) (uintptr_t) i); | |
349 | + if (ret != 0) | |
350 | + { | |
351 | + printf ("pthread_create failed: %d\n", ret); | |
352 | + result = 1; | |
353 | + } | |
354 | + } | |
355 | + | |
356 | + if (result) | |
357 | + break; | |
358 | + | |
359 | + for (i = 0; i < DSO_OPEN_THREADS; i++) | |
360 | + { | |
361 | + ret = pthread_join (thread[i], NULL); | |
362 | + if (ret != 0) | |
363 | + { | |
364 | + printf ("pthread_join failed: %d\n", ret); | |
365 | + result = 1; | |
366 | + } | |
367 | + } | |
368 | + } | |
369 | + | |
370 | + return result; | |
371 | +} | |
372 | + | |
373 | +#define TEST_FUNCTION do_test () | |
374 | +#define TIMEOUT 100 | |
375 | +#include "../test-skeleton.c" | |
376 | diff -urN glibc-2.12-2-gc4ccff1/nptl/tst-stack4mod.c glibc-2.12-2-gc4ccff1.mod/nptl/tst-stack4mod.c | |
377 | --- glibc-2.12-2-gc4ccff1/nptl/tst-stack4mod.c 1969-12-31 19:00:00.000000000 -0500 | |
378 | +++ glibc-2.12-2-gc4ccff1.mod/nptl/tst-stack4mod.c 2015-02-18 14:15:49.817786667 -0500 | |
379 | @@ -0,0 +1,28 @@ | |
380 | +/* This tests DTV usage with TLS in dlopened shared object. | |
381 | + Copyright (C) 2014 Free Software Foundation, Inc. | |
382 | + This file is part of the GNU C Library. | |
383 | + | |
384 | + The GNU C Library is free software; you can redistribute it and/or | |
385 | + modify it under the terms of the GNU Lesser General Public | |
386 | + License as published by the Free Software Foundation; either | |
387 | + version 2.1 of the License, or (at your option) any later version. | |
388 | + | |
389 | + The GNU C Library is distributed in the hope that it will be useful, | |
390 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
391 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
392 | + Lesser General Public License for more details. | |
393 | + | |
394 | + You should have received a copy of the GNU Lesser General Public | |
395 | + License along with the GNU C Library; if not, see | |
396 | + <http://www.gnu.org/licenses/>. */ | |
397 | + | |
398 | +/* 256 is arbitrary here and is known to trigger PR 13862. */ | |
399 | +__thread int var[256] attribute_hidden = {0}; | |
400 | + | |
401 | +void | |
402 | +function (void) | |
403 | +{ | |
404 | + int i; | |
405 | + for (i = 0; i < sizeof (var) / sizeof (int); i++) | |
406 | + var[i] = i; | |
407 | +} |