Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
 * Portions of this file are copyright Rebirth contributors and licensed as
3
 * described in COPYING.txt.
4
 * Portions of this file are copyright Parallax Software and licensed
5
 * according to the Parallax license below.
6
 * See COPYING.txt for license details.
7
 
8
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
9
SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
10
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
11
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
12
IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
13
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
14
FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
15
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
16
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
17
COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
18
*/
19
 
20
/*
21
 *
22
 * Files for debugging memory allocator
23
 *
24
 *
25
 */
26
 
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#include "pstypes.h"
31
#include "dxxerror.h"
32
#include "args.h"
33
#include "console.h"
34
#include "u_mem.h"
35
#include <array>
36
 
37
namespace dcx {
38
 
39
#define MEMSTATS 0
40
#define FULL_MEM_CHECKING 1
41
 
42
#ifdef DEBUG_MEMORY_ALLOCATIONS
43
#if defined(FULL_MEM_CHECKING)
44
 
45
#define CHECKSIZE 16
46
#define CHECKBYTE 0xFC
47
 
48
#define MAX_INDEX 10000
49
 
50
static std::array<void *, MAX_INDEX> MallocBase;
51
static std::array<unsigned int, MAX_INDEX> MallocSize;
52
static std::array<unsigned char, MAX_INDEX> Present;
53
static std::array<const char *, MAX_INDEX> Filename;
54
static std::array<const char *, MAX_INDEX> Varname;
55
static std::array<int, MAX_INDEX> LineNum;
56
static int BytesMalloced = 0;
57
 
58
static int free_list[MAX_INDEX];
59
 
60
static int num_blocks = 0;
61
 
62
static int Initialized = 0;
63
static int LargestIndex = 0;
64
static int out_of_memory = 0;
65
 
66
void mem_init()
67
{
68
        Initialized = 1;
69
 
70
        MallocBase = {};
71
        MallocSize = {};
72
        Present = {};
73
        Filename = {};
74
        Varname = {};
75
        LineNum = {};
76
        for (int i=0; i<MAX_INDEX; i++ )
77
        {
78
                free_list[i] = i;
79
        }
80
 
81
        num_blocks = 0;
82
        LargestIndex = 0;
83
 
84
        atexit(mem_display_blocks);
85
}
86
 
87
static void PrintInfo( int id )
88
{
89
        con_printf(CON_CRITICAL, "\tBlock '%s' created in %s, line %d.", Varname[id], Filename[id], LineNum[id] );
90
}
91
 
92
 
93
void *mem_malloc(size_t size, const char * var, const char * filename, unsigned line)
94
{
95
        int id;
96
        void *ptr;
97
        char * pc;
98
 
99
        if (Initialized==0)
100
                mem_init();
101
 
102
#if MEMSTATS
103
        {
104
                unsigned long   theFreeMem = 0;
105
 
106
                if (sMemStatsFileInitialized)
107
                {
108
                        theFreeMem = FreeMem();
109
 
110
                        fprintf(sMemStatsFile,
111
                                        "\n%9u bytes free before attempting: MALLOC %9u bytes.",
112
                                        theFreeMem,
113
                                        size);
114
                }
115
        }
116
#endif  // end of ifdef memstats
117
 
118
        if ( num_blocks >= MAX_INDEX )  {
119
                con_printf(CON_CRITICAL,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs." );            
120
                con_printf(CON_CRITICAL, "\tBlock '%s' created in %s, line %d.", var, filename, line );
121
                Error( "MEM_OUT_OF_SLOTS" );
122
        }
123
 
124
        id = free_list[ num_blocks++ ];
125
 
126
        if (id > LargestIndex ) LargestIndex = id;
127
 
128
        if (id==-1)
129
        {
130
                con_printf(CON_CRITICAL,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs." );            
131
                //con_printf(CON_CRITICAL, "\tBlock '%s' created in %s, line %d.", Varname[id], Filename[id], LineNum[id] );
132
                Error( "MEM_OUT_OF_SLOTS" );
133
        }
134
        ptr = malloc(size + DXX_DEBUG_BIAS_MEMORY_ALLOCATION + CHECKSIZE);
135
 
136
        if (ptr==NULL)
137
        {
138
                out_of_memory = 1;
139
                con_printf(CON_CRITICAL, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL" );
140
                con_printf(CON_CRITICAL, "\tBlock '%s' created in %s, line %d.", Varname[id], Filename[id], LineNum[id] );
141
                Error( "MEM_OUT_OF_MEMORY" );
142
        }
143
        ptr = reinterpret_cast<char *>(ptr) + DXX_DEBUG_BIAS_MEMORY_ALLOCATION;
144
        MallocBase[id] = ptr;
145
        MallocSize[id] = size;
146
        Varname[id] = var;
147
        Filename[id] = filename;
148
        LineNum[id] = line;
149
        Present[id]    = 1;
150
 
151
        pc = reinterpret_cast<char *>(ptr);
152
 
153
        BytesMalloced += size;
154
 
155
        for (int i=0; i<CHECKSIZE; i++ )
156
                pc[size+i] = CHECKBYTE;
157
 
158
        return ptr;
159
}
160
 
161
void *(mem_calloc)( size_t nmemb, size_t size, const char * var, const char * filename, unsigned line)
162
{
163
        size_t threshold = 1, request = nmemb * size;
164
        threshold <<= (4 * sizeof(threshold));
165
        if ((nmemb | size) >= threshold) {
166
                /* possible overflow condition */
167
                if (request / size != nmemb)
168
                        request = ~static_cast<size_t>(0);
169
        }
170
        void *ptr = mem_malloc(request, var, filename, line);
171
        if (ptr)
172
                memset( ptr, 0, request );
173
        return ptr;
174
}
175
 
176
static int mem_find_id( void * buffer )
177
{
178
        for (int i=0; i<=LargestIndex; i++ )
179
          if (Present[i]==1)
180
            if (MallocBase[i] == buffer )
181
              return i;
182
 
183
        // Didn't find id.
184
        return -1;
185
}
186
 
187
static int mem_check_integrity( int block_number )
188
{
189
        int ErrorCount;
190
        uint8_t * CheckData;
191
 
192
        CheckData = reinterpret_cast<uint8_t *>(reinterpret_cast<char *>(MallocBase[block_number]) + MallocSize[block_number]);
193
 
194
        ErrorCount = 0;
195
 
196
        for (int i=0; i<CHECKSIZE; i++ )
197
                if (CheckData[i] != CHECKBYTE ) {
198
                        ErrorCount++;
199
                        con_printf(CON_CRITICAL, "OA: %p ", &CheckData[i] );
200
                }
201
 
202
        if (ErrorCount &&  (!out_of_memory))    {
203
                con_printf(CON_CRITICAL, "\nMEM_OVERWRITE: Memory after the end of allocated block overwritten." );
204
                PrintInfo( block_number );
205
                con_printf(CON_CRITICAL, "\t%d/%d check bytes were overwritten.", ErrorCount, CHECKSIZE );
206
                Int3();
207
        }
208
 
209
        return ErrorCount;
210
 
211
}
212
 
213
void mem_free( void * buffer )
214
{
215
        int id;
216
 
217
        if (Initialized==0)
218
                mem_init();
219
 
220
#if MEMSTATS
221
        {
222
                unsigned long   theFreeMem = 0;
223
 
224
                if (sMemStatsFileInitialized)
225
                {
226
                        theFreeMem = FreeMem();
227
 
228
                        fprintf(sMemStatsFile,
229
                                        "\n%9u bytes free before attempting: FREE", theFreeMem);
230
                }
231
        }
232
#endif  // end of ifdef memstats
233
 
234
        if (buffer==NULL  &&  (!out_of_memory))
235
        {
236
                con_printf(CON_CRITICAL, "\nMEM_FREE_NULL: An attempt was made to free the null pointer." );
237
                Warning( "MEM: Freeing the NULL pointer!" );
238
                Int3();
239
                return;
240
        }
241
        id = mem_find_id( buffer );
242
 
243
        if (id==-1 &&  (!out_of_memory))
244
        {
245
                con_printf(CON_CRITICAL, "\nMEM_FREE_NOMALLOC: An attempt was made to free a ptr that wasn't\nallocated with mem.h included." );
246
                Warning( "MEM: Freeing a non-malloced pointer!" );
247
                Int3();
248
                return;
249
        }
250
 
251
        mem_check_integrity( id );
252
 
253
        BytesMalloced -= MallocSize[id];
254
 
255
        buffer = reinterpret_cast<char *>(buffer) - DXX_DEBUG_BIAS_MEMORY_ALLOCATION;
256
        free( buffer );
257
 
258
        Present[id] = 0;
259
        MallocBase[id] = 0;
260
        MallocSize[id] = 0;
261
 
262
        free_list[ --num_blocks ] = id;
263
}
264
 
265
void *mem_realloc(void *buffer, size_t size, const char *var, const char *filename, unsigned line)
266
{
267
        void *newbuffer;
268
        int id;
269
 
270
        if (Initialized==0)
271
                mem_init();
272
 
273
        if (size == 0) {
274
                mem_free(buffer);
275
                newbuffer = NULL;
276
        } else if (buffer == NULL) {
277
                newbuffer = mem_malloc(size, var, filename, line);
278
        } else {
279
                newbuffer = mem_malloc(size, var, filename, line);
280
                if (newbuffer != NULL) {
281
                        id = mem_find_id(buffer);
282
                        if (MallocSize[id] < size)
283
                                size = MallocSize[id];
284
                        memcpy(newbuffer, buffer, size);
285
                        mem_free(buffer);
286
                }
287
        }
288
        return newbuffer;
289
}
290
 
291
void mem_display_blocks()
292
{
293
        int numleft;
294
 
295
        if (Initialized==0) return;
296
 
297
#if MEMSTATS
298
        {      
299
                if (sMemStatsFileInitialized)
300
                {
301
                        unsigned long   theFreeMem = 0;
302
 
303
                        theFreeMem = FreeMem();
304
 
305
                        fprintf(sMemStatsFile,
306
                                        "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
307
                        fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
308
                        fclose(sMemStatsFile);
309
                }
310
        }
311
#endif  // end of ifdef memstats
312
 
313
        numleft = 0;
314
        for (int i=0; i<=LargestIndex; i++ )
315
        {
316
                if (Present[i]==1 &&  (!out_of_memory))
317
                {
318
                        numleft++;
319
                        if (CGameArg.DbgShowMemInfo)    {
320
                                con_printf(CON_CRITICAL, "\nMEM_LEAKAGE: Memory block has not been freed." );
321
                                PrintInfo( i );
322
                        }
323
                }
324
        }
325
 
326
        if (numleft &&  (!out_of_memory))
327
        {
328
                Warning( "MEM: %d blocks were left allocated!\n", numleft );
329
        }
330
 
331
}
332
 
333
void mem_validate_heap()
334
{
335
        for (int i=0; i<LargestIndex; i++  )
336
                if (Present[i]==1 )
337
                        mem_check_integrity( i );
338
}
339
 
340
#else
341
 
342
static int Initialized = 0;
343
static unsigned int SmallestAddress = 0xFFFFFFF;
344
static unsigned int LargestAddress = 0x0;
345
static unsigned int BytesMalloced = 0;
346
 
347
void mem_init()
348
{
349
        Initialized = 1;
350
 
351
        SmallestAddress = 0xFFFFFFF;
352
        LargestAddress = 0x0;
353
 
354
        atexit(mem_display_blocks);
355
}
356
 
357
void mem_display_blocks()
358
{
359
        if (Initialized==0) return;
360
 
361
#if MEMSTATS
362
        {      
363
                if (sMemStatsFileInitialized)
364
                {
365
                        unsigned long   theFreeMem = 0;
366
 
367
                        theFreeMem = FreeMem();
368
 
369
                        fprintf(sMemStatsFile,
370
                                        "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
371
                        fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
372
                        fclose(sMemStatsFile);
373
                }
374
        }
375
#endif  // end of ifdef memstats
376
 
377
        if (BytesMalloced != 0 )        {
378
                con_printf(CON_CRITICAL, "\nMEM_LEAKAGE: %d bytes of memory have not been freed.", BytesMalloced );
379
        }
380
 
381
        if (CGameArg.DbgShowMemInfo)    {
382
                con_printf(CON_CRITICAL, "\n\nMEMORY USAGE:" );
383
                con_printf(CON_CRITICAL, "  %u Kbytes dynamic data", (LargestAddress-SmallestAddress+512)/1024 );
384
                con_printf(CON_CRITICAL, "  %u Kbytes code/static data.", (SmallestAddress-(4*1024*1024)+512)/1024 );
385
                con_printf(CON_CRITICAL, "  ---------------------------" );
386
                con_printf(CON_CRITICAL, "  %u Kbytes required.",       (LargestAddress-(4*1024*1024)+512)/1024 );
387
        }
388
}
389
 
390
void mem_validate_heap()
391
{
392
}
393
 
394
#endif
395
#endif
396
 
397
}