Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / alloc.c
1 #ifndef lint
2 static char *RCSid() { return RCSid("$Id: alloc.c,v 1.12 2006/03/17 16:09:03 broeker Exp $"); }
3 #endif
4
5 /* GNUPLOT - alloc.c */
6
7 /*[
8  * Copyright 1986 - 1993, 1998, 2004   Thomas Williams, Colin Kelley
9  *
10  * Permission to use, copy, and distribute this software and its
11  * documentation for any purpose with or without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and
13  * that both that copyright notice and this permission notice appear
14  * in supporting documentation.
15  *
16  * Permission to modify the software is granted, but not the right to
17  * distribute the complete modified source code.  Modifications are to
18  * be distributed as patches to the released version.  Permission to
19  * distribute binaries produced by compiling modified sources is granted,
20  * provided you
21  *   1. distribute the corresponding source modifications from the
22  *    released version in the form of a patch file along with the binaries,
23  *   2. add special version identification to distinguish your version
24  *    in addition to the base release version number,
25  *   3. provide your name and address as the primary contact for the
26  *    support of your modified version, and
27  *   4. retain our contact information in regard to use of the base
28  *    software.
29  * Permission to distribute the released version of the source code along
30  * with corresponding source modifications in the form of a patch file is
31  * granted with same provisions 2 through 4 for binary distributions.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35 ]*/
36
37 /*
38  * AUTHORS
39  *
40  * Alexander Lehmann (collected functions from misc.c and binary.c)
41  *
42  */
43
44 #include "alloc.h"
45
46 #ifndef NO_GIH
47 # include "help.h"
48 #endif
49 #include "util.h"
50
51 #if defined(MSDOS) && defined(__TURBOC__) && !defined(DOSX286)
52 # include <alloc.h>             /* for farmalloc, farrealloc */
53 #endif
54
55 #if defined(_Windows) && !defined(WIN32)
56 # include <windows.h>
57 # include <windowsx.h>
58 # define farmalloc(s) GlobalAllocPtr(GHND,s)
59 # define farrealloc(p,s) GlobalReAllocPtr(p,s,GHND)
60 #endif
61
62
63
64 #ifndef GP_FARMALLOC
65 # ifdef FARALLOC
66 #  define GP_FARMALLOC(size) farmalloc ((size))
67 #  define GP_FARREALLOC(p,size) farrealloc ((p), (size))
68 # else
69 #  define GP_FARMALLOC(size) malloc ((size_t)(size))
70 #  define GP_FARREALLOC(p,size) realloc ((p), (size_t)(size))
71 # endif
72 #endif
73
74 /* uncomment if you want to trace all allocs */
75 #define TRACE_ALLOC(x)          /*printf x */
76
77
78 #ifdef CHECK_HEAP_USE
79
80 /* This is in no way supported, and in particular it breaks the
81  * online help. But it is useful to leave it in in case any
82  * heap-corruption bugs turn up. Wont work with FARALLOC
83  */
84
85 struct frame_struct {
86     char *use;
87     int requested_size;
88     int pad;                    /* preserve 8-byte alignment */
89     int checksum;
90 };
91
92 struct leak_struct {
93     char *file;
94     int line;
95     int allocated;
96 };
97
98 static struct leak_struct leak_stack[40];       /* up to 40 nested leak checks */
99 static struct leak_struct *leak_frame = leak_stack;
100
101 static long bytes_allocated = 0;
102
103 #define RESERVED_SIZE sizeof(struct frame_struct)
104 #define CHECKSUM_INT 0xcaac5e1f
105 #define CHECKSUM_FREE 0xf3eed222
106 #define CHECKSUM_CHAR 0xc5
107
108 static void
109 mark(struct frame_struct *p, unsigned long size, char *usage)
110 {
111     p->use = usage;
112     p->requested_size = size;
113     p->checksum = (CHECKSUM_INT ^ (int) (p->use) ^ size);
114     ((unsigned char *) (p + 1))[size] = CHECKSUM_CHAR;
115 }
116
117 #define mark_free(p) ( ((struct frame_struct *)p)[-1].checksum = CHECKSUM_FREE)
118
119 static void
120 validate(generic *x)
121 {
122     struct frame_struct *p = (struct frame_struct *) x - 1;
123     if (p->checksum != (CHECKSUM_INT ^ (int) (p->use) ^ p->requested_size)) {
124         fprintf(stderr, "Heap corruption at start of block for %s\n", p->use);
125         if (p->checksum == CHECKSUM_FREE)
126             fprintf(stderr, "Looks like it has already been freed ?\n");
127         abort();
128     }
129     if (((unsigned char *) (p + 1))[p->requested_size] != CHECKSUM_CHAR) {
130         fprintf(stderr, "Heap corruption at end of block for %-60s\n", p->use);
131         int_error(NO_CARET, "Argh !");
132     }
133 }
134
135 /* used to confirm that a pointer is inside an allocated region via
136  * macro CHECK_POINTER. Nowhere near as good as using a bounds-checking
137  * compiler (such as gcc-with-bounds-checking), but when we do
138  * come across problems, we can add these guards to the code until
139  * we find the problem, and then leave the guards in (as CHECK_POINTER
140  * macros which expand to nothing, until we need to re-enable them)
141  */
142
143 void
144 check_pointer_in_block(generic *block, generic *p, int size, char *file, int line)
145 {
146     struct frame_struct *f = (struct frame_struct *) block - 1;
147     validate(block);
148     if (p < block || p >= (block + f->requested_size)) {
149         fprintf(stderr, "argh - pointer %p outside block %p->%p for %s at %s:%d\n",
150                 p, block, (char *) block + f->requested_size, f->use, file, line);
151         int_error(NO_CARET, "argh - pointer misuse !");
152     }
153 }
154
155 generic *
156 gp_alloc(size_t size, const char *usage)
157 {
158     struct frame_struct *p;
159     size_t total_size = size + RESERVED_SIZE + 1;
160
161     TRACE_ALLOC(("gp_alloc %d for %s\n", (int) size,
162                  usage ? usage : "<unknown>"));
163
164     p = malloc(total_size);
165     if (!p)
166         int_error(NO_CARET, "Out of memory");
167
168     bytes_allocated += size;
169
170     mark(p, size, usage);
171
172     /* Cast possibly needed for K&R compilers */
173     return (generic *) (p + 1);
174 }
175
176 generic *
177 gp_realloc(generic *old, size_t size, const char *usage)
178 {
179     if (!old)
180         return gp_alloc(size, usage);
181     validate(old);
182     /* if block gets moved, old block is marked free.  If not, we'll
183      * remark it later */
184     mark_free(old);             
185
186     {
187         struct frame_struct *p = (struct frame_struct *) old - 1;
188         size_t total = size + RESERVED_SIZE + 1;
189
190         p = realloc(p, total);
191
192         if (!p)
193             int_error(NO_CARET, "Out of memory");
194
195         TRACE_ALLOC(("gp_realloc %d for %s (was %d)\n", (int) size,
196                      usage ? usage : "<unknown>", p->requested_size));
197
198         bytes_allocated += size - p->requested_size;
199
200         mark(p, size, usage);
201
202         return (generic *) (p + 1);
203     }
204 }
205
206 #undef free
207
208 void
209 checked_free(generic *p)
210 {
211     struct frame_struct *frame;
212
213     validate(p);
214     mark_free(p);               /* trap attempts to free twice */
215     frame = (struct frame_struct *) p - 1;
216     TRACE_ALLOC(("free %d for %s\n",
217                  frame->requested_size,
218                  (frame->use ? frame->use : "(NULL)")));
219     bytes_allocated -= frame->requested_size;
220     free(frame);
221 }
222
223
224 /* this leak checking stuff will be broken by first int_error or interrupt */
225
226 void
227 start_leak_check(char *file, int line)
228 {
229     if (leak_frame >= leak_stack + 40) {
230         fprintf(stderr, "too many nested memory-leak checks - %s:%d\n",
231                 file, line);
232         return;
233     }
234     leak_frame->file = file;
235     leak_frame->line = line;
236     leak_frame->allocated = bytes_allocated;
237
238     ++leak_frame;
239 }
240
241 void
242 end_leak_check(char *file, int line)
243 {
244     if (--leak_frame < leak_stack) {
245         fprintf(stderr, "memory-leak stack underflow at %s:%d\n", file, line);
246         return;
247     }
248     if (leak_frame->allocated != bytes_allocated) {
249         fprintf(stderr,
250                 "net change of %+d heap bytes between %s:%d and %s:%d\n",
251                 (int) (bytes_allocated - leak_frame->allocated),
252                 leak_frame->file, leak_frame->line, file, line);
253     }
254 }
255
256 #else /* CHECK_HEAP_USE */
257
258 /* gp_alloc:
259  * allocate memory
260  * This is a protected version of malloc. It causes an int_error
261  * if there is not enough memory, but first it tries FreeHelp()
262  * to make some room, and tries again. If message is NULL, we
263  * allow NULL return. Otherwise, we handle the error, using the
264  * message to create the int_error string. Note cp/sp_extend uses realloc,
265  * so it depends on this using malloc().
266  */
267
268 generic *
269 gp_alloc(size_t size, const char *message)
270 {
271     char *p;                    /* the new allocation */
272
273 #ifndef NO_GIH
274     p = GP_FARMALLOC(size);
275     if (p == (char *) NULL) {
276         FreeHelp();             /* out of memory, try to make some room */
277 #endif /* NO_GIH */
278         p = GP_FARMALLOC(size); /* try again */
279         if (p == NULL) {
280             /* really out of memory */
281             if (message != NULL) {
282                 int_error(NO_CARET, "out of memory for %s", message);
283                 /* NOTREACHED */
284             }
285             /* else we return NULL */
286         }
287 #ifndef NO_GIH
288     }
289 #endif
290     return (p);
291 }
292
293 /*
294  * note gp_realloc assumes that failed realloc calls leave the original mem
295  * block allocated. If this is not the case with any C compiler, a substitue
296  * realloc function has to be used.
297  */
298
299 generic *
300 gp_realloc(generic *p, size_t size, const char *message)
301 {
302     char *res;                  /* the new allocation */
303
304     /* realloc(NULL,x) is meant to do malloc(x), but doesn't always */
305     if (!p)
306         return gp_alloc(size, message);
307
308 #ifndef NO_GIH
309     res = GP_FARREALLOC(p, size);
310     if (res == (char *) NULL) {
311         FreeHelp();             /* out of memory, try to make some room */
312 #endif /* NO_GIH */
313         res = GP_FARREALLOC(p, size);   /* try again */
314         if (res == (char *) NULL) {
315             /* really out of memory */
316             if (message != NULL) {
317                 int_error(NO_CARET, "out of memory for %s", message);
318                 /* NOTREACHED */
319             }
320             /* else we return NULL */
321         }
322 #ifndef NO_GIH
323     }
324 #endif
325     return (res);
326 }
327
328 #endif /* CHECK_HEAP_USE */
329
330 #ifdef FARALLOC
331 void
332 gpfree(generic *p)
333 {
334 #ifdef _Windows
335     HGLOBAL hGlobal = GlobalHandle(SELECTOROF(p));
336     GlobalUnlock(hGlobal);
337     GlobalFree(hGlobal);
338 #else
339     farfree(p);
340 #endif
341 }
342
343 #endif