summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Shebs <stanshebs@google.com>2020-10-21 13:19:47 -0700
committerFangrui Song <i@maskray.me>2021-08-27 17:26:04 -0700
commitbcc638805a52b425d74fc543ff83a7f6fac0065a (patch)
treedea9e76d98103c885ea814fc9196630fe28a0519
parentd548adb4ef75dfc9bc1838f46f6c67f11e09906e (diff)
downloadglibc-bcc638805a52b425d74fc543ff83a7f6fac0065a.tar.gz
Add a test of TLS support that will fail if leaky
-rw-r--r--nptl/Makefile9
-rw-r--r--nptl/tst-tls7leak.c117
-rw-r--r--nptl/tst-tls7leakmod.c27
3 files changed, 151 insertions, 2 deletions
diff --git a/nptl/Makefile b/nptl/Makefile
index 2ffc54bfd1..fae3c056bf 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -374,7 +374,7 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \
tst-oncex3 tst-oncex4
ifeq ($(build-shared),yes)
tests += tst-atfork2 tst-tls4 tst-_res1 tst-fini1 tst-compat-forwarder
-tests += tst-tls7a
+tests += tst-tls7a tst-tls7leak
tests-internal += tst-tls3 tst-tls3-malloc tst-tls5 tst-stackguard1
tests-nolibpthread += tst-fini1
ifeq ($(have-z-execstack),yes)
@@ -390,7 +390,7 @@ modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \
tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \
tst-_res1mod1 tst-_res1mod2 tst-fini1mod \
tst-join7mod tst-compat-forwarder-mod
-modules-names += tst-tls7amod
+modules-names += tst-tls7amod tst-tls7leakmod
ifneq ($(with-clang),yes)
modules-names += tst-execstack-mod
endif
@@ -409,6 +409,7 @@ tst-tls5modd.so-no-z-defs = yes
tst-tls5mode.so-no-z-defs = yes
tst-tls5modf.so-no-z-defs = yes
tst-tls7amod.so-no-z-defs = yes
+tst-tls7leakmod.so-no-z-defs = yes
ifeq ($(build-shared),yes)
# Build all the modules even when not actually running test programs.
@@ -607,6 +608,10 @@ $(objpfx)tst-tls7a: $(libdl) $(shared-thread-library)
$(objpfx)tst-tls7a.out: $(objpfx)tst-tls7amod.so
$(objpfx)tst-tls7amod.so: $(shared-thread-library)
+$(objpfx)tst-tls7leak: $(libdl) $(shared-thread-library)
+$(objpfx)tst-tls7leak.out: $(objpfx)tst-tls7leakmod.so
+$(objpfx)tst-tls7leakmod.so: $(shared-thread-library)
+
ifeq ($(build-shared),yes)
$(objpfx)tst-tls6.out: tst-tls6.sh $(objpfx)tst-tls5 \
$(objpfx)tst-tls5moda.so $(objpfx)tst-tls5modb.so \
diff --git a/nptl/tst-tls7leak.c b/nptl/tst-tls7leak.c
new file mode 100644
index 0000000000..42825bdc34
--- /dev/null
+++ b/nptl/tst-tls7leak.c
@@ -0,0 +1,117 @@
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This test checks that leakage does not happen from repeated loads
+ of a module with TLS. */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+int (*tlsmod_fun) (void);
+
+/* Async-signal-safe TLS space is gotten via custom allocator using mmap(), so
+ it doesn't work to use functions like mtrace() or mallinfo(). */
+
+size_t get_vm_size (void)
+{
+ long result;
+ FILE *f = fopen ("/proc/self/statm", "r");
+
+ if (!f)
+ {
+ fprintf (stderr, "get_vm_size could not open /proc/self/statm\n");
+ return 0;
+ }
+ if (fscanf (f, "%lu", &result) != 1)
+ {
+ fprintf (stderr, "get_vm_size failed to read size\n");
+ return 0;
+ }
+ if (fclose (f) != 0)
+ {
+ fprintf (stderr, "get_vm_size fclose failed\n");
+ return 0;
+ }
+
+ return (size_t) result;
+}
+
+int
+do_test (void)
+{
+ int count = 0;
+
+ size_t start_size = get_vm_size ();
+
+ if (start_size == 0)
+ {
+ puts ("Cannot get vm size, test cannot run");
+ exit (0);
+ }
+
+ /* Open, use, and close a shared library repeatedly. */
+ for (int i = 0; i < 1000; ++i)
+ {
+ void *h = dlopen ("tst-tls7leakmod.so", RTLD_NOW);
+ if (h == NULL)
+ {
+ puts ("dlopen failed");
+ exit (1);
+ }
+
+ tlsmod_fun = dlsym (h, "module_fun");
+ if (tlsmod_fun == NULL)
+ {
+ puts ("dlsym for module_fun failed");
+ exit (1);
+ }
+
+ count += tlsmod_fun ();
+
+ /* Don't leave dangling pointer after dlclose. */
+ tlsmod_fun = NULL;
+
+ if (dlclose (h))
+ {
+ puts ("dlclose failed");
+ exit (1);
+ }
+
+ }
+
+ size_t end_size = get_vm_size ();
+ printf ("VM usage went from %ld to %ld pages", start_size, end_size);
+
+ /* Allow for some growth in usage. */
+ if ((end_size - start_size) > 10)
+ {
+ printf (", which indicates a leak in TLS allocation\n");
+ return 1;
+ }
+ else
+ {
+ printf (", which is acceptable\n");
+ return 0;
+ }
+}
+
+#define TIMEOUT 8
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-tls7leakmod.c b/nptl/tst-tls7leakmod.c
new file mode 100644
index 0000000000..29751eb467
--- /dev/null
+++ b/nptl/tst-tls7leakmod.c
@@ -0,0 +1,27 @@
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* Dynamic module that does not need to do much. */
+
+__thread int avar;
+
+int
+module_fun (void)
+{
+ ++avar;
+ return avar;
+}