1 /*
2    Replacement memory allocation handling etc.
3    Copyright (C) 1999-2003, Joe Orton <joe@manyfish.co.uk>
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public
16    License along with this library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18    MA 02111-1307, USA
19 
20 */
21 
22 #include "config.h"
23 
24 #ifdef HAVE_STRING_H
25 #include <string.h>
26 #endif
27 
28 #ifdef HAVE_STDLIB_H
29 #include <stdlib.h>
30 #endif
31 
32 #include <stdio.h>
33 
34 #include "ne_alloc.h"
35 
36 static void (*oom)(void);
37 
ne_oom_callback(void (* callback)(void))38 void ne_oom_callback(void (*callback)(void))
39 {
40     oom = callback;
41 }
42 
43 #ifndef NEON_MEMLEAK
44 
45 #define DO_MALLOC(ptr, len) do {		\
46     ptr = malloc((len));			\
47     if (!ptr) {					\
48 	if (oom != NULL)			\
49 	    oom();				\
50 	abort();				\
51     }						\
52 } while(0);
53 
ne_malloc(size_t len)54 void *ne_malloc(size_t len)
55 {
56     void *ptr;
57     DO_MALLOC(ptr, len);
58     return ptr;
59 }
60 
ne_calloc(size_t len)61 void *ne_calloc(size_t len)
62 {
63     void *ptr;
64     DO_MALLOC(ptr, len);
65     return memset(ptr, 0, len);
66 }
67 
ne_realloc(void * ptr,size_t len)68 void *ne_realloc(void *ptr, size_t len)
69 {
70     void *ret = realloc(ptr, len);
71     if (!ret) {
72 	if (oom)
73 	    oom();
74 	abort();
75     }
76     return ret;
77 }
78 
ne_strdup(const char * s)79 char *ne_strdup(const char *s)
80 {
81     char *ret;
82     DO_MALLOC(ret, strlen(s) + 1);
83     return strcpy(ret, s);
84 }
85 
ne_strndup(const char * s,size_t n)86 char *ne_strndup(const char *s, size_t n)
87 {
88     char *new;
89     DO_MALLOC(new, n+1);
90     new[n] = '\0';
91     memcpy(new, s, n);
92     return new;
93 }
94 
95 #else /* NEON_MEMLEAK */
96 
97 /* Memory-leak detection implementation: ne_malloc and friends are
98  * #defined to ne_malloc_ml etc by memleak.h, which is conditionally
99  * included by config.h. */
100 
101 /* memory allocated be ne_*alloc, but not freed. */
102 size_t ne_alloc_used = 0;
103 
104 static struct block {
105     void *ptr;
106     size_t len;
107     const char *file;
108     int line;
109     struct block *next;
110 } *blocks = NULL;
111 
ne_alloc_dump(FILE * f)112 void ne_alloc_dump(FILE *f)
113 {
114     struct block *b;
115 
116     for (b = blocks; b != NULL; b = b->next)
117         fprintf(f, "%" NE_FMT_SIZE_T "b@%s:%d%s", b->len, b->file, b->line,
118                 b->next?", ":"");
119 }
120 
tracking_malloc(size_t len,const char * file,int line)121 static void *tracking_malloc(size_t len, const char *file, int line)
122 {
123     void *ptr = malloc((len));
124     struct block *block;
125 
126     if (!ptr) {
127 	if (oom) oom();
128 	abort();
129     }
130 
131     block = malloc(sizeof *block);
132     if (block != NULL) {
133         block->ptr = ptr;
134         block->len = len;
135         block->file = file;
136         block->line = line;
137         block->next = blocks;
138         blocks = block;
139         ne_alloc_used += len;
140     }
141 
142     return ptr;
143 }
144 
ne_malloc_ml(size_t size,const char * file,int line)145 void *ne_malloc_ml(size_t size, const char *file, int line)
146 {
147     return tracking_malloc(size, file, line);
148 }
149 
ne_calloc_ml(size_t size,const char * file,int line)150 void *ne_calloc_ml(size_t size, const char *file, int line)
151 {
152     return memset(tracking_malloc(size, file, line), 0, size);
153 }
154 
ne_realloc_ml(void * ptr,size_t s,const char * file,int line)155 void *ne_realloc_ml(void *ptr, size_t s, const char *file, int line)
156 {
157     void *ret = realloc(ptr, s);
158     struct block *b;
159 
160     if (!ret) {
161         if (oom) oom();
162         abort();
163     }
164 
165     for (b = blocks; b != NULL; b = b->next) {
166         if (b->ptr == ptr) {
167             ne_alloc_used = ne_alloc_used + s - b->len;
168             b->ptr = ret;
169             b->len = s;
170             break;
171         }
172     }
173 
174     return ret;
175 }
176 
ne_strdup_ml(const char * s,const char * file,int line)177 char *ne_strdup_ml(const char *s, const char *file, int line)
178 {
179     return strcpy(tracking_malloc(strlen(s) + 1, file, line), s);
180 }
181 
ne_strndup_ml(const char * s,size_t n,const char * file,int line)182 char *ne_strndup_ml(const char *s, size_t n, const char *file, int line)
183 {
184     char *ret = tracking_malloc(n + 1, file, line);
185     ret[n] = '\0';
186     return memcpy(ret, s, n);
187 }
188 
ne_free_ml(void * ptr)189 void ne_free_ml(void *ptr)
190 {
191     struct block *b, *last = NULL;
192 
193     for (b = blocks; b != NULL; last = b, b = b->next) {
194         if (b->ptr == ptr) {
195             ne_alloc_used -= b->len;
196             if (last)
197                 last->next = b->next;
198             else
199                 blocks = b->next;
200             free(b);
201             break;
202         }
203     }
204 
205     free(ptr);
206 }
207 
208 #endif /* NEON_MEMLEAK */
209