1 /*!
2  * \file src/free_atexit.c
3  *
4  * \brief .
5  *
6  * <hr>
7  *
8  * <h1><b>Copyright.</b></h1>\n
9  *
10  * Copyright (C) 2010 PCB Contributors (see ChangeLog for details)
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25  *
26  * Contact addresses for paper mail and Email:
27  * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA
28  * haceaton@aplcomm.jhuapl.edu
29  */
30 
31 #include <stdlib.h>
32 #include <string.h>
33 
34 /*!
35  * \brief We need one ID per context - short int with 64k IDs should be
36  * enough.
37  */
38 typedef unsigned int leaky_idx_t;
39 
40 
41 /*!
42  * \brief .
43  *
44  * This structure should be as big as void *, which should be the
45  * natural bit-width of the architecture.\n
46  * We allocate extra admin space to be as big as this union, to preserve
47  * alignment of pointers returned by malloc().\n
48  *
49  * \note In the special corner case when leaky_idx_t is wider than
50  * void * but not multiple of it, the alignment will be messed up,
51  * potentially causing slower memory access.
52  */
53 typedef union {
54   leaky_idx_t idx;
55   void *ptr;
56 } leaky_admin_t;
57 
58 static void         **free_list = NULL;
59 static leaky_idx_t  free_size = 0;
60 
61 
62 /*!
63  * \brief Allocate memory, remember the pointer and free it after exit
64  * from the application.
65  */
leaky_malloc(size_t size)66 void *leaky_malloc (size_t size)
67 {
68   void *new_memory = malloc(size + sizeof(leaky_admin_t));
69 
70   free_list = (void **)realloc (free_list, (free_size + 1) * sizeof(void *));
71   free_list[free_size] = new_memory;
72   *(leaky_idx_t *)new_memory = free_size;
73 
74   free_size++;
75   return new_memory + sizeof(leaky_admin_t);
76 }
77 
78 /*!
79  * \brief Same as leaky_malloc but this one wraps calloc().
80  */
leaky_calloc(size_t nmemb,size_t size)81 void *leaky_calloc (size_t nmemb, size_t size)
82 {
83   size_t size_ = size * nmemb;
84   void *new_memory = leaky_malloc (size_);
85 
86   memset (new_memory, 0, size_);
87   return new_memory;
88 }
89 
90 /*!
91  * \brief Reallocate memory, remember the new pointer and free it after
92  * exit from the application.
93  */
leaky_realloc(void * old_memory,size_t size)94 void *leaky_realloc (void* old_memory, size_t size)
95 {
96   void *new_memory;
97   leaky_idx_t i;
98 
99   if (old_memory == NULL)
100     return leaky_malloc (size);
101 
102   old_memory -= sizeof(leaky_admin_t);
103 
104   i = *(leaky_idx_t *)old_memory;
105 
106   new_memory = realloc (old_memory, size + sizeof(leaky_admin_t));
107   free_list[i] = new_memory;
108 
109   return new_memory + sizeof(leaky_admin_t);
110 }
111 
112 /*!
113  * \brief strdup() using leaky_malloc().
114  */
115 char *
leaky_strdup(const char * src)116 leaky_strdup (const char *src)
117 {
118   int len = strlen (src)+1;
119   char *res = leaky_malloc (len);
120   memcpy (res, src, len);
121   return res;
122 }
123 
124 /*!
125  * \brief Free all allocations.
126  */
leaky_uninit(void)127 void leaky_uninit (void)
128 {
129   int i;
130 
131   for (i = 0; i < free_size; i++)
132     free (free_list[i]);
133 
134   free (free_list);
135   free_size = 0;
136 }
137 
138 /*!
139  * \brief Set up atexit() hook.
140  *
141  * Can be avoided if leaky_uninit() is called by hand.
142  */
leaky_init(void)143 void leaky_init (void)
144 {
145   atexit(leaky_uninit);
146 }
147