diff options
author | Stan Shebs <stanshebs@google.com> | 2020-10-21 13:19:47 -0700 |
---|---|---|
committer | Fangrui Song <i@maskray.me> | 2021-08-27 17:26:04 -0700 |
commit | bcc638805a52b425d74fc543ff83a7f6fac0065a (patch) | |
tree | dea9e76d98103c885ea814fc9196630fe28a0519 | |
parent | d548adb4ef75dfc9bc1838f46f6c67f11e09906e (diff) | |
download | glibc-bcc638805a52b425d74fc543ff83a7f6fac0065a.tar.gz |
Add a test of TLS support that will fail if leaky
-rw-r--r-- | nptl/Makefile | 9 | ||||
-rw-r--r-- | nptl/tst-tls7leak.c | 117 | ||||
-rw-r--r-- | nptl/tst-tls7leakmod.c | 27 |
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; +} |