1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2014 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  *    if any, must include the following acknowledgment:
22  *       "This product includes software developed by the
23  *        Kannel Group (http://www.kannel.org/)."
24  *    Alternately, this acknowledgment may appear in the software itself,
25  *    if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  *    endorse or promote products derived from this software without
29  *    prior written permission. For written permission, please
30  *    contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  *    nor may "Kannel" appear in their name, without prior written
34  *    permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group.  For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  *
59  * wsalloc.c
60  *
61  * Author: Markku Rossi <mtr@iki.fi>
62  *
63  * Copyright (c) 1999-2000 WAPIT OY LTD.
64  *		 All rights reserved.
65  *
66  * Memory allocation routines.  These are simple stub functions to fix
67  * some brain damages, found from some system's default allocators.
68  *
69  */
70 
71 #include "wsint.h"
72 
73 #if !WS_MEM_DEBUG
74 
75 /********************* Global functions *********************************/
76 
ws_malloc(size_t size)77 void *ws_malloc(size_t size)
78 {
79     return malloc(size);
80 }
81 
82 
ws_calloc(size_t num,size_t size)83 void *ws_calloc(size_t num, size_t size)
84 {
85     return calloc(num, size);
86 }
87 
88 
ws_realloc(void * ptr,size_t size)89 void *ws_realloc(void *ptr, size_t size)
90 {
91     if (size == 0) {
92         if (ptr)
93             free(ptr);
94 
95         return NULL;
96     }
97 
98     if (ptr == NULL)
99         return malloc(size);
100 
101     return realloc(ptr, size);
102 }
103 
104 
ws_memdup(const void * ptr,size_t size)105 void *ws_memdup(const void *ptr, size_t size)
106 {
107     unsigned char *data = ws_malloc(size + 1);
108 
109     if (data == NULL)
110         return NULL;
111 
112     memcpy(data, ptr, size);
113     data[size] = '\0';
114 
115     return data;
116 }
117 
118 
ws_strdup(const char * str)119 void *ws_strdup(const char *str)
120 {
121     size_t len;
122     void *s;
123 
124     if (str == NULL)
125         return NULL;
126 
127     len = strlen(str);
128     s = ws_malloc(len + 1);
129 
130     if (s == NULL)
131         return NULL;
132 
133     memcpy(s, str, len + 1);
134 
135     return s;
136 }
137 
138 
ws_free(void * ptr)139 void ws_free(void *ptr)
140 {
141     if (ptr)
142         free(ptr);
143 }
144 
145 #else /* WS_MEM_DEBUG */
146 
147 /********************* Memory debugging routines ************************/
148 
149 #define SIZE(_size) (sizeof(WsMemBlockHdr) + (_size))
150 
151 #define MAGIC 0xfe01fa77
152 
153 struct WsMemBlockHdrRec
154 {
155     unsigned long magic;
156     struct WsMemBlockHdrRec *next;
157     struct WsMemBlockHdrRec *prev;
158     size_t size;
159     const char *file;
160     int line;
161 };
162 
163 typedef struct WsMemBlockHdrRec WsMemBlockHdr;
164 
165 /* A linked list of currently allocated blocks. */
166 WsMemBlockHdr *blocks = NULL;
167 
168 /* How many blocks are currently allocated. */
169 unsigned int num_blocks = 0;
170 
171 /* The maximum amount of blocks used. */
172 unsigned int max_num_blocks = 0;
173 
174 /* How many (user) bytes of memory the currently allocated blocks
175 use. */
176 size_t balance = 0;
177 
178 /* The maximum amount of memory used. */
179 size_t max_balance = 0;
180 
181 /* The alloc sequence number. */
182 unsigned int alloc_number = 0;
183 
184 /* How many allocations are successful. */
185 unsigned int num_successful_allocs = -1;
186 
187 
add_block(WsMemBlockHdr * b,size_t size,const char * file,int line)188 static void add_block(WsMemBlockHdr *b, size_t size, const char *file, int line)
189 {
190     b->magic = MAGIC;
191 
192     b->next = blocks;
193     b->prev = NULL;
194 
195     if (blocks)
196         blocks->prev = b;
197 
198     blocks = b;
199 
200     b->size = size;
201     b->file = file;
202     b->line = line;
203 
204     num_blocks++;
205     balance += size;
206 
207     if (balance > max_balance)
208         max_balance = balance;
209 
210     if (num_blocks > max_num_blocks)
211         max_num_blocks = num_blocks;
212 }
213 
214 
remove_block(WsMemBlockHdr * b)215 static void remove_block(WsMemBlockHdr *b)
216 {
217     if (b->magic != MAGIC)
218         ws_fatal("remove_block(): invalid magic\n");
219 
220     if (b->next)
221         b->next->prev = b->prev;
222     if (b->prev)
223         b->prev->next = b->next;
224     else
225         blocks = b->next;
226 
227     balance -= b->size;
228     num_blocks--;
229 
230     memset(b, 0xfe, SIZE(b->size));
231 }
232 
233 
ws_malloc_i(size_t size,const char * file,int line)234 void *ws_malloc_i(size_t size, const char *file, int line)
235 {
236     WsMemBlockHdr *b;
237 
238     if (alloc_number++ >= num_successful_allocs)
239         return NULL;
240 
241     b = malloc(SIZE(size));
242 
243     if (b == NULL)
244         return NULL;
245 
246     add_block(b, size, file, line);
247 
248     return b + 1;
249 }
250 
251 
ws_calloc_i(size_t num,size_t size,const char * file,int line)252 void *ws_calloc_i(size_t num, size_t size, const char *file, int line)
253 {
254     void *p = ws_malloc_i(num * size, file, line);
255 
256     if (p)
257         memset(p, 0, num * size);
258 
259     return p;
260 }
261 
262 
ws_realloc_i(void * ptr,size_t size,const char * file,int line)263 void *ws_realloc_i(void *ptr, size_t size, const char *file, int line)
264 {
265     WsMemBlockHdr *b = ((WsMemBlockHdr *) ptr) - 1;
266     void *n;
267 
268     if (ptr == NULL)
269         return ws_malloc_i(size, file, line);
270 
271     if (b->size >= size)
272         /* We can use the old block. */
273         return ptr;
274 
275     /* Allocate a bigger block. */
276     n = ws_malloc_i(size, file, line);
277     if (n == NULL)
278         return NULL;
279 
280     memcpy(n, ptr, b->size);
281 
282     /* Free old block. */
283     remove_block(b);
284     free(b);
285 
286     return n;
287 }
288 
289 
ws_memdup_i(const void * ptr,size_t size,const char * file,int line)290 void *ws_memdup_i(const void *ptr, size_t size, const char *file, int line)
291 {
292     void *p = ws_malloc_i(size + 1, file, line);
293 
294     if (p) {
295         unsigned char *cp = (unsigned char *) p;
296 
297         memcpy(p, ptr, size);
298         cp[size] = '\0';
299     }
300 
301     return p;
302 }
303 
304 
ws_strdup_i(const char * str,const char * file,int line)305 void *ws_strdup_i(const char *str, const char *file, int line)
306 {
307     return ws_memdup_i(str, strlen(str), file, line);
308 }
309 
310 
ws_free_i(void * ptr)311 void ws_free_i(void *ptr)
312 {
313     WsMemBlockHdr *b = ((WsMemBlockHdr *) ptr) - 1;
314 
315     if (ptr == NULL)
316         return;
317 
318     remove_block(b);
319     free(b);
320 }
321 
322 
ws_has_leaks(void)323 int ws_has_leaks(void)
324 {
325     return num_blocks || balance;
326 }
327 
328 
ws_dump_blocks(void)329 void ws_dump_blocks(void)
330 {
331     WsMemBlockHdr *b;
332 
333     fprintf(stderr, "ws: maximum memory usage: %u blocks, %ld bytes\n",
334             max_num_blocks, (long) max_balance);
335     fprintf(stderr, "ws: number of allocs: %u\n", alloc_number);
336 
337     if (num_blocks || balance) {
338         fprintf(stderr, "ws: memory leaks: %u blocks, %ld bytes:\n",
339                 num_blocks, (long) balance);
340 
341         for (b = blocks; b; b = b->next)
342             fprintf(stderr, "%s:%d: %ld\n", b->file, b->line, (long) b->size);
343     }
344 }
345 
346 
ws_clear_leaks(unsigned int num_successful_allocs_)347 void ws_clear_leaks(unsigned int num_successful_allocs_)
348 {
349     alloc_number = 0;
350     num_successful_allocs = num_successful_allocs_;
351     blocks = NULL;
352 }
353 
354 #endif /* WS_MEM_DEBUG */
355