@@ -1,3 +1,62 @@
+2018-06-26 DJ Delorie <dj@redhat.com>
+ Carlos O'Donell <carlos@redhat.com>
+
+ [BZ #23329]
+ * include/libc-symbols: Comment the freeres framework.
+ (__libc_freeres_fn_section): Define.
+ (__libc_thread_freeres_fn_section): Define.
+ (__libdl_freeres_fn_section): Define.
+ (__libthread_freeres_fn_section): Define.
+ (libc_thread_freeres_fn): Define.
+ * dlfcn/Makefile (libdl-routines): Add dlfreeres.
+ * dlfcn/Versions (GLIBC_PRIVATE): Add __libdl_freeres.
+ * dlfcn/dlerror.c: Include libc-symbols.h
+ (__dlerror_main_freeres): New function.
+ * include/dlfcn.h: Declare __dlerror_main_freeres.
+ * dlfcn/dlfreeres.c: New file.
+ * dlfcn/sdlfreeres.c: New file.
+ * include/set-hooks.h: Include libc-symbols.h. Fix comment.
+ * malloc/arena.c: Include libc-symbols.h.
+ (arena_thread_freeres): Use __libc_thread_freeres_fn_section.
+ * malloc/set-freeres.c: Add hook for libdl.so, and libpthread.so.
+ (__libc_subfreeres): Call libdl and libpthread hooks.
+ * malloc/thread-freeres.c: Add comments. Use
+ __libc_thread_freeres_fn_section.
+ * nptl/Makefile (libpthread-routines): Add nptlfreeres.
+ * nptl/Version (GLIBC_PRIVATE): Add __libpthread_freeres.
+ * nptl/allocatestack.c (__nptl_free_stacks): New function.
+ (__free_stacks): Rename to...
+ (free_stacks): ...this. Mark static.
+ (queue_stack): Call free_stacks.
+ * nptl/libc_pthread_init.c (freeres_libpthread): Delete.
+ * sysdeps/nptl/pthread-functions.h (pthread_functions): Remove
+ ptr_freeres.
+ * nptl/nptl-init.c (pthread_functions): Remove nptl_freeres.
+ (nptl_freeres): Remove.
+ * nptl/nptlfreeres.c: New file.
+ * nptl/pthreadP.h
+ [IS_IN (libpthread) && SHARED ] (__unwind_freeres): Rename to...
+ [IS_IN (libpthread)] (__nptl_unwind_freeres): ...this.
+ (__free_stacks): Rename to...
+ (__nptl_free_stacks): ...this.
+ (__freeres_shm_directory): Declare.
+ * nptl/unwind-forcedunwind.c: Include libc-symbols.h.
+ (__unwind_freeres): Rename to...
+ (__nptl_unwind_freeres): ...this. Use libpthread_freeres_fn.
+ * sysdeps/unix/sysv/linux/shm-directory.c (freeit): Rename to...
+ [IS_IN (libpthread)] (__freeres_shm_directory): ...this.
+ Use libpthread_freeres_fn.
+ * resolv/res-close.c: Include libc-symbols.h.
+ (res_thread_freeres): Use __libc_thread_freeres_fn_section.
+ * resolv/resolv_conf.c: Include libc-symbols.h.
+ (freeres): Use libc_freeres_fn.
+ * string/strerror_l.c: Include libc-symbols.h.
+ (strerror_thread_freeres): Use __libc_thread_freeres_fn_section.
+ * sunrpc/rpc_thread.c: Include libc-symbols.h.
+ (__rpc_thread_destroy): Use __libc_thread_freeres_fn_section.
+ * sysdeps/mach/strerror_l.c: Inlcude libc-symbols.h
+ (strerror_thread_freeres): Use __libc_thread_freeres_fn_section.
+
2018-06-26 Joseph Myers <joseph@codesourcery.com>
[BZ #13888]
@@ -22,7 +22,7 @@ include ../Makeconfig
headers := bits/dlfcn.h dlfcn.h
extra-libs := libdl
libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo \
- dlmopen dlfcn
+ dlmopen dlfcn dlfreeres
routines := $(patsubst %,s%,$(filter-out dlfcn,$(libdl-routines)))
elide-routines.os := $(routines)
@@ -13,5 +13,6 @@ libdl {
}
GLIBC_PRIVATE {
_dlfcn_hook;
+ __libdl_freeres;
}
}
@@ -24,6 +24,7 @@
#include <string.h>
#include <libc-lock.h>
#include <ldsodefs.h>
+#include <libc-symbols.h>
#if !defined SHARED && IS_IN (libdl)
@@ -222,6 +223,19 @@ free_key_mem (void *mem)
# ifdef SHARED
+/* Free the dlerror-related resources. */
+void __libdl_freeres_fn_section
+__dlerror_main_freeres (void)
+{
+ void *mem;
+ /* Free the global memory if used. */
+ check_free (&last_result);
+ /* Free the TSD memory if used. */
+ mem = __libc_getspecific (key);
+ if (mem != NULL)
+ free_key_mem (mem);
+}
+
struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
libdl_hidden_data_def (_dlfcn_hook)
new file mode 100644
@@ -0,0 +1,30 @@
+/* Clean up allocated libdl memory on demand.
+ Copyright (C) 2018 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/>. */
+
+#include <set-hooks.h>
+#include <libc-symbols.h>
+#include <dlfcn.h>
+
+/* Free libdl.so resources.
+ Note: Caller ensures we are called only once. */
+void __libdl_freeres_fn_section
+__libdl_freeres (void)
+{
+ call_function_static_weak (__dlerror_main_freeres);
+}
+libc_hidden_def (__libdl_freeres)
new file mode 100644
@@ -0,0 +1 @@
+#include "dlfreeres.c"
@@ -155,6 +155,8 @@ extern void __libc_register_dl_open_hook (struct link_map *map)
extern void __libc_register_dlfcn_hook (struct link_map *map)
attribute_hidden;
#endif
-#endif
+extern void __dlerror_main_freeres (void) attribute_hidden;
+
+#endif
#endif
@@ -217,16 +217,6 @@
static const char __evoke_link_warning_##symbol[] \
__attribute__ ((used, section (".gnu.warning." #symbol __sec_comment))) \
= msg;
-#define libc_freeres_ptr(decl) \
- __make_section_unallocated ("__libc_freeres_ptrs, \"aw\", %nobits") \
- decl __attribute__ ((section ("__libc_freeres_ptrs" __sec_comment)))
-#define __libc_freeres_fn_section \
- __attribute__ ((section ("__libc_freeres_fn")))
-
-#define libc_freeres_fn(name) \
- static void name (void) __attribute_used__ __libc_freeres_fn_section; \
- text_set_element (__libc_subfreeres, name); \
- static void name (void)
/* A canned warning for sysdeps/stub functions. */
#define stub_warning(name) \
@@ -244,6 +234,105 @@ requires at runtime the shared libraries from the glibc version used \
for linking")
#endif
+/* Resource Freeing Hooks:
+
+ Normally a process exits and the OS cleans up any allocated
+ memory. However, when tooling like mtrace or valgrind is monitoring
+ the process we need to free all resources that are part of the
+ process in order to provide the consistency required to track
+ memory leaks.
+
+ A single public API exists and is __libc_freeres(), and this is used
+ by applications like valgrind to freee resouces.
+
+ There are 3 cases:
+
+ (a) __libc_freeres
+
+ In this case all you need to do is define the freeing routine:
+
+ foo.c:
+ libfoo_freeres_fn (foo_freeres)
+ {
+ complex_free (mem);
+ }
+
+ This ensures the function is called at the right point to free
+ resources.
+
+ (b) __libc_freeres_ptr
+
+ The framework for (a) iterates over the list of pointers-to-free
+ in (b) and frees them.
+
+ foo.c:
+ libc_freeres_ptr (static char *foo_buffer);
+
+ Freeing these resources alaways happens last and is equivalent
+ to registering a function that does 'free (foo_buffer)'.
+
+ (c) Explicit lists of free routines to call or objects to free.
+
+ It is the intended goal to remove (a) and (b) which have some
+ non-determinism based on link order, and instead use explicit
+ lists of functions and frees to resolve cleanup ordering issues
+ and make it easy to debug and maintain.
+
+ As of today the following subsystems use (c):
+
+ Per-thread cleanup:
+ * malloc/thread-freeres.c
+
+ libdl cleanup:
+ * dlfcn/dlfreeres.c
+
+ libpthread cleanup:
+ * nptl/nptlfreeres.c
+
+ So if you need any shutdown routines to run you should add them
+ directly to the appropriate subsystem's shutdown list.
+
+ You should still place your function into the appropriate
+ section like this (such functions cannot be static and must be
+ prototyped in the appropriate headers):
+
+ foo.c:
+ void __libdl_freeres_fn_section
+ foo (void)
+ {
+ free (mem);
+ }
+
+ This helps ensure we have some markup for the relevant functions
+ and that they do not pollute icache. */
+
+/* Resource pointers to freed in libc.so. */
+#define libc_freeres_ptr(decl) \
+ __make_section_unallocated ("__libc_freeres_ptrs, \"aw\", %nobits") \
+ decl __attribute__ ((section ("__libc_freeres_ptrs" __sec_comment)))
+
+/* Resource freeing functions from libc.so. */
+#define __libc_freeres_fn_section \
+ __attribute__ ((section ("__libc_freeres_fn")))
+
+/* Resource freeing functions for threads in libc.so. */
+#define __libc_thread_freeres_fn_section \
+ __attribute__ ((section ("__libc_thread_freeres_fn")))
+
+/* Resource freeing functions for libdl.so */
+#define __libdl_freeres_fn_section \
+ __attribute__ ((section ("__libdl_freeres_fn")))
+
+/* Resource freeing functions for libpthread.so. */
+#define __libpthread_freeres_fn_section \
+ __attribute__ ((section ("__libpthread_freeres_fn")))
+
+/* Resource freeing functions for libc.so. */
+#define libc_freeres_fn(name) \
+ static void name (void) __attribute_used__ __libc_freeres_fn_section; \
+ text_set_element (__libc_subfreeres, name); \
+ static void name (void)
+
/* Declare SYMBOL to be TYPE (`function' or `object') of SIZE bytes
alias to ORIGINAL, when the assembler supports such declarations
(such as in ELF).
@@ -22,11 +22,12 @@
#define __need_size_t
#include <stddef.h>
#include <sys/cdefs.h>
+#include <libc-symbols.h>
#ifdef symbol_set_define
/* Define a hook variable called NAME. Functions put on this hook take
arguments described by PROTO. Use `text_set_element (NAME, FUNCTION)'
- from gnu-stabs.h to add a function to the hook. */
+ from include/libc-symbols.h to add a function to the hook. */
# define DEFINE_HOOK(NAME, PROTO) \
typedef void __##NAME##_hook_function_t PROTO; \
@@ -18,6 +18,7 @@
not, see <http://www.gnu.org/licenses/>. */
#include <stdbool.h>
+#include <libc-symbols.h>
#if HAVE_TUNABLES
# define TUNABLE_NAMESPACE malloc
@@ -941,7 +942,7 @@ arena_get_retry (mstate ar_ptr, size_t bytes)
return ar_ptr;
}
-void
+void __libc_thread_freeres_fn_section
__malloc_arena_thread_freeres (void)
{
/* Shut down the thread cache first. This could deallocate data for
@@ -26,6 +26,10 @@ DEFINE_HOOK (__libc_subfreeres, (void));
symbol_set_define (__libc_freeres_ptrs);
+extern __attribute__((weak)) void __libdl_freeres (void);
+
+extern __attribute__((weak)) void __libpthread_freeres (void);
+
void __libc_freeres_fn_section
__libc_freeres (void)
{
@@ -39,8 +43,19 @@ __libc_freeres (void)
_IO_cleanup ();
+ /* We run the resource freeing after IO cleanup. */
RUN_HOOK (__libc_subfreeres, ());
+ /* Call the libdl list of cleanup functions
+ (weak-ref-and-check). */
+ if (&__libdl_freeres != NULL)
+ call_function_static_weak (__libdl_freeres);
+
+ /* Call the libpthread list of cleanup functions
+ (weak-ref-and-check). */
+ if (&__libpthread_freeres != NULL)
+ call_function_static_weak (__libpthread_freeres);
+
for (p = symbol_set_first_element (__libc_freeres_ptrs);
!symbol_set_end_p (__libc_freeres_ptrs, p); ++p)
free (*p);
@@ -21,12 +21,13 @@
#include <resolv/resolv-internal.h>
#include <rpc/rpc.h>
#include <string.h>
+#include <libc-symbols.h>
/* Thread shutdown function. Note that this function must be called
for threads during shutdown for correctness reasons. Unlike
- __libc_subfreeres, skipping calls to it is not a valid
- optimization. */
-void
+ __libc_subfreeres, skipping calls to it is not a valid optimization.
+ This is called directly from pthread_create as the thread exits. */
+void __libc_thread_freeres_fn_section
__libc_thread_freeres (void)
{
call_function_static_weak (__rpc_thread_destroy);
@@ -45,7 +45,7 @@ pthread-compat-wrappers = \
sigwait sigsuspend \
recvmsg sendmsg
-libpthread-routines = nptl-init vars events version pt-interp \
+libpthread-routines = nptl-init nptlfreeres vars events version pt-interp \
pthread_create pthread_exit pthread_detach \
pthread_join pthread_tryjoin pthread_timedjoin \
pthread_join_common \
@@ -271,5 +271,6 @@ libpthread {
__pthread_unwind; __pthread_get_minstack;
__pthread_barrier_init; __pthread_barrier_wait;
__shm_directory;
+ __libpthread_freeres;
}
}
@@ -32,6 +32,7 @@
#include <futex-internal.h>
#include <kernel-features.h>
#include <stack-aliasing.h>
+#include <libc-symbols.h>
#ifndef NEED_SEPARATE_REGISTER_STACK
@@ -251,8 +252,8 @@ get_cached_stack (size_t *sizep, void **memp)
/* Free stacks until cache size is lower than LIMIT. */
-void
-__free_stacks (size_t limit)
+static void
+free_stacks (size_t limit)
{
/* We reduce the size of the cache. Remove the last entries until
the size is below the limit. */
@@ -288,6 +289,12 @@ __free_stacks (size_t limit)
}
}
+/* Free all the stacks on cleanup. */
+void __libpthread_freeres_fn_section
+__nptl_free_stacks (void)
+{
+ free_stacks (0);
+}
/* Add a stack frame which is not used anymore to the stack. Must be
called with the cache lock held. */
@@ -302,7 +309,7 @@ queue_stack (struct pthread *stack)
stack_cache_actsize += stack->stackblock_size;
if (__glibc_unlikely (stack_cache_actsize > stack_cache_maxsize))
- __free_stacks (stack_cache_maxsize);
+ free_stacks (stack_cache_maxsize);
}
@@ -77,11 +77,3 @@ __libc_pthread_init (unsigned long int *ptr, void (*reclaim) (void),
return &__libc_multiple_threads;
#endif
}
-
-#ifdef SHARED
-libc_freeres_fn (freeres_libptread)
-{
- if (__libc_pthread_functions_init)
- PTHFCT_CALL (ptr_freeres, ());
-}
-#endif
@@ -78,9 +78,6 @@ extern
void __nptl_set_robust (struct pthread *);
#ifdef SHARED
-static void nptl_freeres (void);
-
-
static const struct pthread_functions pthread_functions =
{
.ptr_pthread_attr_destroy = __pthread_attr_destroy,
@@ -140,8 +137,6 @@ static const struct pthread_functions pthread_functions =
# ifdef SIGSETXID
.ptr__nptl_setxid = __nptl_setxid,
# endif
- /* For now only the stack cache needs to be freed. */
- .ptr_freeres = nptl_freeres,
.ptr_set_robust = __nptl_set_robust
};
# define ptr_pthread_functions &pthread_functions
@@ -151,16 +146,6 @@ static const struct pthread_functions pthread_functions =
#ifdef SHARED
-/* This function is called indirectly from the freeres code in libc. */
-static void
-__libc_freeres_fn_section
-nptl_freeres (void)
-{
- __unwind_freeres ();
- __free_stacks (0);
-}
-
-
static
#endif
void
new file mode 100644
@@ -0,0 +1,31 @@
+/* Clean up allocated libpthread memory on demand.
+ Copyright (C) 2018 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/>. */
+
+#include <set-hooks.h>
+#include <libc-symbols.h>
+#include <pthreadP.h>
+
+/* Free libpthread.so resources.
+ Note: Caller ensures we are called only once. */
+void __libpthread_freeres_fn_section
+__libpthread_freeres (void)
+{
+ call_function_static_weak (__nptl_free_stacks);
+ call_function_static_weak (__freeres_shm_directory);
+ call_function_static_weak (__nptl_unwind_freeres);
+}
@@ -279,8 +279,8 @@ hidden_proto (__pthread_register_cancel)
hidden_proto (__pthread_unregister_cancel)
# ifdef SHARED
extern void attribute_hidden pthread_cancel_init (void);
-extern void __unwind_freeres (void);
# endif
+extern void __nptl_unwind_freeres (void) attribute_hidden;
#endif
@@ -597,7 +597,8 @@ extern int __nptl_setxid (struct xid_command *cmdp) attribute_hidden;
extern void __nptl_set_robust (struct pthread *self);
#endif
-extern void __free_stacks (size_t limit) attribute_hidden;
+extern void __nptl_free_stacks (void) attribute_hidden;
+extern void __freeres_shm_directory (void) attribute_hidden;
extern void __wait_lookup_done (void) attribute_hidden;
@@ -87,6 +87,7 @@
#include <resolv_conf.h>
#include <not-cancel.h>
#include <stdlib.h>
+#include <libc-symbols.h>
/* Close all open sockets. If FREE_ADDR is true, deallocate any
separately allocated name server addresses. */
@@ -126,7 +127,7 @@ res_nclose (res_state statp)
libc_hidden_def (__res_nclose)
/* This is called when a thread is exiting to free resources held in _res. */
-void
+void __libc_thread_freeres_fn_section
__res_thread_freeres (void)
{
__resolv_context_freeres ();
@@ -140,4 +141,5 @@ __res_thread_freeres (void)
/* Make sure we do a full re-initialization the next time. */
_res.options = 0;
}
+/* Also must be called when the main thread exits. */
text_set_element (__libc_subfreeres, __res_thread_freeres);
@@ -23,6 +23,7 @@
#include <libc-lock.h>
#include <resolv-internal.h>
#include <sys/stat.h>
+#include <libc-symbols.h>
/* _res._u._ext.__glibc_extension_index is used as an index into a
struct resolv_conf_array object. The intent of this construction
@@ -21,7 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
-
+#include <libc-symbols.h>
static __thread char *last_value;
@@ -57,7 +57,7 @@ strerror_l (int errnum, locale_t loc)
}
-void
+void __libc_thread_freeres_fn_section
__strerror_thread_freeres (void)
{
free (last_value);
@@ -5,6 +5,7 @@
#include <libc-lock.h>
#include <libc-tsd.h>
#include <shlib-compat.h>
+#include <libc-symbols.h>
/* Variable used in non-threaded applications or for the first thread. */
@@ -15,7 +16,7 @@ static __thread struct rpc_thread_variables *thread_rpc_vars
/*
* Task-variable destructor
*/
-void
+void __libc_thread_freeres_fn_section
__rpc_thread_destroy (void)
{
struct rpc_thread_variables *tvp = thread_rpc_vars;
@@ -24,6 +24,7 @@
#include <mach/error.h>
#include <errorlib.h>
#include <sys/param.h>
+#include <libc-symbols.h>
static __thread char *last_value;
@@ -86,8 +87,8 @@ strerror_l (int errnum, locale_t loc)
return (char *) translate (es->subsystem[sub].codes[code], loc);
}
-
-void
+/* This is called when a thread is exiting to free the last_value string. */
+void __libc_thread_freeres_fn_section
__strerror_thread_freeres (void)
{
free (last_value);
@@ -94,7 +94,6 @@ struct pthread_functions
__attribute ((noreturn)) __cleanup_fct_attribute;
void (*ptr__nptl_deallocate_tsd) (void);
int (*ptr__nptl_setxid) (struct xid_command *);
- void (*ptr_freeres) (void);
void (*ptr_set_robust) (struct pthread *);
};
@@ -23,6 +23,7 @@
#include <sysdep.h>
#include <gnu/lib-names.h>
#include <unwind-resume.h>
+#include <libc-symbols.h>
static void *libgcc_s_handle;
void (*__libgcc_s_resume) (struct _Unwind_Exception *exc)
@@ -79,9 +80,9 @@ pthread_cancel_init (void)
libgcc_s_handle = handle;
}
-void
-__libc_freeres_fn_section
-__unwind_freeres (void)
+/* Register for cleanup in libpthread.so. */
+void __libpthread_freeres_fn_section
+__nptl_unwind_freeres (void)
{
void *handle = libgcc_s_handle;
if (handle != NULL)
@@ -26,6 +26,7 @@
#include <sys/statfs.h>
#include <libc-lock.h>
#include "linux_fsinfo.h"
+#include <libc-symbols.h>
/* Mount point of the shared memory filesystem. */
@@ -135,13 +136,13 @@ __shm_directory (size_t *len)
}
#if IS_IN (libpthread)
hidden_def (__shm_directory)
-#endif
-
/* Make sure the table is freed if we want to free everything before
exiting. */
-libc_freeres_fn (freeit)
+void __libpthread_freeres_fn_section
+__freeres_shm_directory (void)
{
if (mountpoint.dir != defaultdir)
free (mountpoint.dir);
}
+#endif