Bug#964141: libc6: "cannot allocate memory in static TLS block" with some library combinations on arm64
control: tags -1 patch
Hello, the patch (v5) applied on top of 2.31 (build-tested in Ubuntu) seems to solve the issue:
diff -Nru glibc-2.31/debian/changelog glibc-2.31/debian/changelog
--- glibc-2.31/debian/changelog 2020-06-11 09:53:48.000000000 +0000
+++ glibc-2.31/debian/changelog 2020-07-03 10:21:12.000000000 +0000
@@ -1,3 +1,9 @@
+glibc (2.31-0ubuntu11) groovy; urgency=medium
+
+ * Fix arm64 sadness on pyside2
+
+ -- Gianfranco Costamagna <locutusofborg@debian.org> Fri, 03 Jul 2020 11:45:47 +0200
+
glibc (2.31-0ubuntu10) groovy; urgency=medium
* Copy the fully conditionalized x86 variant for math-vector-fortran.h
diff -Nru glibc-2.31/debian/patches/arm64-fix-2.patch glibc-2.31/debian/patches/arm64-fix-2.patch
--- glibc-2.31/debian/patches/arm64-fix-2.patch 1970-01-01 00:00:00.000000000 +0000
+++ glibc-2.31/debian/patches/arm64-fix-2.patch 2020-07-03 10:21:10.000000000 +0000
@@ -0,0 +1,606 @@
+Origin: http://51.15.138.76/patch/37618/
+
+diff --git a/csu/libc-tls.c b/csu/libc-tls.c
+index e2603157e8..fb77cd94fa 100644
+--- a/csu/libc-tls.c
++++ b/csu/libc-tls.c
+@@ -56,6 +56,9 @@ size_t _dl_tls_static_align;
+ loaded modules with IE-model TLS or for TLSDESC optimization.
+ See comments in elf/dl-tls.c where it is initialized. */
+ size_t _dl_tls_static_surplus;
++/* Remaining amount of static TLS that may be used for optimizing
++ dynamic TLS access (e.g. with TLSDESC). */
++size_t _dl_tls_static_optional;
+
+ /* Generation counter for the dtv. */
+ size_t _dl_tls_generation;
+diff --git a/elf/Makefile b/elf/Makefile
+index 6fe1df90bb..5fadaec27c 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -201,7 +201,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+ tst-unwind-ctor tst-unwind-main tst-audit13 \
+ tst-sonamemove-link tst-sonamemove-dlopen tst-dlopen-tlsmodid \
+ tst-dlopen-self tst-auditmany tst-initfinilazyfail tst-dlopenfail \
+- tst-dlopenfail-2
++ tst-dlopenfail-2 tst-tls-ie tst-tls-ie-dlmopen
+ # reldep9
+ tests-internal += loadtest unload unload2 circleload1 \
+ neededtest neededtest2 neededtest3 neededtest4 \
+@@ -312,7 +312,11 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ tst-auditmanymod7 tst-auditmanymod8 tst-auditmanymod9 \
+ tst-initlazyfailmod tst-finilazyfailmod \
+ tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \
+- tst-dlopenfailmod3 tst-ldconfig-ld-mod
++ tst-dlopenfailmod3 tst-ldconfig-ld-mod \
++ tst-tls-ie-mod0 tst-tls-ie-mod1 tst-tls-ie-mod2 \
++ tst-tls-ie-mod3 tst-tls-ie-mod4 tst-tls-ie-mod5 \
++ tst-tls-ie-mod6
++
+ # Most modules build with _ISOMAC defined, but those filtered out
+ # depend on internal headers.
+ modules-names-tests = $(filter-out ifuncmod% tst-libc_dlvsym-dso tst-tlsmod%,\
+@@ -1699,3 +1702,23 @@ $(objpfx)tst-auxobj: $(objpfx)tst-filterobj-aux.so
+
+ $(objpfx)tst-ldconfig-ld_so_conf-update.out: $(objpfx)tst-ldconfig-ld-mod.so
+ $(objpfx)tst-ldconfig-ld_so_conf-update: $(libdl)
++
++$(objpfx)tst-tls-ie: $(libdl) $(shared-thread-library)
++$(objpfx)tst-tls-ie.out: \
++ $(objpfx)tst-tls-ie-mod0.so \
++ $(objpfx)tst-tls-ie-mod1.so \
++ $(objpfx)tst-tls-ie-mod2.so \
++ $(objpfx)tst-tls-ie-mod3.so \
++ $(objpfx)tst-tls-ie-mod4.so \
++ $(objpfx)tst-tls-ie-mod5.so \
++ $(objpfx)tst-tls-ie-mod6.so
++
++$(objpfx)tst-tls-ie-dlmopen: $(libdl) $(shared-thread-library)
++$(objpfx)tst-tls-ie-dlmopen.out: \
++ $(objpfx)tst-tls-ie-mod0.so \
++ $(objpfx)tst-tls-ie-mod1.so \
++ $(objpfx)tst-tls-ie-mod2.so \
++ $(objpfx)tst-tls-ie-mod3.so \
++ $(objpfx)tst-tls-ie-mod4.so \
++ $(objpfx)tst-tls-ie-mod5.so \
++ $(objpfx)tst-tls-ie-mod6.so
+diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
+index ffcc84d396..6d32e49467 100644
+--- a/elf/dl-reloc.c
++++ b/elf/dl-reloc.c
+@@ -39,13 +39,16 @@
+ /* We are trying to perform a static TLS relocation in MAP, but it was
+ dynamically loaded. This can only work if there is enough surplus in
+ the static TLS area already allocated for each running thread. If this
+- object's TLS segment is too big to fit, we fail. If it fits,
+- we set MAP->l_tls_offset and return.
+- This function intentionally does not return any value but signals error
+- directly, as static TLS should be rare and code handling it should
+- not be inlined as much as possible. */
++ object's TLS segment is too big to fit, we fail with -1. If it fits,
++ we set MAP->l_tls_offset and return 0.
++ A portion of the surplus static TLS can be optionally used to optimize
++ dynamic TLS access (with TLSDESC or powerpc TLS optimizations).
++ If OPTIONAL is true then TLS is allocated for such optimization and
++ the caller must have a fallback in case the optional portion of surplus
++ TLS runs out. If OPTIONAL is false then the entire surplus TLS area is
++ considered and the allocation only fails if that runs out. */
+ int
+-_dl_try_allocate_static_tls (struct link_map *map)
++_dl_try_allocate_static_tls (struct link_map *map, bool optional)
+ {
+ /* If we've already used the variable with dynamic access, or if the
+ alignment requirements are too high, fail. */
+@@ -68,8 +71,14 @@ _dl_try_allocate_static_tls (struct link_map *map)
+
+ size_t n = (freebytes - blsize) / map->l_tls_align;
+
+- size_t offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align
+- - map->l_tls_firstbyte_offset);
++ /* Account optional static TLS surplus usage. */
++ size_t use = freebytes - n * map->l_tls_align - map->l_tls_firstbyte_offset;
++ if (optional && use > GL(dl_tls_static_optional))
++ goto fail;
++ else if (optional)
++ GL(dl_tls_static_optional) -= use;
++
++ size_t offset = GL(dl_tls_static_used) + use;
+
+ map->l_tls_offset = GL(dl_tls_static_used) = offset;
+ #elif TLS_DTV_AT_TP
+@@ -83,6 +92,13 @@ _dl_try_allocate_static_tls (struct link_map *map)
+ if (used > GL(dl_tls_static_size))
+ goto fail;
+
++ /* Account optional static TLS surplus usage. */
++ size_t use = used - GL(dl_tls_static_used);
++ if (optional && use > GL(dl_tls_static_optional))
++ goto fail;
++ else if (optional)
++ GL(dl_tls_static_optional) -= use;
++
+ map->l_tls_offset = offset;
+ map->l_tls_firstbyte_offset = GL(dl_tls_static_used);
+ GL(dl_tls_static_used) = used;
+@@ -110,12 +126,15 @@ _dl_try_allocate_static_tls (struct link_map *map)
+ return 0;
+ }
+
++/* This function intentionally does not return any value but signals error
++ directly, as static TLS should be rare and code handling it should
++ not be inlined as much as possible. */
+ void
+ __attribute_noinline__
+ _dl_allocate_static_tls (struct link_map *map)
+ {
+ if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
+- || _dl_try_allocate_static_tls (map))
++ || _dl_try_allocate_static_tls (map, false))
+ {
+ _dl_signal_error (0, map->l_name, NULL, N_("\
+ cannot allocate memory in static TLS block"));
+diff --git a/elf/dl-tls.c b/elf/dl-tls.c
+index 2201a1cc1d..af5db12d08 100644
+--- a/elf/dl-tls.c
++++ b/elf/dl-tls.c
+@@ -57,25 +57,26 @@
+ This should be large enough to cover runtime libraries of the
+ compiler such as libgomp and libraries in libc other than libc.so. */
+ #define OTHER_IE_TLS 144
+-/* Size of additional surplus TLS, placeholder for TLS optimizations. */
+-#define OPT_SURPLUS_TLS 512
+
+ void
+ _dl_tls_static_surplus_init (void)
+ {
+- size_t nns;
++ size_t nns, opt_tls;
+
+ #if HAVE_TUNABLES
+ nns = TUNABLE_GET (nns, size_t, NULL);
++ opt_tls = TUNABLE_GET (optional_static_tls, size_t, NULL);
+ #else
+ /* Default values of the tunables. */
+ nns = 4;
++ opt_tls = 512;
+ #endif
+ if (nns > DL_NNS)
+ nns = DL_NNS;
++ GL(dl_tls_static_optional) = opt_tls;
+ GLRO(dl_tls_static_surplus) = ((nns - 1) * LIBC_IE_TLS
+ + nns * OTHER_IE_TLS
+- + OPT_SURPLUS_TLS);
++ + opt_tls);
+ }
+
+ /* Out-of-memory handler. */
+diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
+index b07742d7b3..35634ef24d 100644
+--- a/elf/dl-tunables.list
++++ b/elf/dl-tunables.list
+@@ -134,5 +134,10 @@ glibc {
+ maxval: 16
+ default: 4
+ }
++ optional_static_tls {
++ type: SIZE_T
++ minval: 0
++ default: 512
++ }
+ }
+ }
+diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
+index bb7a66f4cd..6727233e1a 100644
+--- a/elf/dynamic-link.h
++++ b/elf/dynamic-link.h
+@@ -40,9 +40,10 @@
+ (__builtin_expect ((sym_map)->l_tls_offset \
+ != FORCED_DYNAMIC_TLS_OFFSET, 1) \
+ && (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET, 1) \
+- || _dl_try_allocate_static_tls (sym_map) == 0))
++ || _dl_try_allocate_static_tls (sym_map, true) == 0))
+
+-int _dl_try_allocate_static_tls (struct link_map *map) attribute_hidden;
++int _dl_try_allocate_static_tls (struct link_map *map, bool optional)
++ attribute_hidden;
+
+ #include <elf.h>
+
+diff --git a/elf/tst-tls-ie-dlmopen.c b/elf/tst-tls-ie-dlmopen.c
+new file mode 100644
+index 0000000000..0be47c7237
+--- /dev/null
++++ b/elf/tst-tls-ie-dlmopen.c
+@@ -0,0 +1,114 @@
++/* Test dlopen of modules with initial-exec TLS after dlmopen.
++ Copyright (C) 2016-2020 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <https://www.gnu.org/licenses/>. */
++
++/* This test tries to check that surplus static TLS is not used up for
++ dynamic TLS optimizations and 4*144 = 576 bytes of static TLS is
++ still available for dlopening modules with initial-exec TLS after 3
++ new dlmopen namespaces are created. It depends on rtld.nns=4 and
++ rtld.optional_static_tls=512 tunable settings. */
++
++#include <errno.h>
++#include <pthread.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++static int do_test (void);
++#include <support/xthread.h>
++#include <support/xdlfcn.h>
++#include <support/test-driver.c>
++
++/* Have some big TLS in the main exe: should not use surplus TLS. */
++__thread char maintls[1000];
++
++static pthread_barrier_t barrier;
++
++/* Forces multi-threaded behaviour. */
++static void *
++blocked_thread_func (void *closure)
++{
++ xpthread_barrier_wait (&barrier);
++ /* TLS load and access tests run here in the main thread. */
++ xpthread_barrier_wait (&barrier);
++ return NULL;
++}
++
++static void *
++load_and_access (Lmid_t lmid, const char *mod, const char *func)
++{
++ /* Load module with TLS. */
++ void *p = xdlmopen (lmid, mod, RTLD_NOW);
++ /* Access the TLS variable to ensure it is allocated. */
++ void (*f) (void) = (void (*) (void))xdlsym (p, func);
++ f ();
++ return p;
++}
++
++static int
++do_test (void)
++{
++ void *mods[5];
++
++ {
++ int ret = pthread_barrier_init (&barrier, NULL, 2);
++ if (ret != 0)
++ {
++ errno = ret;
++ printf ("error: pthread_barrier_init: %m\n");
++ exit (1);
++ }
++ }
++
++ pthread_t blocked_thread = xpthread_create (NULL, blocked_thread_func, NULL);
++ xpthread_barrier_wait (&barrier);
++
++ printf ("maintls[%zu]:\t %p .. %p\n",
++ sizeof maintls, maintls, maintls + sizeof maintls);
++ memset (maintls, 1, sizeof maintls);
++
++ /* Load modules with dynamic TLS (use surplus static TLS for libc
++ in new namespaces and may be for TLS optimizations too). */
++ mods[0] = load_and_access (LM_ID_BASE, "tst-tls-ie-mod0.so", "access0");
++ mods[1] = load_and_access (LM_ID_NEWLM, "tst-tls-ie-mod1.so", "access1");
++ mods[2] = load_and_access (LM_ID_NEWLM, "tst-tls-ie-mod2.so", "access2");
++ mods[3] = load_and_access (LM_ID_NEWLM, "tst-tls-ie-mod3.so", "access3");
++ /* Load modules with initial-exec TLS (can only use surplus static TLS). */
++ mods[4] = load_and_access (LM_ID_BASE, "tst-tls-ie-mod6.so", "access6");
++
++ /* Here 576 bytes + 3 * libc use of surplus static TLS is in use so less
++ than 1024 bytes are available (exact number depends on TLS optimizations
++ and the libc TLS use). */
++ printf ("The next dlmopen should fail...\n");
++ void *p = dlmopen (LM_ID_BASE, "tst-tls-ie-mod4.so", RTLD_NOW);
++ if (p != NULL)
++ {
++ printf ("error: expected dlmopen to fail because there is "
++ "not enough surplus static TLS.\n");
++ exit (1);
++ }
++ printf ("...OK failed with: %s.\n", dlerror ());
++
++ xpthread_barrier_wait (&barrier);
++ xpthread_join (blocked_thread);
++
++ /* Close the modules. */
++ for (int i = 0; i < 5; ++i)
++ xdlclose (mods[i]);
++
++ return 0;
++}
+diff --git a/elf/tst-tls-ie-mod.h b/elf/tst-tls-ie-mod.h
+new file mode 100644
+index 0000000000..46b362a9b7
+--- /dev/null
++++ b/elf/tst-tls-ie-mod.h
+@@ -0,0 +1,40 @@
++/* Module with specified TLS size and model.
++ Copyright (C) 2020 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <https://www.gnu.org/licenses/>. */
++
++/* This file is parameterized by macros N, SIZE and MODEL. */
++
++#include <stdio.h>
++#include <string.h>
++
++#define CONCATX(x, y) x ## y
++#define CONCAT(x, y) CONCATX (x, y)
++#define STRX(x) #x
++#define STR(x) STRX (x)
++
++#define VAR CONCAT (var, N)
++
++__attribute__ ((aligned (8), tls_model (MODEL)))
++__thread char VAR[SIZE];
++
++void
++CONCAT (access, N) (void)
++{
++ printf (STR (VAR) "[%d]:\t %p .. %p " MODEL "\n", SIZE, VAR, VAR + SIZE);
++ fflush (stdout);
++ memset (VAR, 1, SIZE);
++}
+diff --git a/elf/tst-tls-ie-mod0.c b/elf/tst-tls-ie-mod0.c
+new file mode 100644
+index 0000000000..2450686e40
+--- /dev/null
++++ b/elf/tst-tls-ie-mod0.c
+@@ -0,0 +1,4 @@
++#define N 0
++#define SIZE 480
++#define MODEL "global-dynamic"
++#include "tst-tls-ie-mod.h"
+diff --git a/elf/tst-tls-ie-mod1.c b/elf/tst-tls-ie-mod1.c
+new file mode 100644
+index 0000000000..849ff91e53
+--- /dev/null
++++ b/elf/tst-tls-ie-mod1.c
+@@ -0,0 +1,4 @@
++#define N 1
++#define SIZE 120
++#define MODEL "global-dynamic"
++#include "tst-tls-ie-mod.h"
+diff --git a/elf/tst-tls-ie-mod2.c b/elf/tst-tls-ie-mod2.c
+new file mode 100644
+index 0000000000..23915ab67b
+--- /dev/null
++++ b/elf/tst-tls-ie-mod2.c
+@@ -0,0 +1,4 @@
++#define N 2
++#define SIZE 24
++#define MODEL "global-dynamic"
++#include "tst-tls-ie-mod.h"
+diff --git a/elf/tst-tls-ie-mod3.c b/elf/tst-tls-ie-mod3.c
+new file mode 100644
+index 0000000000..5395f844a5
+--- /dev/null
++++ b/elf/tst-tls-ie-mod3.c
+@@ -0,0 +1,4 @@
++#define N 3
++#define SIZE 16
++#define MODEL "global-dynamic"
++#include "tst-tls-ie-mod.h"
+diff --git a/elf/tst-tls-ie-mod4.c b/elf/tst-tls-ie-mod4.c
+new file mode 100644
+index 0000000000..93ac2eacae
+--- /dev/null
++++ b/elf/tst-tls-ie-mod4.c
+@@ -0,0 +1,4 @@
++#define N 4
++#define SIZE 1024
++#define MODEL "initial-exec"
++#include "tst-tls-ie-mod.h"
+diff --git a/elf/tst-tls-ie-mod5.c b/elf/tst-tls-ie-mod5.c
+new file mode 100644
+index 0000000000..84b3fd285b
+--- /dev/null
++++ b/elf/tst-tls-ie-mod5.c
+@@ -0,0 +1,4 @@
++#define N 5
++#define SIZE 128
++#define MODEL "initial-exec"
++#include "tst-tls-ie-mod.h"
+diff --git a/elf/tst-tls-ie-mod6.c b/elf/tst-tls-ie-mod6.c
+new file mode 100644
+index 0000000000..c736bf0684
+--- /dev/null
++++ b/elf/tst-tls-ie-mod6.c
+@@ -0,0 +1,4 @@
++#define N 6
++#define SIZE 576
++#define MODEL "initial-exec"
++#include "tst-tls-ie-mod.h"
+diff --git a/elf/tst-tls-ie.c b/elf/tst-tls-ie.c
+new file mode 100644
+index 0000000000..c06454c50c
+--- /dev/null
++++ b/elf/tst-tls-ie.c
+@@ -0,0 +1,113 @@
++/* Test dlopen of modules with initial-exec TLS.
++ Copyright (C) 2016-2020 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <https://www.gnu.org/licenses/>. */
++
++/* This test tries to check that surplus static TLS is not used up for
++ dynamic TLS optimizations and 3*192 + 4*144 = 1152 bytes of static
++ TLS is available for dlopening modules with initial-exec TLS. It
++ depends on rtld.nns=4 and rtld.optional_static_tls=512 tunable setting. */
++
++#include <errno.h>
++#include <pthread.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++static int do_test (void);
++#include <support/xthread.h>
++#include <support/xdlfcn.h>
++#include <support/test-driver.c>
++
++/* Have some big TLS in the main exe: should not use surplus TLS. */
++__thread char maintls[1000];
++
++static pthread_barrier_t barrier;
++
++/* Forces multi-threaded behaviour. */
++static void *
++blocked_thread_func (void *closure)
++{
++ xpthread_barrier_wait (&barrier);
++ /* TLS load and access tests run here in the main thread. */
++ xpthread_barrier_wait (&barrier);
++ return NULL;
++}
++
++static void *
++load_and_access (const char *mod, const char *func)
++{
++ /* Load module with TLS. */
++ void *p = xdlopen (mod, RTLD_NOW);
++ /* Access the TLS variable to ensure it is allocated. */
++ void (*f) (void) = (void (*) (void))xdlsym (p, func);
++ f ();
++ return p;
++}
++
++static int
++do_test (void)
++{
++ void *mods[6];
++
++ {
++ int ret = pthread_barrier_init (&barrier, NULL, 2);
++ if (ret != 0)
++ {
++ errno = ret;
++ printf ("error: pthread_barrier_init: %m\n");
++ exit (1);
++ }
++ }
++
++ pthread_t blocked_thread = xpthread_create (NULL, blocked_thread_func, NULL);
++ xpthread_barrier_wait (&barrier);
++
++ printf ("maintls[%zu]:\t %p .. %p\n",
++ sizeof maintls, maintls, maintls + sizeof maintls);
++ memset (maintls, 1, sizeof maintls);
++
++ /* Load modules with dynamic TLS (may use surplus static TLS
++ opportunistically). */
++ mods[0] = load_and_access ("tst-tls-ie-mod0.so", "access0");
++ mods[1] = load_and_access ("tst-tls-ie-mod1.so", "access1");
++ mods[2] = load_and_access ("tst-tls-ie-mod2.so", "access2");
++ mods[3] = load_and_access ("tst-tls-ie-mod3.so", "access3");
++ /* Load modules with initial-exec TLS (can only use surplus static TLS). */
++ mods[4] = load_and_access ("tst-tls-ie-mod4.so", "access4");
++ mods[5] = load_and_access ("tst-tls-ie-mod5.so", "access5");
++
++ /* Here 1152 bytes of surplus static TLS is in use and at most 512 bytes
++ are available (depending on TLS optimizations). */
++ printf ("The next dlopen should fail...\n");
++ void *p = dlopen ("tst-tls-ie-mod6.so", RTLD_NOW);
++ if (p != NULL)
++ {
++ printf ("error: expected dlopen to fail because there is "
++ "not enough surplus static TLS.\n");
++ exit (1);
++ }
++ printf ("...OK failed with: %s.\n", dlerror ());
++
++ xpthread_barrier_wait (&barrier);
++ xpthread_join (blocked_thread);
++
++ /* Close the modules. */
++ for (int i = 0; i < 6; ++i)
++ xdlclose (mods[i]);
++
++ return 0;
++}
+#diff --git a/manual/tunables.texi b/manual/tunables.texi
+#index 978e08f4fb..7f891c2710 100644
+#--- a/manual/tunables.texi
+#+++ b/manual/tunables.texi
+#@@ -247,6 +247,23 @@ e.g. LD_AUDIT, or will use more than 4 dynamic link namespaces as created
+# by @code{dlmopen} with an lmid argument of @code{LM_ID_NEWLM}.
+# @end deftp
+#
+#+@deftp Tunable glibc.rtld.optional_static_tls
+#+Sets the amount of surplus static TLS in bytes to allocate at program
+#+startup. Every thread created allocates this amount of specified surplus
+#+static TLS. This is a minimum value and additional space may be allocated
+#+for internal purposes including alignment. Optional static TLS is used for
+#+optimizing dynamic TLS access for platforms that support such optimizations
+#+e.g. TLS descriptors or optimized TLS access for POWER (@code{DT_PPC64_OPT}
+#+and @code{DT_PPC_OPT}). In order to make the best use of such optimizations
+#+the value should be as many bytes as would be required to hold all TLS
+#+variables in all dynamic loaded shared libraries. The value cannot be known
+#+by the dynamic loader because it doesn't know the expected set of shared
+#+libraries which will be loaded. The existing static TLS space cannot be
+#+changed once allocated at process startup. The default allocation of
+#+optional static TLS is 512 bytes and is allocated in every thread.
+#+@end deftp
+#+
+#+
+# @node Elision Tunables
+# @section Elision Tunables
+# @cindex elision tunables
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index 3b0c6d9620..997084fb4b 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -439,6 +439,9 @@ struct rtld_global
+ EXTERN size_t _dl_tls_static_used;
+ /* Alignment requirement of the static TLS block. */
+ EXTERN size_t _dl_tls_static_align;
++ /* Remaining amount of static TLS that may be used for optimizing
++ dynamic TLS access (e.g. with TLSDESC). */
++ EXTERN size_t _dl_tls_static_optional;
+
+ /* Number of additional entries in the slotinfo array of each slotinfo
+ list element. A large number makes it almost certain take we never
+
diff -Nru glibc-2.31/debian/patches/arm64-fix.patch glibc-2.31/debian/patches/arm64-fix.patch
--- glibc-2.31/debian/patches/arm64-fix.patch 1970-01-01 00:00:00.000000000 +0000
+++ glibc-2.31/debian/patches/arm64-fix.patch 2020-07-03 10:06:19.000000000 +0000
@@ -0,0 +1,249 @@
+Origin: http://51.15.138.76/patch/37616/
+diff --git a/csu/libc-tls.c b/csu/libc-tls.c
+index 73ade0fec5..e2603157e8 100644
+--- a/csu/libc-tls.c
++++ b/csu/libc-tls.c
+@@ -46,13 +46,16 @@ bool _dl_tls_dtv_gaps;
+ struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list;
+ /* Number of modules in the static TLS block. */
+ size_t _dl_tls_static_nelem;
+-/* Size of the static TLS block. Giving this initialized value
+- preallocates some surplus bytes in the static TLS area. */
+-size_t _dl_tls_static_size = 2048;
++/* Size of the static TLS block. */
++size_t _dl_tls_static_size;
+ /* Size actually allocated in the static TLS block. */
+ size_t _dl_tls_static_used;
+ /* Alignment requirement of the static TLS block. */
+ size_t _dl_tls_static_align;
++/* Size of surplus space in the static TLS area for dynamically
++ loaded modules with IE-model TLS or for TLSDESC optimization.
++ See comments in elf/dl-tls.c where it is initialized. */
++size_t _dl_tls_static_surplus;
+
+ /* Generation counter for the dtv. */
+ size_t _dl_tls_generation;
+@@ -81,10 +84,8 @@ init_slotinfo (void)
+ static void
+ init_static_tls (size_t memsz, size_t align)
+ {
+- /* That is the size of the TLS memory for this object. The initialized
+- value of _dl_tls_static_size is provided by dl-open.c to request some
+- surplus that permits dynamic loading of modules with IE-model TLS. */
+- GL(dl_tls_static_size) = roundup (memsz + GL(dl_tls_static_size),
++ /* That is the size of the TLS memory for this object. */
++ GL(dl_tls_static_size) = roundup (memsz + GLRO(dl_tls_static_surplus),
+ TLS_TCB_ALIGN);
+ #if TLS_TCB_AT_TP
+ GL(dl_tls_static_size) += TLS_TCB_SIZE;
+@@ -125,25 +126,24 @@ __libc_setup_tls (void)
+ break;
+ }
+
++ /* Calculate the size of the static TLS surplus. */
++ _dl_tls_static_surplus_init ();
++
+ /* We have to set up the TCB block which also (possibly) contains
+ 'errno'. Therefore we avoid 'malloc' which might touch 'errno'.
+ Instead we use 'sbrk' which would only uses 'errno' if it fails.
+ In this case we are right away out of memory and the user gets
+- what she/he deserves.
+-
+- The initialized value of _dl_tls_static_size is provided by dl-open.c
+- to request some surplus that permits dynamic loading of modules with
+- IE-model TLS. */
++ what she/he deserves. */
+ #if TLS_TCB_AT_TP
+ /* Align the TCB offset to the maximum alignment, as
+ _dl_allocate_tls_storage (in elf/dl-tls.c) does using __libc_memalign
+ and dl_tls_static_align. */
+- tcb_offset = roundup (memsz + GL(dl_tls_static_size), max_align);
++ tcb_offset = roundup (memsz + GLRO(dl_tls_static_surplus), max_align);
+ tlsblock = __sbrk (tcb_offset + TLS_INIT_TCB_SIZE + max_align);
+ #elif TLS_DTV_AT_TP
+ tcb_offset = roundup (TLS_INIT_TCB_SIZE, align ?: 1);
+ tlsblock = __sbrk (tcb_offset + memsz + max_align
+- + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size));
++ + TLS_PRE_TCB_SIZE + GLRO(dl_tls_static_surplus));
+ tlsblock += TLS_PRE_TCB_SIZE;
+ #else
+ /* In case a model with a different layout for the TCB and DTV
+diff --git a/elf/dl-tls.c b/elf/dl-tls.c
+index fa03234610..2201a1cc1d 100644
+--- a/elf/dl-tls.c
++++ b/elf/dl-tls.c
+@@ -29,10 +29,54 @@
+ #include <dl-tls.h>
+ #include <ldsodefs.h>
+
+-/* Amount of excess space to allocate in the static TLS area
+- to allow dynamic loading of modules defining IE-model TLS data. */
+-#define TLS_STATIC_SURPLUS 64 + DL_NNS * 100
++#define TUNABLE_NAMESPACE rtld
++#include <dl-tunables.h>
++
++/* Surplus static TLS, GLRO(dl_tls_static_surplus), is used for
++
++ - IE TLS in libc.so for all dlmopen namespaces except in the initial
++ one where libc.so is not loaded dynamically but at startup time,
++ - IE TLS in other libraries which may be dynamically loaded even in the
++ initial namespace,
++ - and optionally for optimizing dynamic TLS access.
++
++ The maximum number of namespaces is DL_NNS, but to support that many
++ namespaces correctly the static TLS allocation should be significantly
++ increased, which may cause problems with small thread stacks due to the
++ way static TLS is accounted (bug 11787).
++
++ So there is a rtld.nns tunable limit on the number of supported namespaces
++ that affects the size of the static TLS and by default it's small enough
++ not to cause problems with existing applications. The limit is not
++ enforced or checked: it is the user's responsibility to increase rtld.nns
++ if more dlmopen namespaces are used. */
++
++/* Size of initial-exec TLS in libc.so. */
++#define LIBC_IE_TLS 192
++/* Size of initial-exec TLS in libraries other than libc.so.
++ This should be large enough to cover runtime libraries of the
++ compiler such as libgomp and libraries in libc other than libc.so. */
++#define OTHER_IE_TLS 144
++/* Size of additional surplus TLS, placeholder for TLS optimizations. */
++#define OPT_SURPLUS_TLS 512
+
++void
++_dl_tls_static_surplus_init (void)
++{
++ size_t nns;
++
++#if HAVE_TUNABLES
++ nns = TUNABLE_GET (nns, size_t, NULL);
++#else
++ /* Default values of the tunables. */
++ nns = 4;
++#endif
++ if (nns > DL_NNS)
++ nns = DL_NNS;
++ GLRO(dl_tls_static_surplus) = ((nns - 1) * LIBC_IE_TLS
++ + nns * OTHER_IE_TLS
++ + OPT_SURPLUS_TLS);
++}
+
+ /* Out-of-memory handler. */
+ static void
+@@ -218,7 +262,8 @@ _dl_determine_tlsoffset (void)
+ }
+
+ GL(dl_tls_static_used) = offset;
+- GL(dl_tls_static_size) = (roundup (offset + TLS_STATIC_SURPLUS, max_align)
++ GL(dl_tls_static_size) = (roundup (offset + GLRO(dl_tls_static_surplus),
++ max_align)
+ + TLS_TCB_SIZE);
+ #elif TLS_DTV_AT_TP
+ /* The TLS blocks start right after the TCB. */
+@@ -262,7 +307,7 @@ _dl_determine_tlsoffset (void)
+ }
+
+ GL(dl_tls_static_used) = offset;
+- GL(dl_tls_static_size) = roundup (offset + TLS_STATIC_SURPLUS,
++ GL(dl_tls_static_size) = roundup (offset + GLRO(dl_tls_static_surplus),
+ TLS_TCB_ALIGN);
+ #else
+ # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
+index 0d398dd251..b07742d7b3 100644
+--- a/elf/dl-tunables.list
++++ b/elf/dl-tunables.list
+@@ -126,4 +126,13 @@ glibc {
+ default: 3
+ }
+ }
++
++ rtld {
++ nns {
++ type: SIZE_T
++ minval: 1
++ maxval: 16
++ default: 4
++ }
++ }
+ }
+diff --git a/elf/rtld.c b/elf/rtld.c
+index f4c2602d65..f339f6894f 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -737,6 +737,9 @@ init_tls (void)
+ }
+ assert (i == GL(dl_tls_max_dtv_idx));
+
++ /* Calculate the size of the static TLS surplus. */
++ _dl_tls_static_surplus_init ();
++
+ /* Compute the TLS offsets for the various blocks. */
+ _dl_determine_tlsoffset ();
+
+#diff --git a/manual/tunables.texi b/manual/tunables.texi
+#index ec18b10834..978e08f4fb 100644
+#--- a/manual/tunables.texi
+#+++ b/manual/tunables.texi
+#@@ -31,6 +31,7 @@ their own namespace.
+# @menu
+# * Tunable names:: The structure of a tunable name
+# * Memory Allocation Tunables:: Tunables in the memory allocation subsystem
+#+* Dynamic Linking Tunables:: Tunables in the dynamic linking subsystem
+# * Elision Tunables:: Tunables in elision subsystem
+# * POSIX Thread Tunables:: Tunables in the POSIX thread subsystem
+# * Hardware Capability Tunables:: Tunables that modify the hardware
+#@@ -226,6 +227,26 @@ pointer, so add 4 on 32-bit systems or 8 on 64-bit systems to the size
+# passed to @code{malloc} for the largest bin size to enable.
+# @end deftp
+#
+#+@node Dynamic Linking Tunables
+#+@section Dynamic Linking Tunables
+#+@cindex dynamic linking tunables
+#+@cindex rtld tunables
+#+
+#+@deftp {Tunable namespace} glibc.rtld
+#+Dynamic linker behavior can be modified by setting the
+#+following tunables in the @code{rtld} namespace:
+#+@end deftp
+#+
+#+@deftp Tunable glibc.rtld.nns
+#+Sets the number of supported dynamic link namespaces (see @code{dlmopen}).
+#+Currently this limit can be set between 1 and 16 inclusive, the default is 4.
+#+Each link namespace consumes some memory in all thread, and thus raising the
+#+limit will increase the amount of memory each thread uses. Raising the limit
+#+is useful when your application uses more than 4 dynamic linker audit modules
+#+e.g. LD_AUDIT, or will use more than 4 dynamic link namespaces as created
+#+by @code{dlmopen} with an lmid argument of @code{LM_ID_NEWLM}.
+#+@end deftp
+#+
+# @node Elision Tunables
+# @section Elision Tunables
+# @cindex elision tunables
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index c525ffa12c..3b0c6d9620 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -580,6 +580,11 @@ struct rtld_global_ro
+ binaries, don't honor for PIEs). */
+ EXTERN ElfW(Addr) _dl_use_load_bias;
+
++ /* Size of surplus space in the static TLS area for dynamically
++ loaded modules with IE-model TLS or for TLSDESC optimization.
++ See comments in elf/dl-tls.c where it is initialized. */
++ EXTERN size_t _dl_tls_static_surplus;
++
+ /* Name of the shared object to be profiled (if any). */
+ EXTERN const char *_dl_profile;
+ /* Filename of the output file. */
+@@ -1086,6 +1091,9 @@ extern size_t _dl_count_modids (void) attribute_hidden;
+ /* Calculate offset of the TLS blocks in the static TLS block. */
+ extern void _dl_determine_tlsoffset (void) attribute_hidden;
+
++/* Calculate the size of the static TLS surplus. */
++void _dl_tls_static_surplus_init (void) attribute_hidden;
++
+ #ifndef SHARED
+ /* Set up the TCB for statically linked applications. This is called
+ early during startup because we always use TLS (for errno and the
+
diff -Nru glibc-2.31/debian/patches/series glibc-2.31/debian/patches/series
--- glibc-2.31/debian/patches/series 2020-06-10 13:59:46.000000000 +0000
+++ glibc-2.31/debian/patches/series 2020-07-03 10:07:07.000000000 +0000
@@ -136,3 +136,5 @@
ubuntu/localedata/ug_CN@latin.diff
ubuntu/local-pldd-root.diff
ubuntu/cet-backport.diff
+arm64-fix.patch
+arm64-fix-2.patch
Reply to: