diff --git a/common/init.c b/common/init.c index e00b9b308..8a0b6a8e7 100644 --- a/common/init.c +++ b/common/init.c @@ -46,6 +46,21 @@ #include "util.h" +/* This object is used to register memory cleanup functions. + Technically they are not needed but they can avoid frequent + questions about un-released memory. Note that we use the system + malloc and not any wrappers. */ +struct mem_cleanup_item_s; +typedef struct mem_cleanup_item_s *mem_cleanup_item_t; + +struct mem_cleanup_item_s +{ + mem_cleanup_item_t next; + void (*func) (void); +}; + +static mem_cleanup_item_t mem_cleanup_list; + /* The default error source of the application. This is different from GPG_ERR_SOURCE_DEFAULT in that it does not depend on the @@ -65,6 +80,36 @@ sleep_on_exit (void) #endif /*HAVE_W32CE_SYSTEM*/ +static void +run_mem_cleanup (void) +{ + mem_cleanup_item_t next; + + while (mem_cleanup_list) + { + next = mem_cleanup_list->next; + mem_cleanup_list->func (); + free (mem_cleanup_list); + mem_cleanup_list = next; + } +} + + +void +register_mem_cleanup_func (void (*func)(void)) +{ + mem_cleanup_item_t item; + + item = malloc (sizeof *item); + if (item) + { + item->func = func; + item->next = mem_cleanup_list; + mem_cleanup_list = item; + } +} + + /* If STRING is not NULL write string to es_stdout or es_stderr. MODE must be 1 or 2. If STRING is NULL flush the respective stream. */ static int @@ -100,6 +145,8 @@ _init_common_subsystems (gpg_err_source_t errsource, int *argcp, char ***argvp) /* Store the error source in a gloabl variable. */ default_errsource = errsource; + atexit (run_mem_cleanup); + /* Try to auto set the character set. */ set_native_charset (NULL); diff --git a/common/init.h b/common/init.h index 633ffac52..eea2eb167 100644 --- a/common/init.h +++ b/common/init.h @@ -36,6 +36,8 @@ # error GPG_ERR_SOURCE_DEFAULT has default value #endif +void register_mem_cleanup_func (void (*func)(void)); + void _init_common_subsystems (gpg_err_source_t errsource, int *argcp, char ***argvp); #define init_common_subsystems(a,b) \ diff --git a/g10/kbnode.c b/g10/kbnode.c index 1a8b91e43..d4907408b 100644 --- a/g10/kbnode.c +++ b/g10/kbnode.c @@ -31,35 +31,58 @@ #define USE_UNUSED_NODES 1 +static int cleanup_registered; static KBNODE unused_nodes; -static KBNODE -alloc_node(void) +#if USE_UNUSED_NODES +static void +release_unused_nodes (void) { - KBNODE n; + while (unused_nodes) + { + kbnode_t next = unused_nodes->next; + xfree (unused_nodes); + unused_nodes = next; + } +} +#endif /*USE_UNUSED_NODES*/ - n = unused_nodes; - if( n ) - unused_nodes = n->next; - else - n = xmalloc( sizeof *n ); - n->next = NULL; - n->pkt = NULL; - n->flag = 0; - n->private_flag=0; - n->recno = 0; - return n; + +static kbnode_t +alloc_node (void) +{ + kbnode_t n; + + n = unused_nodes; + if (n) + unused_nodes = n->next; + else + { + if (!cleanup_registered) + { + cleanup_registered = 1; + register_mem_cleanup_func (release_unused_nodes); + } + n = xmalloc (sizeof *n); + } + n->next = NULL; + n->pkt = NULL; + n->flag = 0; + n->private_flag=0; + n->recno = 0; + return n; } static void free_node( KBNODE n ) { - if( n ) { + if (n) + { #if USE_UNUSED_NODES - n->next = unused_nodes; - unused_nodes = n; + n->next = unused_nodes; + unused_nodes = n; #else - xfree( n ); + xfree (n); #endif } }