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