Move libc_freeres_ptrs and libc_subfreeres to hidden/weak functions

They are both used by __libc_freeres to free all library malloc
allocated resources to help tooling like mtrace or valgrind with
memory leak tracking.

The current scheme uses assembly markers and linker script entries
to consolidate the free routine function pointers in the RELRO segment
and to be freed buffers in BSS.

This patch changes it to use specific free functions for
libc_freeres_ptrs buffers and call the function pointer array directly
with call_function_static_weak.

It allows the removal of both the internal macros and the linker
script sections.

Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
This commit is contained in:
Adhemerval Zanella Netto 2022-12-27 18:11:42 -03:00 committed by Adhemerval Zanella
parent e4d336f1ac
commit 88677348b4
90 changed files with 585 additions and 244 deletions

View File

@ -560,14 +560,7 @@ $(common-objpfx)shlib.lds: $(common-objpfx)config.make $(..)Makerules
-Wl,--verbose 2>/dev/null | \ -Wl,--verbose 2>/dev/null | \
sed > $@T \ sed > $@T \
-e '/^=========/,/^=========/!d;/^=========/d' \ -e '/^=========/,/^=========/!d;/^=========/d' \
-e 's/^.*\*(\.dynbss).*$$/& \
PROVIDE(__start___libc_freeres_ptrs = .); \
*(__libc_freeres_ptrs) \
PROVIDE(__stop___libc_freeres_ptrs = .);/'\
-e 's@^.*\*(\.jcr).*$$@& \ -e 's@^.*\*(\.jcr).*$$@& \
PROVIDE(__start___libc_subfreeres = .);\
__libc_subfreeres : { *(__libc_subfreeres) }\
PROVIDE(__stop___libc_subfreeres = .);\
PROVIDE(__start___libc_IO_vtables = .);\ PROVIDE(__start___libc_IO_vtables = .);\
__libc_IO_vtables : { *(__libc_IO_vtables) }\ __libc_IO_vtables : { *(__libc_IO_vtables) }\
PROVIDE(__stop___libc_IO_vtables = .);\ PROVIDE(__stop___libc_IO_vtables = .);\

View File

@ -299,10 +299,7 @@ __md5_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
return buffer; return buffer;
} }
#ifndef _LIBC static char *buffer;
# define libc_freeres_ptr(decl) decl
#endif
libc_freeres_ptr (static char *buffer);
char * char *
__md5_crypt (const char *key, const char *salt) __md5_crypt (const char *key, const char *salt)
@ -326,11 +323,9 @@ __md5_crypt (const char *key, const char *salt)
return __md5_crypt_r (key, salt, buffer, buflen); return __md5_crypt_r (key, salt, buffer, buflen);
} }
#ifndef _LIBC
static void static void
__attribute__ ((__destructor__)) __attribute__ ((__destructor__))
free_mem (void) free_mem (void)
{ {
free (buffer); free (buffer);
} }
#endif

View File

@ -386,10 +386,7 @@ __sha256_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
return buffer; return buffer;
} }
#ifndef _LIBC static char *buffer;
# define libc_freeres_ptr(decl) decl
#endif
libc_freeres_ptr (static char *buffer);
/* This entry point is equivalent to the `crypt' function in Unix /* This entry point is equivalent to the `crypt' function in Unix
libcs. */ libcs. */
@ -418,11 +415,9 @@ __sha256_crypt (const char *key, const char *salt)
return __sha256_crypt_r (key, salt, buffer, buflen); return __sha256_crypt_r (key, salt, buffer, buflen);
} }
#ifndef _LIBC
static void static void
__attribute__ ((__destructor__)) __attribute__ ((__destructor__))
free_mem (void) free_mem (void)
{ {
free (buffer); free (buffer);
} }
#endif

View File

@ -408,10 +408,7 @@ __sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
return buffer; return buffer;
} }
#ifndef _LIBC static char *buffer;
# define libc_freeres_ptr(decl) decl
#endif
libc_freeres_ptr (static char *buffer);
/* This entry point is equivalent to the `crypt' function in Unix /* This entry point is equivalent to the `crypt' function in Unix
libcs. */ libcs. */
@ -440,11 +437,9 @@ __sha512_crypt (const char *key, const char *salt)
return __sha512_crypt_r (key, salt, buffer, buflen); return __sha512_crypt_r (key, salt, buffer, buflen);
} }
#ifndef _LIBC
static void static void
__attribute__ ((__destructor__)) __attribute__ ((__destructor__))
free_mem (void) free_mem (void)
{ {
free (buffer); free (buffer);
} }
#endif

View File

@ -87,6 +87,5 @@ static struct dl_action_result *const dl_action_result_malloc_failed
reporting via dlerror. */ reporting via dlerror. */
extern __thread struct dl_action_result *__libc_dlerror_result extern __thread struct dl_action_result *__libc_dlerror_result
attribute_tls_model_ie; attribute_tls_model_ie;
void __libc_dlerror_result_free (void) attribute_hidden;
#endif /* _DLERROR_H */ #endif /* _DLERROR_H */

View File

@ -228,7 +228,7 @@ __libc_dlclose (void *map)
} }
static bool __libc_freeres_fn_section static bool
free_slotinfo (struct dtv_slotinfo_list **elemp) free_slotinfo (struct dtv_slotinfo_list **elemp)
{ {
size_t cnt; size_t cnt;
@ -256,7 +256,8 @@ free_slotinfo (struct dtv_slotinfo_list **elemp)
} }
libc_freeres_fn (free_mem) void
__dl_libc_freemem (void)
{ {
struct link_map *l; struct link_map *l;
struct r_search_path_elem *d; struct r_search_path_elem *d;

View File

@ -20,12 +20,13 @@
#include <libc-lock.h> #include <libc-lock.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <set-freeres.h>
/* We need to protect the dynamic buffer handling. */ /* We need to protect the dynamic buffer handling. */
__libc_lock_define_initialized (static, lock); __libc_lock_define_initialized (static, lock);
libc_freeres_ptr (static char *buffer); static char *buffer;
/* Read one entry from the given stream. */ /* Read one entry from the given stream. */
struct group * struct group *
@ -82,3 +83,5 @@ fgetgrent (FILE *stream)
return result; return result;
} }
weak_alias (buffer, __libc_fgetgrent_freemem_ptr)

View File

@ -20,6 +20,7 @@
#include <gshadow.h> #include <gshadow.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <set-freeres.h>
/* A reasonable size for a buffer to start with. */ /* A reasonable size for a buffer to start with. */
@ -28,7 +29,7 @@
/* We need to protect the dynamic buffer handling. */ /* We need to protect the dynamic buffer handling. */
__libc_lock_define_initialized (static, lock); __libc_lock_define_initialized (static, lock);
libc_freeres_ptr (static char *buffer); static char *buffer;
/* Read one shadow entry from the given stream. */ /* Read one shadow entry from the given stream. */
struct sgrp * struct sgrp *
@ -85,3 +86,5 @@ fgetsgent (FILE *stream)
return result; return result;
} }
weak_alias (buffer, __libc_fgetsgent_freeres_ptr);

View File

@ -449,7 +449,8 @@ __gconv_release_cache (struct __gconv_step *steps, size_t nsteps)
/* Free all resources if necessary. */ /* Free all resources if necessary. */
libc_freeres_fn (free_mem) void
__gconv_cache_freemem (void)
{ {
if (cache_malloced) if (cache_malloced)
free (gconv_cache); free (gconv_cache);

View File

@ -530,7 +530,8 @@ __gconv_load_conf (void)
/* Free all resources if necessary. */ /* Free all resources if necessary. */
libc_freeres_fn (free_mem) void
__gconv_conf_freemem (void)
{ {
if (__gconv_path_elem != NULL && __gconv_path_elem != &empty_path_elem) if (__gconv_path_elem != NULL && __gconv_path_elem != &empty_path_elem)
free ((void *) __gconv_path_elem); free ((void *) __gconv_path_elem);

View File

@ -169,7 +169,7 @@ add_derivation (const char *fromset, const char *toset,
not all memory will be freed. */ not all memory will be freed. */
} }
static void __libc_freeres_fn_section static void
free_derivation (void *p) free_derivation (void *p)
{ {
struct known_derivation *deriv = (struct known_derivation *) p; struct known_derivation *deriv = (struct known_derivation *) p;
@ -793,7 +793,6 @@ __gconv_close_transform (struct __gconv_step *steps, size_t nsteps)
/* Free the modules mentioned. */ /* Free the modules mentioned. */
static void static void
__libc_freeres_fn_section
free_modules_db (struct gconv_module *node) free_modules_db (struct gconv_module *node)
{ {
if (node->left != NULL) if (node->left != NULL)
@ -812,7 +811,8 @@ free_modules_db (struct gconv_module *node)
/* Free all resources if necessary. */ /* Free all resources if necessary. */
libc_freeres_fn (free_mem) void
__gconv_db_freemem (void)
{ {
/* First free locale memory. This needs to be done before freeing /* First free locale memory. This needs to be done before freeing
derivations, as ctype cleanup functions dereference steps arrays which we derivations, as ctype cleanup functions dereference steps arrays which we

View File

@ -184,7 +184,7 @@ __gconv_release_shlib (struct __gconv_loaded_object *handle)
/* We run this if we debug the memory allocation. */ /* We run this if we debug the memory allocation. */
static void __libc_freeres_fn_section static void
do_release_all (void *nodep) do_release_all (void *nodep)
{ {
struct __gconv_loaded_object *obj = (struct __gconv_loaded_object *) nodep; struct __gconv_loaded_object *obj = (struct __gconv_loaded_object *) nodep;
@ -196,7 +196,8 @@ do_release_all (void *nodep)
free (obj); free (obj);
} }
libc_freeres_fn (free_mem) void
__gconv_dl_freemem (void)
{ {
__tdestroy (loaded, do_release_all); __tdestroy (loaded, do_release_all);
loaded = NULL; loaded = NULL;

View File

@ -237,79 +237,6 @@ requires at runtime the shared libraries from the glibc version used \
for linking") for linking")
#endif #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. */
/* Resource pointers to free 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 go in this section. */
#define __libc_freeres_fn_section \
__attribute__ ((__used__, section ("__libc_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 /* Declare SYMBOL to be TYPE (`function' or `object') of SIZE bytes
alias to ORIGINAL, when the assembler supports such declarations alias to ORIGINAL, when the assembler supports such declarations
(such as in ELF). (such as in ELF).

142
include/set-freeres.h Normal file
View File

@ -0,0 +1,142 @@
/* Macros for internal resource Freeing Hooks.
Copyright (C) 2022 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/>. */
#ifndef _SET_FREERES_H
#define _SET_FREERES_H 1
#include <shlib-compat.h>
#include <printf.h>
#include <time.h>
#include <resolv/resolv-internal.h>
/* 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.
Each free routines must be explicit listed below. */
/* From libc.so. */
extern void __dl_libc_freemem (void) attribute_hidden;
extern void __hdestroy (void) attribute_hidden;
extern void __gconv_cache_freemem (void) attribute_hidden;
extern void __gconv_conf_freemem (void) attribute_hidden;
extern void __gconv_db_freemem (void) attribute_hidden;
extern void __gconv_dl_freemem (void) attribute_hidden;
extern void __intl_freemem (void) attribute_hidden;
extern void __libio_freemem (void) attribute_hidden;
extern void __libc_fstab_freemem (void) attribute_hidden;
extern void __nscd_gr_map_freemem (void) attribute_hidden;
extern void __nscd_hst_map_freemem (void) attribute_hidden;
extern void __nscd_pw_map_freemem (void) attribute_hidden;
extern void __nscd_serv_map_freemem (void) attribute_hidden;
extern void __nscd_group_map_freemem (void) attribute_hidden;
extern void __libc_regcomp_freemem (void) attribute_hidden;
extern void __libc_atfork_freemem (void) attribute_hidden;
extern void __libc_resolv_conf_freemem (void) attribute_hidden;
extern void __res_thread_freeres (void) attribute_hidden;
extern void __libc_printf_freemem (void) attribute_hidden;
extern void __libc_fmtmsg_freemem (void) attribute_hidden;
extern void __libc_setenv_freemem (void) attribute_hidden;
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_31)
extern void __rpc_freemem (void) attribute_hidden;
extern void __rpc_thread_destroy (void) attribute_hidden;
#endif
extern void __libc_getaddrinfo_freemem (void) attribute_hidden;
extern void __libc_tzset_freemem (void) attribute_hidden;
extern void __libc_localealias_freemem (void) attribute_hidden;
extern void __libc_getutent_freemem (void) attribute_hidden;
extern void __libc_getutline_freemem (void) attribute_hidden;
/* From nss/nss_module.c */
extern void __nss_module_freeres (void) attribute_hidden;
/* From nss/nss_action.c */
extern void __nss_action_freeres (void) attribute_hidden;
/* From nss/nss_database.c */
extern void __nss_database_freeres (void) attribute_hidden;
/* From libio/genops.c */
extern int _IO_cleanup (void) attribute_hidden;;
/* From dlfcn/dlerror.c */
extern void __libc_dlerror_result_free (void) attribute_hidden;
/* From either libc.so or libpthread.so */
extern void __libpthread_freeres (void) attribute_hidden;
/* From either libc.so or libanl.so */
#if PTHREAD_IN_LIBC
extern void __gai_freemem (void) attribute_hidden;
/* From either libc.so or librt.so */
extern void __aio_freemem (void) attribute_hidden;
#endif
/* From libc.so */
extern char * __libc_fgetgrent_freemem_ptr attribute_hidden;
extern char * __libc_fgetsgent_freeres_ptr attribute_hidden;
extern char * __libc_getnetgrent_freemem_ptr attribute_hidden;
extern char * __libc_rcmd_freemem_ptr attribute_hidden;
extern char * __libc_rexec_freemem_ptr attribute_hidden;
extern void * __libc_mntent_freemem_ptr attribute_hidden;
extern char * __libc_fgetpwent_freemem_ptr attribute_hidden;
extern struct netaddr * __libc_resolv_res_hconf_freemem_ptr attribute_hidden;
extern char * __libc_fgetspent_freemem_ptr attribute_hidden;
extern __time64_t * __libc_tzfile_freemem_ptr attribute_hidden;
extern char * __libc_getnameinfo_freemem_ptr attribute_hidden;
extern struct utmp * __libc_getutent_freemem_ptr attribute_hidden;
extern struct utmp * __libc_getutid_freemem_ptr attribute_hidden;
extern struct utmp * __libc_getutline_freemem_ptr attribute_hidden;
extern printf_arginfo_size_function ** __libc_reg_printf_freemem_ptr
attribute_hidden;
extern printf_va_arg_function ** __libc_reg_type_freemem_ptr
attribute_hidden;
/* From nss/getXXbyYY.c */
extern char * __libc_getgrgid_freemem_ptr attribute_hidden;
extern char * __libc_getgrnam_freemem_ptr attribute_hidden;
extern char * __libc_getpwnam_freemem_ptr attribute_hidden;
extern char * __libc_getpwuid_freemem_ptr attribute_hidden;
extern char * __libc_getspnam_freemem_ptr attribute_hidden;
extern char * __libc_getaliasbyname_freemem_ptr attribute_hidden;
extern char * __libc_gethostbyaddr_freemem_ptr attribute_hidden;
extern char * __libc_gethostbyname_freemem_ptr attribute_hidden;
extern char * __libc_gethostbyname2_freemem_ptr attribute_hidden;
extern char * __libc_getnetbyaddr_freemem_ptr attribute_hidden;
extern char * __libc_getnetbyname_freemem_ptr attribute_hidden;
extern char * __libc_getprotobynumber_freemem_ptr attribute_hidden;
extern char * __libc_getprotobyname_freemem_ptr attribute_hidden;
extern char * __libc_getrpcbyname_freemem_ptr attribute_hidden;
extern char * __libc_getrpcbynumber_freemem_ptr attribute_hidden;
extern char * __libc_getservbyname_freemem_ptr attribute_hidden;
extern char * __libc_getservbyport_freemem_ptr attribute_hidden;
/* From nss/getXXent.c */
extern char * __libc_getgrent_freemem_ptr attribute_hidden;
extern char * __libc_getpwent_freemem_ptr attribute_hidden;
extern char * __libc_getspent_freemem_ptr attribute_hidden;
extern char * __libc_getaliasent_freemem_ptr attribute_hidden;
extern char * __libc_gethostent_freemem_ptr attribute_hidden;
extern char * __libc_getnetent_freemem_ptr attribute_hidden;
extern char * __libc_getprotoent_freemem_ptr attribute_hidden;
extern char * __libc_getrpcent_freemem_ptr attribute_hidden;
extern char * __libc_getservent_freemem_ptr attribute_hidden;
/* From misc/efgcvt-template.c */
extern char * __libc_efgcvt_freemem_ptr attribute_hidden;
extern char * __libc_qefgcvt_freemem_ptr attribute_hidden;
#endif

View File

@ -72,12 +72,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <libc-lock.h> #include <libc-lock.h>
#include <scratch_buffer.h> #include <scratch_buffer.h>
#include <net-internal.h> #include <net-internal.h>
#include <set-freeres.h>
#ifndef min #ifndef min
# define min(x,y) (((x) > (y)) ? (y) : (x)) # define min(x,y) (((x) > (y)) ? (y) : (x))
#endif /* min */ #endif /* min */
libc_freeres_ptr (static char *domain); static char *domain;
/* Former NI_IDN_ALLOW_UNASSIGNED, NI_IDN_USE_STD3_ASCII_RULES flags, /* Former NI_IDN_ALLOW_UNASSIGNED, NI_IDN_USE_STD3_ASCII_RULES flags,
now ignored. */ now ignored. */
@ -556,3 +557,5 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
return 0; return 0;
} }
libc_hidden_def (getnameinfo) libc_hidden_def (getnameinfo)
weak_alias (domain, __libc_getnameinfo_freemem_ptr)

View File

@ -19,9 +19,10 @@
#include <netdb.h> #include <netdb.h>
#include <stdlib.h> #include <stdlib.h>
#include <libc-lock.h> #include <libc-lock.h>
#include <set-freeres.h>
/* Static buffer for return value. We allocate it when needed. */ /* Static buffer for return value. We allocate it when needed. */
libc_freeres_ptr (static char *buffer); static char *buffer;
/* All three strings should fit in a block of 1kB size. */ /* All three strings should fit in a block of 1kB size. */
#define BUFSIZE 1024 #define BUFSIZE 1024
@ -47,3 +48,5 @@ getnetgrent (char **hostp, char **userp, char **domainp)
return __getnetgrent_r (hostp, userp, domainp, buffer, BUFSIZE); return __getnetgrent_r (hostp, userp, domainp, buffer, BUFSIZE);
} }
weak_alias (buffer, __libc_getnetgrent_freemem_ptr)

View File

@ -80,6 +80,7 @@
#include <sys/uio.h> #include <sys/uio.h>
#include <sigsetops.h> #include <sigsetops.h>
#include <shlib-compat.h> #include <shlib-compat.h>
#include <set-freeres.h>
int __ivaliduser (FILE *, uint32_t, const char *, const char *); int __ivaliduser (FILE *, uint32_t, const char *, const char *);
@ -98,7 +99,7 @@ int iruserok (uint32_t raddr, int superuser, const char *ruser,
libc_hidden_proto (iruserok_af) libc_hidden_proto (iruserok_af)
libc_freeres_ptr(static char *ahostbuf); static char *ahostbuf;
int int
rcmd_af (char **ahost, u_short rport, const char *locuser, const char *remuser, rcmd_af (char **ahost, u_short rport, const char *locuser, const char *remuser,
@ -817,3 +818,5 @@ __validuser2_sa (FILE *hostf, struct sockaddr *ra, size_t ralen,
return retval; return retval;
} }
weak_alias (ahostbuf, __libc_rcmd_freemem_ptr)

View File

@ -40,9 +40,10 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <set-freeres.h>
int rexecoptions; int rexecoptions;
libc_freeres_ptr (static char *ahostbuf); static char *ahostbuf;
int int
rexec_af (char **ahost, int rport, const char *name, const char *pass, rexec_af (char **ahost, int rport, const char *name, const char *pass,
@ -196,3 +197,5 @@ rexec (char **ahost, int rport, const char *name, const char *pass,
{ {
return rexec_af(ahost, rport, name, pass, cmd, fd2p, AF_INET); return rexec_af(ahost, rport, name, pass, cmd, fd2p, AF_INET);
} }
weak_alias (ahostbuf, __libc_rexec_freemem_ptr)

View File

@ -1667,7 +1667,8 @@ mempcpy (void *dest, const void *src, size_t n)
#ifdef _LIBC #ifdef _LIBC
/* If we want to free all resources we have to do some work at /* If we want to free all resources we have to do some work at
program's end. */ program's end. */
libc_freeres_fn (free_mem) void
__intl_freemem (void)
{ {
void *old; void *old;

View File

@ -185,7 +185,7 @@ out:
#ifdef _LIBC #ifdef _LIBC
/* This is called from iconv/gconv_db.c's free_mem, as locales must /* This is called from iconv/gconv_db.c's free_mem, as locales must
be freed before freeing gconv steps arrays. */ be freed before freeing gconv steps arrays. */
void __libc_freeres_fn_section void
_nl_finddomain_subfreeres (void) _nl_finddomain_subfreeres (void)
{ {
struct loaded_l10nfile *runp = _nl_loaded_domains; struct loaded_l10nfile *runp = _nl_loaded_domains;

View File

@ -1284,7 +1284,6 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
#ifdef _LIBC #ifdef _LIBC
void void
__libc_freeres_fn_section
_nl_unload_domain (struct loaded_domain *domain) _nl_unload_domain (struct loaded_domain *domain)
{ {
size_t i; size_t i;

View File

@ -126,14 +126,10 @@ struct alias_map
}; };
#ifndef _LIBC static char *string_space;
# define libc_freeres_ptr(decl) decl
#endif
libc_freeres_ptr (static char *string_space);
static size_t string_space_act; static size_t string_space_act;
static size_t string_space_max; static size_t string_space_max;
libc_freeres_ptr (static struct alias_map *map); static struct alias_map *map;
static size_t nmap; static size_t nmap;
static size_t maxmap; static size_t maxmap;
@ -439,3 +435,10 @@ alias_compare (const struct alias_map *map1, const struct alias_map *map2)
return c1 - c2; return c1 - c2;
#endif #endif
} }
void
__libc_localealias_freemem (void)
{
free (string_space);
free (map);
}

View File

@ -26,6 +26,7 @@
#include "libioP.h" #include "libioP.h"
#include <stdio.h> #include <stdio.h>
#include <set-freeres.h>
int int
__fcloseall (void) __fcloseall (void)

View File

@ -765,8 +765,8 @@ weak_alias (_IO_flush_all_linebuffered, _flushlbf)
actual buffer because this will happen anyway once the program actual buffer because this will happen anyway once the program
terminated. If we do want to look for memory leaks we have to free terminated. If we do want to look for memory leaks we have to free
the buffers. Whether something is freed is determined by the the buffers. Whether something is freed is determined by the
function sin the libc_freeres section. Those are called as part of function called by __libc_freeres (those are not called as part of
the atexit routine, just like _IO_cleanup. The problem is we do the atexit routine, different from _IO_cleanup). The problem is we do
not know whether the freeres code is called first or _IO_cleanup. not know whether the freeres code is called first or _IO_cleanup.
if the former is the case, we set the DEALLOC_BUFFER variable to if the former is the case, we set the DEALLOC_BUFFER variable to
true and _IO_unbuffer_all will take care of the rest. If true and _IO_unbuffer_all will take care of the rest. If
@ -844,8 +844,8 @@ _IO_unbuffer_all (void)
#endif #endif
} }
void
libc_freeres_fn (buffer_free) __libio_freemem (void)
{ {
dealloc_buffers = true; dealloc_buffers = true;

View File

@ -491,7 +491,6 @@ libc_hidden_proto (_IO_wdo_write)
extern int _IO_flush_all_lockp (int); extern int _IO_flush_all_lockp (int);
extern int _IO_flush_all (void); extern int _IO_flush_all (void);
libc_hidden_proto (_IO_flush_all) libc_hidden_proto (_IO_flush_all)
extern int _IO_cleanup (void);
extern void _IO_flush_all_linebuffered (void); extern void _IO_flush_all_linebuffered (void);
libc_hidden_proto (_IO_flush_all_linebuffered) libc_hidden_proto (_IO_flush_all_linebuffered)
extern int _IO_new_fgetpos (FILE *, __fpos_t *); extern int _IO_new_fgetpos (FILE *, __fpos_t *);

View File

@ -498,7 +498,7 @@ _nl_load_locale_from_archive (int category, const char **namep)
return lia->data[category]; return lia->data[category];
} }
void __libc_freeres_fn_section void
_nl_archive_subfreeres (void) _nl_archive_subfreeres (void)
{ {
struct locale_in_archive *lia; struct locale_in_archive *lia;

View File

@ -381,10 +381,10 @@ extern struct __locale_data *_nl_load_locale_from_archive (int category,
const char **namep) const char **namep)
attribute_hidden; attribute_hidden;
/* Subroutine of setlocale's __libc_subfreeres hook. */ /* Subroutine of setlocale's free resource. */
extern void _nl_archive_subfreeres (void) attribute_hidden; extern void _nl_archive_subfreeres (void) attribute_hidden;
/* Subroutine of gconv-db's __libc_subfreeres hook. */ /* Subroutine of gconv-db's free resource. */
extern void _nl_locale_subfreeres (void) attribute_hidden; extern void _nl_locale_subfreeres (void) attribute_hidden;
/* Validate the contents of a locale file and set up the in-core /* Validate the contents of a locale file and set up the in-core

View File

@ -468,7 +468,7 @@ setlocale (int category, const char *locale)
} }
libc_hidden_def (setlocale) libc_hidden_def (setlocale)
static void __libc_freeres_fn_section static void
free_category (int category, free_category (int category,
struct __locale_data *here, struct __locale_data *c_data) struct __locale_data *here, struct __locale_data *c_data)
{ {
@ -498,7 +498,7 @@ free_category (int category,
/* This is called from iconv/gconv_db.c's free_mem, as locales must /* This is called from iconv/gconv_db.c's free_mem, as locales must
be freed before freeing gconv steps arrays. */ be freed before freeing gconv steps arrays. */
void __libc_freeres_fn_section void
_nl_locale_subfreeres (void) _nl_locale_subfreeres (void)
{ {
#ifdef NL_CURRENT_INDIRECT #ifdef NL_CURRENT_INDIRECT

View File

@ -17,10 +17,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <utmp.h> #include <utmp.h>
#include <set-freeres.h>
/* Local buffer to store the result. */ /* Local buffer to store the result. */
libc_freeres_ptr (static struct utmp *buffer); static struct utmp *buffer;
struct utmp * struct utmp *
@ -42,3 +43,5 @@ __getutent (void)
} }
libc_hidden_def (__getutent) libc_hidden_def (__getutent)
weak_alias (__getutent, getutent) weak_alias (__getutent, getutent)
weak_alias (buffer, __libc_getutent_freemem_ptr)

View File

@ -17,10 +17,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <utmp.h> #include <utmp.h>
#include <set-freeres.h>
/* Local buffer to store the result. */ /* Local buffer to store the result. */
libc_freeres_ptr (static struct utmp *buffer); static struct utmp *buffer;
struct utmp * struct utmp *
__getutid (const struct utmp *id) __getutid (const struct utmp *id)
@ -40,3 +40,5 @@ __getutid (const struct utmp *id)
} }
libc_hidden_def (__getutid) libc_hidden_def (__getutid)
weak_alias (__getutid, getutid) weak_alias (__getutid, getutid)
weak_alias (buffer, __libc_getutid_freemem_ptr)

View File

@ -17,10 +17,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <utmp.h> #include <utmp.h>
#include <set-freeres.h>
/* Local buffer to store the result. */ /* Local buffer to store the result. */
libc_freeres_ptr (static struct utmp *buffer); static struct utmp *buffer;
struct utmp * struct utmp *
@ -41,3 +42,5 @@ __getutline (const struct utmp *line)
} }
libc_hidden_def (__getutline) libc_hidden_def (__getutline)
weak_alias (__getutline, getutline) weak_alias (__getutline, getutline)
weak_alias (buffer, __libc_getutline_freemem_ptr)

View File

@ -15,32 +15,62 @@
License along with the GNU C Library; if not, see License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */ <https://www.gnu.org/licenses/>. */
#include <array_length.h>
#include <atomic.h> #include <atomic.h>
#include <stdlib.h> #include <stdlib.h>
#include <set-hooks.h>
#include <libc-internal.h> #include <libc-internal.h>
#include <unwind-link.h> #include <unwind-link.h>
#include <dlfcn/dlerror.h>
#include <ldsodefs.h> #include <ldsodefs.h>
#include <set-freeres.h>
#include <set-freeres-system.h>
#include "../nss/nsswitch.h" #ifndef SHARED
#include "../libio/libioP.h" # pragma weak __nss_module_freeres
# pragma weak __nss_action_freeres
DEFINE_HOOK (__libc_subfreeres, (void)); # pragma weak __nss_database_freeres
# pragma weak __dl_libc_freemem
symbol_set_define (__libc_freeres_ptrs); # pragma weak __hdestroy
# pragma weak __gconv_cache_freemem
extern void __libpthread_freeres (void) # pragma weak __gconv_conf_freemem
#if PTHREAD_IN_LIBC && defined SHARED # pragma weak __gconv_db_freemem
/* It is possible to call __libpthread_freeres directly in shared # pragma weak __gconv_dl_freemem
builds with an integrated libpthread. */ # pragma weak __intl_freemem
attribute_hidden # pragma weak __libio_freemem
#else # pragma weak __libc_fstab_freemem
__attribute__ ((weak)) # pragma weak __nscd_gr_map_freemem
# pragma weak __nscd_hst_map_freemem
# pragma weak __nscd_pw_map_freemem
# pragma weak __nscd_serv_map_freemem
# pragma weak __nscd_group_map_freemem
# pragma weak __libc_regcomp_freemem
# pragma weak __libc_atfork_freemem
# pragma weak __res_thread_freeres
# pragma weak __libc_resolv_conf_freemem
# pragma weak __libc_printf_freemem
# pragma weak __libc_fmtmsg_freemem
# pragma weak __libc_setenv_freemem
# pragma weak __rpc_freemem
# pragma weak __rpc_thread_destroy
# pragma weak __libc_getaddrinfo_freemem
# pragma weak __libc_tzset_freemem
# pragma weak __libc_localealias_freemem
# pragma weak __gai_freemem
# pragma weak __aio_freemem
# pragma weak __libpthread_freeres
# pragma weak __libc_dlerror_result_free
# pragma weak __check_pf_freemem
#endif #endif
;
void __libc_freeres_fn_section #ifdef SHARED
# define call_free_static_weak(__ptr) \
free (__ptr)
#else
# define call_free_static_weak(__ptr) \
if (&__ptr != NULL) \
free (__ptr);
#endif
void
__libc_freeres (void) __libc_freeres (void)
{ {
/* This function might be called from different places. So better /* This function might be called from different places. So better
@ -49,8 +79,6 @@ __libc_freeres (void)
if (!atomic_compare_and_exchange_bool_acq (&already_called, 1, 0)) if (!atomic_compare_and_exchange_bool_acq (&already_called, 1, 0))
{ {
void *const *p;
call_function_static_weak (__nss_module_freeres); call_function_static_weak (__nss_module_freeres);
call_function_static_weak (__nss_action_freeres); call_function_static_weak (__nss_action_freeres);
call_function_static_weak (__nss_database_freeres); call_function_static_weak (__nss_database_freeres);
@ -58,7 +86,43 @@ __libc_freeres (void)
_IO_cleanup (); _IO_cleanup ();
/* We run the resource freeing after IO cleanup. */ /* We run the resource freeing after IO cleanup. */
RUN_HOOK (__libc_subfreeres, ()); call_function_static_weak (__dl_libc_freemem);
call_function_static_weak (__hdestroy);
call_function_static_weak (__gconv_cache_freemem);
call_function_static_weak (__gconv_conf_freemem);
call_function_static_weak (__gconv_db_freemem);
call_function_static_weak (__gconv_dl_freemem);
call_function_static_weak (__intl_freemem);
call_function_static_weak (__libio_freemem);
call_function_static_weak (__libc_fstab_freemem);
call_function_static_weak (__nscd_gr_map_freemem);
call_function_static_weak (__nscd_hst_map_freemem);
call_function_static_weak (__nscd_pw_map_freemem);
call_function_static_weak (__nscd_serv_map_freemem);
call_function_static_weak (__nscd_group_map_freemem);
call_function_static_weak (__libc_regcomp_freemem);
call_function_static_weak (__libc_atfork_freemem);
/* __res_thread_freeres deallocates the per-thread resolv_context);
which in turn drop the reference count of the current global object.
So it need to be before __libc_resolv_conf_freemem. */
call_function_static_weak (__res_thread_freeres);
call_function_static_weak (__libc_resolv_conf_freemem);
call_function_static_weak (__libc_printf_freemem);
call_function_static_weak (__libc_fmtmsg_freemem);
call_function_static_weak (__libc_setenv_freemem);
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_31)
call_function_static_weak (__rpc_freemem);
call_function_static_weak (__rpc_thread_destroy);
#endif
call_function_static_weak (__libc_getaddrinfo_freemem);
call_function_static_weak (__libc_tzset_freemem);
call_function_static_weak (__libc_localealias_freemem);
#if PTHREAD_IN_LIBC
call_function_static_weak (__gai_freemem);
call_function_static_weak (__aio_freemem);
#endif
call_function_static_weak (__libpthread_freeres); call_function_static_weak (__libpthread_freeres);
@ -72,9 +136,55 @@ __libc_freeres (void)
GLRO (dl_libc_freeres) (); GLRO (dl_libc_freeres) ();
#endif #endif
for (p = symbol_set_first_element (__libc_freeres_ptrs); call_free_static_weak (__libc_fgetgrent_freemem_ptr);
!symbol_set_end_p (__libc_freeres_ptrs, p); ++p) call_free_static_weak (__libc_fgetsgent_freeres_ptr);
free (*p); call_free_static_weak (__libc_getnetgrent_freemem_ptr);
call_free_static_weak (__libc_rcmd_freemem_ptr);
call_free_static_weak (__libc_rexec_freemem_ptr);
call_free_static_weak (__libc_mntent_freemem_ptr);
call_free_static_weak (__libc_fgetpwent_freemem_ptr);
call_free_static_weak (__libc_resolv_res_hconf_freemem_ptr);
call_free_static_weak (__libc_fgetspent_freemem_ptr);
call_free_static_weak (__libc_tzfile_freemem_ptr);
call_free_static_weak (__libc_getnameinfo_freemem_ptr);
call_free_static_weak (__libc_getutent_freemem_ptr);
call_free_static_weak (__libc_getutid_freemem_ptr);
call_free_static_weak (__libc_getutline_freemem_ptr);
call_free_static_weak (__libc_reg_printf_freemem_ptr);
call_free_static_weak (__libc_reg_type_freemem_ptr);
call_free_static_weak (__libc_getgrgid_freemem_ptr);
call_free_static_weak (__libc_getgrnam_freemem_ptr);
call_free_static_weak (__libc_getpwnam_freemem_ptr);
call_free_static_weak (__libc_getpwuid_freemem_ptr);
call_free_static_weak (__libc_getspnam_freemem_ptr);
call_free_static_weak (__libc_getaliasbyname_freemem_ptr);
call_free_static_weak (__libc_gethostbyaddr_freemem_ptr);
call_free_static_weak (__libc_gethostbyname_freemem_ptr);
call_free_static_weak (__libc_gethostbyname2_freemem_ptr);
call_free_static_weak (__libc_getnetbyaddr_freemem_ptr);
call_free_static_weak (__libc_getnetbyname_freemem_ptr);
call_free_static_weak (__libc_getprotobynumber_freemem_ptr);
call_free_static_weak (__libc_getprotobyname_freemem_ptr);
call_free_static_weak (__libc_getrpcbyname_freemem_ptr);
call_free_static_weak (__libc_getrpcbynumber_freemem_ptr);
call_free_static_weak (__libc_getservbyname_freemem_ptr);
call_free_static_weak (__libc_getservbyport_freemem_ptr);
call_free_static_weak (__libc_getgrent_freemem_ptr);
call_free_static_weak (__libc_getpwent_freemem_ptr);
call_free_static_weak (__libc_getspent_freemem_ptr);
call_free_static_weak (__libc_getaliasent_freemem_ptr);
call_free_static_weak (__libc_gethostent_freemem_ptr);
call_free_static_weak (__libc_getnetent_freemem_ptr);
call_free_static_weak (__libc_getprotoent_freemem_ptr);
call_free_static_weak (__libc_getrpcent_freemem_ptr);
call_free_static_weak (__libc_getservent_freemem_ptr);
call_free_static_weak (__libc_efgcvt_freemem_ptr);
call_free_static_weak (__libc_qefgcvt_freemem_ptr);
call_freeres_system_funcs;
} }
} }
libc_hidden_def (__libc_freeres) libc_hidden_def (__libc_freeres)

View File

@ -16,18 +16,15 @@
License along with the GNU C Library; if not, see License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */ <https://www.gnu.org/licenses/>. */
#include <dlfcn/dlerror.h>
#include <libc-internal.h> #include <libc-internal.h>
#include <malloc-internal.h> #include <malloc-internal.h>
#include <resolv/resolv-internal.h> #include <set-freeres.h>
#include <rpc/rpc.h>
#include <string.h>
#include <tls-internal.h>
#include <shlib-compat.h> #include <shlib-compat.h>
#include <tls-internal.h>
/* Thread shutdown function. Note that this function must be called /* Thread shutdown function. Note that this function must be called
for threads during shutdown for correctness reasons. Unlike for threads during shutdown for correctness reasons. Unlike
__libc_subfreeres, skipping calls to it is not a valid optimization. __libc_freeres, skipping calls to it is not a valid optimization.
This is called directly from pthread_create as the thread exits. */ This is called directly from pthread_create as the thread exits. */
void void
__libc_thread_freeres (void) __libc_thread_freeres (void)

View File

@ -22,6 +22,7 @@
#include <sys/param.h> #include <sys/param.h>
#include <libc-lock.h> #include <libc-lock.h>
#include <math_ldbl_opt.h> #include <math_ldbl_opt.h>
#include <set-freeres.h>
#ifndef SPRINTF #ifndef SPRINTF
# define SPRINTF sprintf # define SPRINTF sprintf
@ -38,7 +39,7 @@
static char FCVT_BUFFER[MAXDIG]; static char FCVT_BUFFER[MAXDIG];
static char ECVT_BUFFER[MAXDIG]; static char ECVT_BUFFER[MAXDIG];
libc_freeres_ptr (static char *FCVT_BUFPTR); static char *FCVT_BUFPTR;
char * char *
__FCVT (FLOAT_TYPE value, int ndigit, int *decpt, int *sign) __FCVT (FLOAT_TYPE value, int ndigit, int *decpt, int *sign)
@ -73,3 +74,5 @@ __GCVT (FLOAT_TYPE value, int ndigit, char *buf)
SPRINTF (buf, "%.*" FLOAT_FMT_FLAG "g", MIN (ndigit, NDIGIT_MAX), value); SPRINTF (buf, "%.*" FLOAT_FMT_FLAG "g", MIN (ndigit, NDIGIT_MAX), value);
return buf; return buf;
} }
weak_alias (FCVT_BUFPTR, __EFGCVT_FREEMEM_PTR);

View File

@ -24,6 +24,7 @@
#define __GCVT __gcvt #define __GCVT __gcvt
#define __ECVT_R __ecvt_r #define __ECVT_R __ecvt_r
#define __FCVT_R __fcvt_r #define __FCVT_R __fcvt_r
#define __EFGCVT_FREEMEM_PTR __libc_efgcvt_freemem_ptr
#include <efgcvt-dbl-macros.h> #include <efgcvt-dbl-macros.h>
#include <efgcvt-template.c> #include <efgcvt-template.c>

View File

@ -177,7 +177,8 @@ fstab_convert (struct fstab_state *state)
/* Make sure the memory is freed if the programs ends while in /* Make sure the memory is freed if the programs ends while in
memory-debugging mode and something actually was allocated. */ memory-debugging mode and something actually was allocated. */
libc_freeres_fn (fstab_free) void
__libc_fstab_freemem (void)
{ {
char *buffer; char *buffer;

View File

@ -46,7 +46,3 @@ __hdestroy (void)
__hdestroy_r (&htab); __hdestroy_r (&htab);
} }
weak_alias (__hdestroy, hdestroy) weak_alias (__hdestroy, hdestroy)
/* Make sure the table is freed if we want to free everything before
exiting. */
text_set_element (__libc_subfreeres, __hdestroy);

View File

@ -19,6 +19,7 @@
#include <mntent.h> #include <mntent.h>
#include <stdlib.h> #include <stdlib.h>
#include <allocate_once.h> #include <allocate_once.h>
#include <set-freeres.h>
struct mntent_buffer struct mntent_buffer
{ {
@ -28,7 +29,7 @@ struct mntent_buffer
/* We don't want to allocate the static buffer all the time since it /* We don't want to allocate the static buffer all the time since it
is not always used (in fact, rather infrequently). */ is not always used (in fact, rather infrequently). */
libc_freeres_ptr (static void *mntent_buffer); static void *mntent_buffer;
static void * static void *
allocate (void *closure) allocate (void *closure)
@ -56,3 +57,5 @@ getmntent (FILE *stream)
return __getmntent_r (stream, &buffer->m, return __getmntent_r (stream, &buffer->m,
buffer->buffer, sizeof (buffer->buffer)); buffer->buffer, sizeof (buffer->buffer));
} }
weak_alias (mntent_buffer, __libc_mntent_freemem_ptr)

View File

@ -24,6 +24,7 @@
#define __GCVT __qgcvt #define __GCVT __qgcvt
#define __ECVT_R __qecvt_r #define __ECVT_R __qecvt_r
#define __FCVT_R __qfcvt_r #define __FCVT_R __qfcvt_r
#define __EFGCVT_FREEMEM_PTR __libc_qefgcvt_freemem_ptr
#include <efgcvt-ldbl-macros.h> #include <efgcvt-ldbl-macros.h>
#include <efgcvt-template.c> #include <efgcvt-template.c>

View File

@ -131,7 +131,7 @@ __libc_unwind_link_after_fork (void)
} }
} }
void __libc_freeres_fn_section void
__libc_unwind_link_freeres (void) __libc_unwind_link_freeres (void)
{ {
if (global_libgcc_handle != NULL) if (global_libgcc_handle != NULL)

View File

@ -16,7 +16,6 @@
License along with the GNU C Library; if not, see License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */ <https://www.gnu.org/licenses/>. */
#include <set-hooks.h>
#include <libc-symbols.h> #include <libc-symbols.h>
#include <pthreadP.h> #include <pthreadP.h>
#include <nptl-stack.h> #include <nptl-stack.h>

View File

@ -68,7 +68,8 @@ libc_locked_map_ptr (,__gr_map_handle) attribute_hidden;
/* Note that we only free the structure if necessary. The memory /* Note that we only free the structure if necessary. The memory
mapping is not removed since it is not visible to the malloc mapping is not removed since it is not visible to the malloc
handling. */ handling. */
libc_freeres_fn (gr_map_free) void
__nscd_gr_map_freemem (void)
{ {
if (__gr_map_handle.mapped != NO_MAPPING) if (__gr_map_handle.mapped != NO_MAPPING)
{ {

View File

@ -81,7 +81,8 @@ libc_locked_map_ptr (, __hst_map_handle) attribute_hidden;
/* Note that we only free the structure if necessary. The memory /* Note that we only free the structure if necessary. The memory
mapping is not removed since it is not visible to the malloc mapping is not removed since it is not visible to the malloc
handling. */ handling. */
libc_freeres_fn (hst_map_free) void
__nscd_hst_map_freemem (void)
{ {
if (__hst_map_handle.mapped != NO_MAPPING) if (__hst_map_handle.mapped != NO_MAPPING)
{ {

View File

@ -67,7 +67,8 @@ libc_locked_map_ptr (static, map_handle);
/* Note that we only free the structure if necessary. The memory /* Note that we only free the structure if necessary. The memory
mapping is not removed since it is not visible to the malloc mapping is not removed since it is not visible to the malloc
handling. */ handling. */
libc_freeres_fn (pw_map_free) void
__nscd_pw_map_freemem (void)
{ {
if (map_handle.mapped != NO_MAPPING) if (map_handle.mapped != NO_MAPPING)
{ {

View File

@ -62,7 +62,8 @@ libc_locked_map_ptr (, __serv_map_handle) attribute_hidden;
/* Note that we only free the structure if necessary. The memory /* Note that we only free the structure if necessary. The memory
mapping is not removed since it is not visible to the malloc mapping is not removed since it is not visible to the malloc
handling. */ handling. */
libc_freeres_fn (serv_map_free) void
__nscd_serv_map_freemem (void)
{ {
if (__serv_map_handle.mapped != NO_MAPPING) if (__serv_map_handle.mapped != NO_MAPPING)
{ {

View File

@ -31,7 +31,8 @@ libc_locked_map_ptr (static, map_handle);
/* Note that we only free the structure if necessary. The memory /* Note that we only free the structure if necessary. The memory
mapping is not removed since it is not visible to the malloc mapping is not removed since it is not visible to the malloc
handling. */ handling. */
libc_freeres_fn (pw_map_free) void
__nscd_group_map_freemem (void)
{ {
if (map_handle.mapped != NO_MAPPING) if (map_handle.mapped != NO_MAPPING)
{ {

View File

@ -20,6 +20,7 @@
#include <libc-lock.h> #include <libc-lock.h>
#include <stdlib.h> #include <stdlib.h>
#include <resolv.h> #include <resolv.h>
#include <set-freeres.h>
#include "nsswitch.h" #include "nsswitch.h"
@ -58,6 +59,9 @@
#define APPEND_R1(name) name##_r #define APPEND_R1(name) name##_r
#define INTERNAL(name) INTERNAL1 (name) #define INTERNAL(name) INTERNAL1 (name)
#define INTERNAL1(name) __##name #define INTERNAL1(name) __##name
#define APPEND_FREEMEM_NAME1(name) __libc_##name##_freemem_ptr
#define APPEND_FREEMEM_NAME(name) APPEND_FREEMEM_NAME1(name)
#define FREEMEM_NAME APPEND_FREEMEM_NAME (FUNCTION_NAME)
/* Sometimes we need to store error codes in the `h_errno' variable. */ /* Sometimes we need to store error codes in the `h_errno' variable. */
#ifdef NEED_H_ERRNO #ifdef NEED_H_ERRNO
@ -86,8 +90,9 @@ extern int INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf,
__libc_lock_define_initialized (static, lock); __libc_lock_define_initialized (static, lock);
/* This points to the static buffer used. */ /* This points to the static buffer used. */
libc_freeres_ptr (static char *buffer); static char *buffer;
weak_alias (buffer, FREEMEM_NAME)
LOOKUP_TYPE * LOOKUP_TYPE *
FUNCTION_NAME (ADD_PARAMS) FUNCTION_NAME (ADD_PARAMS)

View File

@ -18,6 +18,7 @@
#include <errno.h> #include <errno.h>
#include <libc-lock.h> #include <libc-lock.h>
#include <stdlib.h> #include <stdlib.h>
#include <set-freeres.h>
#include "nsswitch.h" #include "nsswitch.h"
@ -43,6 +44,9 @@
#define APPEND_R1(name) name##_r #define APPEND_R1(name) name##_r
#define INTERNAL(name) INTERNAL1 (name) #define INTERNAL(name) INTERNAL1 (name)
#define INTERNAL1(name) __##name #define INTERNAL1(name) __##name
#define APPEND_FREEMEM_NAME1(name) __libc_##name##_freemem_ptr
#define APPEND_FREEMEM_NAME(name) APPEND_FREEMEM_NAME1(name)
#define FREEMEM_NAME APPEND_FREEMEM_NAME (GETFUNC_NAME)
/* Sometimes we need to store error codes in the `h_errno' variable. */ /* Sometimes we need to store error codes in the `h_errno' variable. */
#ifdef NEED_H_ERRNO #ifdef NEED_H_ERRNO
@ -62,8 +66,9 @@ extern int INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer,
__libc_lock_define_initialized (static, lock); __libc_lock_define_initialized (static, lock);
/* This points to the static buffer used. */ /* This points to the static buffer used. */
libc_freeres_ptr (static char *buffer); static char *buffer;
weak_alias (buffer, FREEMEM_NAME)
LOOKUP_TYPE * LOOKUP_TYPE *
GETFUNC_NAME (void) GETFUNC_NAME (void)

View File

@ -102,7 +102,7 @@ __nss_action_allocate (struct nss_action *actions, size_t count)
return result; return result;
} }
void __libc_freeres_fn_section void
__nss_action_freeres (void) __nss_action_freeres (void)
{ {
struct nss_action_list_wrapper *current = nss_actions; struct nss_action_list_wrapper *current = nss_actions;

View File

@ -101,8 +101,5 @@ nss_action_list __nss_action_allocate (struct nss_action *actions,
EINVAL means that LINE is syntactically invalid. */ EINVAL means that LINE is syntactically invalid. */
nss_action_list __nss_action_parse (const char *line); nss_action_list __nss_action_parse (const char *line);
/* Called from __libc_freeres. */
void __nss_action_freeres (void) attribute_hidden;
#endif /* _NSS_ACTION_H */ #endif /* _NSS_ACTION_H */

View File

@ -495,7 +495,7 @@ __nss_database_get_noreload (enum nss_database db)
return result; return result;
} }
void __libc_freeres_fn_section void
__nss_database_freeres (void) __nss_database_freeres (void)
{ {
free (global_database_state); free (global_database_state);

View File

@ -64,9 +64,6 @@ libc_hidden_proto (__nss_database_get)
nss_action_list __nss_database_get_noreload (enum nss_database db) nss_action_list __nss_database_get_noreload (enum nss_database db)
attribute_hidden; attribute_hidden;
/* Called from __libc_freeres. */
void __nss_database_freeres (void) attribute_hidden;
/* Internal type. Exposed only for fork handling purposes. */ /* Internal type. Exposed only for fork handling purposes. */
struct nss_database_data struct nss_database_data
{ {

View File

@ -416,7 +416,7 @@ __nss_module_disable_loading (void)
__libc_lock_unlock (nss_module_list_lock); __libc_lock_unlock (nss_module_list_lock);
} }
void __libc_freeres_fn_section void
__nss_module_freeres (void) __nss_module_freeres (void)
{ {
struct nss_module *current = nss_module_list; struct nss_module *current = nss_module_list;

View File

@ -100,7 +100,4 @@ void *__nss_module_get_function (struct nss_module *module, const char *name)
/* Block attempts to dlopen any module we haven't already opened. */ /* Block attempts to dlopen any module we haven't already opened. */
void __nss_module_disable_loading (void); void __nss_module_disable_loading (void);
/* Called from __libc_freeres. */
void __nss_module_freeres (void) attribute_hidden;
#endif /* NSS_MODULE_H */ #endif /* NSS_MODULE_H */

View File

@ -710,7 +710,8 @@ re_comp (const char *s)
} }
#ifdef _LIBC #ifdef _LIBC
libc_freeres_fn (free_mem) void
__libc_regcomp_freemem (void)
{ {
__regfree (&re_comp_buf); __regfree (&re_comp_buf);
} }

View File

@ -217,7 +217,8 @@ __run_postfork_handlers (enum __run_fork_handler_type who, _Bool do_locking,
} }
libc_freeres_fn (free_mem) void
__libc_atfork_freemem (void)
{ {
lll_lock (atfork_lock, LLL_PRIVATE); lll_lock (atfork_lock, LLL_PRIVATE);

View File

@ -20,12 +20,13 @@
#include <pwd.h> #include <pwd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <set-freeres.h>
/* We need to protect the dynamic buffer handling. */ /* We need to protect the dynamic buffer handling. */
__libc_lock_define_initialized (static, lock); __libc_lock_define_initialized (static, lock);
libc_freeres_ptr (static char *buffer); static char *buffer;
/* Read one entry from the given stream. */ /* Read one entry from the given stream. */
struct passwd * struct passwd *
@ -82,3 +83,5 @@ fgetpwent (FILE *stream)
return result; return result;
} }
weak_alias (buffer, __libc_fgetpwent_freemem_ptr)

View File

@ -434,7 +434,11 @@ handle_requests (void *arg)
/* Free allocated resources. */ /* Free allocated resources. */
libc_freeres_fn (free_res) #if !PTHREAD_IN_LIBC
__attribute__ ((__destructor__)) static
#endif
void
__gai_freemem (void)
{ {
size_t row; size_t row;

View File

@ -140,5 +140,3 @@ __res_thread_freeres (void)
/* Make sure we do a full re-initialization the next time. */ /* Make sure we do a full re-initialization the next time. */
_res.options = 0; _res.options = 0;
} }
/* Also must be called when the main thread exits. */
text_set_element (__libc_subfreeres, __res_thread_freeres);

View File

@ -42,6 +42,7 @@
#include "res_hconf.h" #include "res_hconf.h"
#include <wchar.h> #include <wchar.h>
#include <atomic.h> #include <atomic.h>
#include <set-freeres.h>
#if IS_IN (libc) #if IS_IN (libc)
# define fgets_unlocked __fgets_unlocked # define fgets_unlocked __fgets_unlocked
@ -330,19 +331,8 @@ _res_hconf_init (void)
#if IS_IN (libc) #if IS_IN (libc)
# if defined SIOCGIFCONF && defined SIOCGIFNETMASK # if defined SIOCGIFCONF && defined SIOCGIFNETMASK
/* List of known interfaces. */ /* List of known interfaces. */
libc_freeres_ptr ( static struct netaddr *ifaddrs;
static struct netaddr weak_alias (ifaddrs, __libc_resolv_res_hconf_freemem_ptr)
{
int addrtype;
union
{
struct
{
uint32_t addr;
uint32_t mask;
} ipv4;
} u;
} *ifaddrs);
# endif # endif
/* Reorder addresses returned in a hostent such that the first address /* Reorder addresses returned in a hostent such that the first address

View File

@ -34,6 +34,20 @@
loads and stores. */ loads and stores. */
typedef HEADER __attribute__ ((__aligned__(1))) UHEADER; typedef HEADER __attribute__ ((__aligned__(1))) UHEADER;
/* List of known interfaces. */
struct netaddr
{
int addrtype;
union
{
struct
{
uint32_t addr;
uint32_t mask;
} ipv4;
} u;
};
/* Legacy function. This needs to be removed once all NSS modules /* Legacy function. This needs to be removed once all NSS modules
have been adjusted. */ have been adjusted. */
static inline bool static inline bool

View File

@ -654,7 +654,8 @@ __resolv_conf_detach (struct __res_state *resp)
} }
/* Deallocate the global data. */ /* Deallocate the global data. */
libc_freeres_fn (freeres) void
__libc_resolv_conf_freemem (void)
{ {
/* No locking because this function is supposed to be called when /* No locking because this function is supposed to be called when
the process has turned single-threaded. */ the process has turned single-threaded. */

View File

@ -23,6 +23,8 @@
#include <resolv.h> #include <resolv.h>
#include <support/check.h> #include <support/check.h>
void __libc_freeres (void);
static int static int
do_test (void) do_test (void)
{ {

View File

@ -694,7 +694,11 @@ handle_fildes_io (void *arg)
/* Free allocated resources. */ /* Free allocated resources. */
libc_freeres_fn (free_res) #if !PTHREAD_IN_LIBC
__attribute__ ((__destructor__)) static
#endif
void
__aio_freemem (void)
{ {
size_t row; size_t row;

View File

@ -20,6 +20,7 @@
#include <shadow.h> #include <shadow.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <set-freeres.h>
/* A reasonable size for a buffer to start with. */ /* A reasonable size for a buffer to start with. */
@ -28,7 +29,7 @@
/* We need to protect the dynamic buffer handling. */ /* We need to protect the dynamic buffer handling. */
__libc_lock_define_initialized (static, lock); __libc_lock_define_initialized (static, lock);
libc_freeres_ptr (static char *buffer); static char *buffer;
/* Read one shadow entry from the given stream. */ /* Read one shadow entry from the given stream. */
struct spwd * struct spwd *
@ -85,3 +86,5 @@ fgetspent (FILE *stream)
return result; return result;
} }
weak_alias (buffer, __libc_fgetspent_freemem_ptr);

View File

@ -183,7 +183,8 @@ __handle_registered_modifier_wc (const unsigned int **format,
} }
libc_freeres_fn (free_mem) void
__libc_printf_freemem (void)
{ {
if (__printf_modifier_table != NULL) if (__printf_modifier_table != NULL)
{ {

View File

@ -21,11 +21,11 @@
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <libc-lock.h> #include <libc-lock.h>
#include <set-freeres.h>
/* Array of functions indexed by format character. */ /* Array of functions indexed by format character. */
libc_freeres_ptr (printf_arginfo_size_function **__printf_arginfo_table) printf_arginfo_size_function **__printf_arginfo_table attribute_hidden;
attribute_hidden;
printf_function **__printf_function_table attribute_hidden; printf_function **__printf_function_table attribute_hidden;
__libc_lock_define_initialized (static, lock) __libc_lock_define_initialized (static, lock)
@ -79,3 +79,5 @@ __register_printf_function (int spec, printf_function converter,
(printf_arginfo_size_function*) arginfo); (printf_arginfo_size_function*) arginfo);
} }
weak_alias (__register_printf_function, register_printf_function) weak_alias (__register_printf_function, register_printf_function)
weak_alias (__printf_arginfo_table, __libc_reg_printf_freemem_ptr)

View File

@ -19,11 +19,11 @@
#include <printf.h> #include <printf.h>
#include <stdlib.h> #include <stdlib.h>
#include <libc-lock.h> #include <libc-lock.h>
#include <set-freeres.h>
/* Array of functions indexed by format character. */ /* Array of functions indexed by format character. */
libc_freeres_ptr (printf_va_arg_function **__printf_va_arg_table) printf_va_arg_function **__printf_va_arg_table attribute_hidden;
attribute_hidden;
__libc_lock_define_initialized (static, lock); __libc_lock_define_initialized (static, lock);
@ -59,3 +59,5 @@ __register_printf_type (printf_va_arg_function fct)
return result; return result;
} }
weak_alias (__register_printf_type, register_printf_type) weak_alias (__register_printf_type, register_printf_type)
weak_alias (__printf_va_arg_table, __libc_reg_type_freemem_ptr)

View File

@ -20,7 +20,7 @@
#include <unistd.h> #include <unistd.h>
#include <pointer_guard.h> #include <pointer_guard.h>
#include <libc-lock.h> #include <libc-lock.h>
#include <libio/libioP.h> #include <set-freeres.h>
#include "exit.h" #include "exit.h"
/* Initialize the flag that indicates exit function processing /* Initialize the flag that indicates exit function processing

View File

@ -361,7 +361,8 @@ __addseverity (int severity, const char *string)
weak_alias (__addseverity, addseverity) weak_alias (__addseverity, addseverity)
libc_freeres_fn (free_mem) void
__libc_fmtmsg_freemem (void)
{ {
struct severity_info *runp = severity_list; struct severity_info *runp = severity_list;

View File

@ -323,7 +323,8 @@ clearenv (void)
return 0; return 0;
} }
#ifdef _LIBC #ifdef _LIBC
libc_freeres_fn (free_mem) void
__libc_setenv_freemem (void)
{ {
/* Remove all traces. */ /* Remove all traces. */
clearenv (); clearenv ();

View File

@ -389,8 +389,8 @@ auth_errmsg (enum auth_stat stat)
} }
libc_freeres_fn (free_mem) void
__rpc_freemem (void)
{ {
/* Not libc_freeres_ptr, since buf is a macro. */
free (buf); free (buf);
} }

View File

@ -37,7 +37,6 @@ __rpc_thread_destroy (void)
thread_rpc_vars = NULL; thread_rpc_vars = NULL;
} }
} }
text_set_element (__libc_subfreeres, __rpc_thread_destroy);
/* /*
* Initialize RPC multi-threaded operation * Initialize RPC multi-threaded operation

View File

@ -276,9 +276,9 @@ do_test (void)
else else
/* This is arguably a bug: Regular process termination /* This is arguably a bug: Regular process termination
does not unregister the service with rpcbind. The does not unregister the service with rpcbind. The
unset rpcbind call happens from a __libc_subfreeres unset rpcbind call happens from a __libc_freeres,
callback, and this only happens when running under and this only happens when running under memory debuggers
memory debuggers such as valgrind. */ such as valgrind. */
TEST_VERIFY (!state.unset_called); TEST_VERIFY (!state.unset_called);
} }
else else

View File

@ -0,0 +1,19 @@
/* System specific resource deallocation. Generic version.
Copyright (C) 2022 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/>. */
#define call_freeres_fp_funcs

View File

@ -0,0 +1,19 @@
/* System specific resource deallocation. Generic version.
Copyright (C) 2020-2022 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/>. */
#define call_freeres_os_funcs

View File

@ -0,0 +1,27 @@
/* System specific resource deallocation. Generic version.
Copyright (C) 2022 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/>. */
/* Each system may define weak functions to free any resource allocated with
malloc to avoid interfere with mtrace. */
#include <set-freeres-os.h>
#include <set-freeres-fp.h>
#define call_freeres_system_funcs \
call_freeres_os_funcs; \
call_freeres_fp_funcs

View File

@ -42,6 +42,7 @@ typeof (qfcvt_r) ___qfcvtieee128_r;
#define __GCVT ___qgcvtieee128 #define __GCVT ___qgcvtieee128
#define __ECVT_R ___qecvtieee128_r #define __ECVT_R ___qecvtieee128_r
#define __FCVT_R ___qfcvtieee128_r #define __FCVT_R ___qfcvtieee128_r
#define __EFGCVT_FREEMEM_PTR __libc_efgcvtieee128_freemem_ptr
#include <efgcvt-ldbl-macros.h> #include <efgcvt-ldbl-macros.h>
#include <efgcvt-template.c> #include <efgcvt-template.c>

View File

@ -0,0 +1,22 @@
/* System specific resource deallocation. IBM long double 128 version.
Copyright (C) 2022 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/>. */
extern char * __libc_efgcvtieee128_freemem_ptr attribute_hidden;
#define call_freeres_fp_funcs \
call_free_static_weak (__libc_efgcvtieee128_freemem_ptr)

View File

@ -9,7 +9,6 @@
mach/boolean.h mach/boolean.h
mach/i386/boolean.h mach/i386/boolean.h
mach/i386/vm_types.h mach/i386/vm_types.h
mach/i386/stdint.h
mach/mig_errors.h mach/mig_errors.h
device/device_types.h device/device_types.h
mach/std_types.h mach/std_types.h

View File

@ -1761,7 +1761,8 @@ check_gaiconf_mtime (const struct __stat64_t64 *st)
#endif #endif
libc_freeres_fn(fini) void
__libc_getaddrinfo_freemem (void)
{ {
if (labels != default_labels) if (labels != default_labels)
{ {
@ -2233,7 +2234,7 @@ no_file:
/* If we previously read the file but it is gone now, free the old data and /* If we previously read the file but it is gone now, free the old data and
use the builtin one. Leave the reload flag alone. */ use the builtin one. Leave the reload flag alone. */
fini (); __libc_getaddrinfo_freemem ();
} }

View File

@ -24,6 +24,7 @@
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <set-freeres.h>
char *__ttyname; char *__ttyname;
@ -31,7 +32,8 @@ static char *getttyname (int fd, dev_t mydev, ino_t myino,
int save, int *dostat); int save, int *dostat);
libc_freeres_ptr (static char *getttyname_name); static char *getttyname_name;
weak_alias (getttyname_name, __ttyname_freemem_ptr)
static char * static char *
getttyname (int fd, dev_t mydev, ino_t myino, int save, int *dostat) getttyname (int fd, dev_t mydev, ino_t myino, int save, int *dostat)

View File

@ -362,7 +362,8 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6,
} }
/* Free the cache if it has been allocated. */ /* Free the cache if it has been allocated. */
libc_freeres_fn (freecache) void
__check_pf_freemem (void)
{ {
if (cache) if (cache)
__free_in6ai (cache->in6ai); __free_in6ai (cache->in6ai);

View File

@ -25,6 +25,7 @@
# define weak_alias(n,a) # define weak_alias(n,a)
#endif #endif
#include "login/getutent.c" #include "login/getutent.c"
_weak_alias (buffer, __libc_getutent_freemem_ptr)
#if defined SHARED #if defined SHARED
default_symbol_version (__getutent, getutent, UTMP_COMPAT_BASE); default_symbol_version (__getutent, getutent, UTMP_COMPAT_BASE);

View File

@ -25,6 +25,7 @@
# define weak_alias(n,a) # define weak_alias(n,a)
#endif #endif
#include "login/getutid.c" #include "login/getutid.c"
_weak_alias (buffer, __libc_getutid_freemem_ptr)
#if defined SHARED #if defined SHARED
default_symbol_version (__getutid, getutid, UTMP_COMPAT_BASE); default_symbol_version (__getutid, getutid, UTMP_COMPAT_BASE);

View File

@ -25,6 +25,7 @@
# define weak_alias(n,a) # define weak_alias(n,a)
#endif #endif
#include "login/getutline.c" #include "login/getutline.c"
_weak_alias (buffer, __libc_getutline_freemem_ptr)
#if defined SHARED #if defined SHARED
default_symbol_version (__getutline, getutline, UTMP_COMPAT_BASE); default_symbol_version (__getutline, getutline, UTMP_COMPAT_BASE);

View File

@ -0,0 +1,24 @@
/* System specific resource deallocation. Linux version.
Copyright (C) 2022 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/>. */
extern void __check_pf_freemem (void) attribute_hidden;
extern char * __ttyname_freemem_ptr attribute_hidden;
#define call_freeres_os_funcs \
call_function_static_weak (__check_pf_freemem); \
call_free_static_weak (__ttyname_freemem_ptr)

View File

@ -19,15 +19,11 @@
#include <limits.h> #include <limits.h>
#include <termios.h> #include <termios.h>
#include <stdlib.h> #include <stdlib.h>
#include <set-freeres.h>
#include "ttyname.h" #include "ttyname.h"
static char *ttyname_buf = NULL; static char *ttyname_buf = NULL;
weak_alias (ttyname_buf, __ttyname_freemem_ptr)
libc_freeres_fn (free_mem)
{
free (ttyname_buf);
}
/* Return the pathname of the terminal FD is open on, or NULL on errors. /* Return the pathname of the terminal FD is open on, or NULL on errors.
The returned storage is good only until the next call to this function. */ The returned storage is good only until the next call to this function. */

View File

@ -26,6 +26,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <stdint.h> #include <stdint.h>
#include <alloc_buffer.h> #include <alloc_buffer.h>
#include <set-freeres.h>
#include <timezone/tzfile.h> #include <timezone/tzfile.h>
@ -50,7 +51,7 @@ struct leap
}; };
static size_t num_transitions; static size_t num_transitions;
libc_freeres_ptr (static __time64_t *transitions); static __time64_t *transitions;
static unsigned char *type_idxs; static unsigned char *type_idxs;
static size_t num_types; static size_t num_types;
static struct ttinfo *types; static struct ttinfo *types;
@ -780,3 +781,5 @@ __tzfile_compute (__time64_t timer, int use_localtime,
} }
} }
} }
weak_alias (transitions, __libc_tzfile_freemem_ptr)

View File

@ -610,7 +610,8 @@ __tz_convert (__time64_t timer, int use_localtime, struct tm *tp)
} }
libc_freeres_fn (free_mem) void
__libc_tzset_freemem (void)
{ {
while (tzstring_list != NULL) while (tzstring_list != NULL)
{ {