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