1
/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany
3
* PrimeBase Media Stream for MySQL
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program 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
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
* Original author: Paul McCullagh (H&G2JCtL)
20
* Continued development: Barry Leslie
27
* For debugging memory leaks search for "DEBUG-BREAK-POINT" and watch mm_tracking_id
38
#include "CSException.h"
41
#include "CSStrUtil.h"
52
void *cs_malloc(size_t size)
56
if (!(ptr = malloc(size)))
57
CSException::throwOSError(CS_CONTEXT, ENOMEM);
61
void *cs_calloc(size_t size)
65
if (!(ptr = malloc(size)))
66
CSException::throwOSError(CS_CONTEXT, ENOMEM);
71
void cs_realloc(void **ptr, size_t size)
75
if (!(new_ptr = realloc(*ptr, size)))
76
CSException::throwOSError(CS_CONTEXT, ENOMEM);
80
void cs_free(void *ptr)
86
* -----------------------------------------------------------------------
87
* DEBUG MEMORY ALLOCATION AND HEAP CHECKING
94
#define ADD_TOTAL_ALLOCS 4000
96
#define SHIFT_RIGHT(ptr, n) memmove(((char *) (ptr)) + sizeof(MissingMemoryRec), (ptr), (long) (n) * sizeof(MissingMemoryRec))
97
#define SHIFT_LEFT(ptr, n) memmove((ptr), ((char *) (ptr)) + sizeof(MissingMemoryRec), (long) (n) * sizeof(MissingMemoryRec))
99
typedef struct MissingMemory {
102
const char *func_name;
103
const char *file_name;
105
} MissingMemoryRec, *MissingMemoryPtr;
107
static MissingMemoryRec *mm_addresses = NULL;
108
static u_int mm_nr_in_use = 0L;
109
static u_int mm_total_allocated = 0L;
110
static u_int mm_alloc_count = 0;
111
static pthread_mutex_t mm_mutex;
113
/* Set this variable to the ID of the memory you want
116
static u_int mm_tracking_id = 0;
118
static void mm_println(const char *str)
123
static long mm_find_pointer(void *ptr)
125
register long i, n, guess;
130
guess = (i + n - 1) >> 1;
131
if (ptr == mm_addresses[guess].ptr)
133
if (ptr < mm_addresses[guess].ptr)
141
static long mm_add_pointer(void *ptr)
143
register int i, n, guess;
145
if (mm_nr_in_use == mm_total_allocated) {
146
/* Not enough space, add more: */
147
MissingMemoryRec *new_addresses;
149
new_addresses = (MissingMemoryRec *) malloc(sizeof(MissingMemoryRec) * (mm_total_allocated + ADD_TOTAL_ALLOCS));
154
memcpy(new_addresses, mm_addresses, sizeof(MissingMemoryRec) * mm_total_allocated);
158
mm_addresses = new_addresses;
159
mm_total_allocated += ADD_TOTAL_ALLOCS;
165
guess = (i + n - 1) >> 1;
166
if (ptr < mm_addresses[guess].ptr)
172
SHIFT_RIGHT(&mm_addresses[i], mm_nr_in_use - i);
174
mm_addresses[i].ptr = ptr;
178
static char *cs_mm_watch_point = 0;
180
static long mm_remove_pointer(void *ptr)
182
register int i, n, guess;
184
if (cs_mm_watch_point == ptr)
185
printf("Hit watch point\n");
190
guess = (i + n - 1) >> 1;
191
if (ptr == mm_addresses[guess].ptr)
193
if (ptr < mm_addresses[guess].ptr)
201
/* Decrease the number of sets, and shift left: */
203
SHIFT_LEFT(&mm_addresses[guess], mm_nr_in_use - guess);
207
static void mm_throw_assertion(MissingMemoryPtr mm_ptr, void *p, const char *message)
212
snprintf(str, 200, "MM ERROR: %08p (#%"PRId32") %s:%"PRId32" %s",
215
cs_last_name_of_path(mm_ptr->file_name),
220
snprintf(str, 200, "MM ERROR: %08p %s", p, message);
224
static u_int mm_add_core_ptr(void *ptr, const char *func, const char *file, int line)
229
mm = mm_add_pointer(ptr);
231
mm_println("MM ERROR: Cannot allocate table big enough!");
235
/* Record the pointer: */
236
if (mm_alloc_count == mm_tracking_id) {
237
/* Enable you to set a breakpoint: */
238
id = mm_alloc_count++; // DEBUG-BREAK-POINT
241
id = mm_alloc_count++;
243
mm_addresses[mm].ptr = ptr;
244
mm_addresses[mm].id = id;
245
mm_addresses[mm].func_name = func;
247
mm_addresses[mm].file_name = file;
249
mm_addresses[mm].file_name = "?";
250
mm_addresses[mm].line_nr = line;
254
static void mm_remove_core_ptr(void *ptr)
258
mm = mm_remove_pointer(ptr);
260
mm_println("MM ERROR: Pointer not allocated");
265
static long mm_find_core_ptr(void *ptr)
269
mm = mm_find_pointer(ptr);
271
mm_throw_assertion(NULL, ptr, "Pointer not allocated");
275
static void mm_replace_core_ptr(long i, void *ptr)
277
MissingMemoryRec tmp = mm_addresses[i];
280
mm_remove_pointer(mm_addresses[i].ptr);
281
mm = mm_add_pointer(ptr);
283
mm_println("MM ERROR: Cannot allocate table big enough!");
286
mm_addresses[mm] = tmp;
287
mm_addresses[mm].ptr = ptr;
291
* -----------------------------------------------------------------------
292
* MISSING MEMORY PUBLIC ROUTINES
295
#define MEM_DEBUG_HDR_SIZE offsetof(MemoryDebugRec, data)
296
#define MEM_TRAILER_SIZE 2
297
#define MEM_HEADER 0x01010101
298
#define MEM_FREED 0x03030303
299
#define MEM_TRAILER_BYTE 0x02
300
#define MEM_FREED_BYTE 0x03
302
typedef struct MemoryDebug {
304
u_int md_id; /* The memory ID! */
307
} MemoryDebugRec, *MemoryDebugPtr;
309
static size_t mm_check_and_free(MissingMemoryPtr mm_ptr, void *p, bool freeme)
311
unsigned char *ptr = (unsigned char *) p - MEM_DEBUG_HDR_SIZE;
312
MemoryDebugPtr debug_ptr = (MemoryDebugPtr) ptr;
313
size_t size = debug_ptr->size;
314
long a_value; /* Added to simplfy debugging. */
318
if (!ASSERT(((size_t) p & 1L) == 0))
321
if (debug_ptr->check == MEM_FREED) {
322
mm_println("MM ERROR: Pointer already freed 'debug_ptr->check != MEM_FREED'");
325
a_value = MEM_HEADER;
326
if (debug_ptr->check != MEM_HEADER) {
327
mm_println("MM ERROR: Header not valid 'debug_ptr->check != MEM_HEADER'");
330
a_value = MEM_TRAILER_BYTE;
331
if (!(*((unsigned char *) ptr + size + MEM_DEBUG_HDR_SIZE) == MEM_TRAILER_BYTE &&
332
*((unsigned char *) ptr + size + MEM_DEBUG_HDR_SIZE + 1L) == MEM_TRAILER_BYTE)) {
333
mm_throw_assertion(mm_ptr, p, "Trailer overwritten");
338
debug_ptr->check = MEM_FREED;
339
*((unsigned char *) ptr + size + MEM_DEBUG_HDR_SIZE) = MEM_FREED_BYTE;
340
*((unsigned char *) ptr + size + MEM_DEBUG_HDR_SIZE + 1L) = MEM_FREED_BYTE;
342
memset(((unsigned char *) ptr) + MEM_DEBUG_HDR_SIZE, 0xF5, size);
349
bool cs_mm_scan_core(void)
357
pthread_mutex_lock(&mm_mutex);
359
for (mm=0; mm<mm_nr_in_use; mm++) {
360
if (!mm_check_and_free(&mm_addresses[mm], mm_addresses[mm].ptr, false))
364
pthread_mutex_unlock(&mm_mutex);
368
void cs_mm_memmove(void *block, void *dest, void *source, size_t size)
371
MemoryDebugPtr debug_ptr = (MemoryDebugPtr) ((char *) block - MEM_DEBUG_HDR_SIZE);
374
pthread_mutex_lock(&mm_mutex);
375
mm_find_core_ptr(block);
376
pthread_mutex_unlock(&mm_mutex);
378
mm_check_and_free(NULL, block, false);
380
if (dest < block || (char *) dest > (char *) block + debug_ptr->size) {
381
mm_println("MM ERROR: Destination not in block");
384
if ((char *) dest + size > (char *) block + debug_ptr->size) {
385
mm_println("MM ERROR: Copy will overwrite memory");
390
memmove(dest, source, size);
393
void cs_mm_memcpy(void *block, void *dest, void *source, size_t size)
396
MemoryDebugPtr debug_ptr = (MemoryDebugPtr) ((char *) block - MEM_DEBUG_HDR_SIZE);
399
pthread_mutex_lock(&mm_mutex);
400
mm_find_core_ptr(block);
401
pthread_mutex_unlock(&mm_mutex);
403
mm_check_and_free(NULL, block, false);
405
if (dest < block || (char *) dest > (char *) block + debug_ptr->size)
406
mm_throw_assertion(NULL, block, "Destination not in block");
407
if ((char *) dest + size > (char *) block + debug_ptr->size)
408
mm_throw_assertion(NULL, block, "Copy will overwrite memory");
411
memcpy(dest, source, size);
414
void cs_mm_memset(void *block, void *dest, int value, size_t size)
417
MemoryDebugPtr debug_ptr = (MemoryDebugPtr) ((char *) block - MEM_DEBUG_HDR_SIZE);
420
pthread_mutex_lock(&mm_mutex);
421
mm_find_core_ptr(block);
422
pthread_mutex_unlock(&mm_mutex);
424
mm_check_and_free(NULL, block, false);
426
if (dest < block || (char *) dest > (char *) block + debug_ptr->size)
427
mm_throw_assertion(NULL, block, "Destination not in block");
428
if ((char *) dest + size > (char *) block + debug_ptr->size)
429
mm_throw_assertion(NULL, block, "Copy will overwrite memory");
432
memset(dest, value, size);
435
void *cs_mm_malloc(const char *func, const char *file, int line, size_t size)
437
unsigned char *p = (unsigned char *) cs_malloc(size + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE);
442
memset(p, 0x55, size + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE);
444
((MemoryDebugPtr) p)->check = MEM_HEADER;
445
((MemoryDebugPtr) p)->md_id = 0;
446
((MemoryDebugPtr) p)->size = (u_int) size;
447
*(p + size + MEM_DEBUG_HDR_SIZE) = MEM_TRAILER_BYTE;
448
*(p + size + MEM_DEBUG_HDR_SIZE + 1L) = MEM_TRAILER_BYTE;
451
pthread_mutex_lock(&mm_mutex);
452
((MemoryDebugPtr) p)->md_id = mm_add_core_ptr(p + MEM_DEBUG_HDR_SIZE, func, file, line);
453
pthread_mutex_unlock(&mm_mutex);
456
return p + MEM_DEBUG_HDR_SIZE;
459
void *cs_mm_calloc(const char *func, const char *file, int line, size_t size)
461
unsigned char *p = (unsigned char *) cs_calloc(size + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE);
466
((MemoryDebugPtr) p)->check = MEM_HEADER;
467
((MemoryDebugPtr) p)->md_id = 0;
468
((MemoryDebugPtr) p)->size = (u_int) size;
469
*(p + size + MEM_DEBUG_HDR_SIZE) = MEM_TRAILER_BYTE;
470
*(p + size + MEM_DEBUG_HDR_SIZE + 1L) = MEM_TRAILER_BYTE;
473
pthread_mutex_lock(&mm_mutex);
474
((MemoryDebugPtr) p)->md_id = mm_add_core_ptr(p + MEM_DEBUG_HDR_SIZE, func, file, line);
475
pthread_mutex_unlock(&mm_mutex);
478
return p + MEM_DEBUG_HDR_SIZE;
481
void cs_mm_realloc(const char *func, const char *file, int line, void **ptr, size_t newsize)
483
unsigned char *oldptr = (unsigned char *) *ptr;
489
*ptr = cs_mm_malloc(func, file, line, newsize);
494
// The lock must be held until the realloc has completed otherwise
495
// a scan of the memory may report a bad memory header.
496
pthread_mutex_lock(&mm_mutex);
497
if ((mm = mm_find_core_ptr(oldptr)) < 0) {
498
pthread_mutex_unlock(&mm_mutex);
499
CSException::throwOSError(CS_CONTEXT, ENOMEM);
501
// pthread_mutex_unlock(&mm_mutex); It will be unlocked below
504
oldptr = oldptr - MEM_DEBUG_HDR_SIZE;
505
size = ((MemoryDebugPtr) oldptr)->size;
507
ASSERT(((MemoryDebugPtr) oldptr)->check == MEM_HEADER);
508
ASSERT(*((unsigned char *) oldptr + size + MEM_DEBUG_HDR_SIZE) == MEM_TRAILER_BYTE &&
509
*((unsigned char *) oldptr + size + MEM_DEBUG_HDR_SIZE + 1L) == MEM_TRAILER_BYTE);
511
/* Grow allways moves! */
512
pnew = (unsigned char *) cs_malloc(newsize + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE);
515
pthread_mutex_unlock(&mm_mutex);
517
CSException::throwOSError(CS_CONTEXT, ENOMEM);
521
if (newsize > size) {
522
memcpy(((MemoryDebugPtr) pnew)->data, ((MemoryDebugPtr) oldptr)->data, size);
523
memset(((MemoryDebugPtr) pnew)->data + size, 0x55, newsize - size);
526
memcpy(((MemoryDebugPtr) pnew)->data, ((MemoryDebugPtr) oldptr)->data, newsize);
527
memset(oldptr, 0x55, size + MEM_DEBUG_HDR_SIZE + MEM_TRAILER_SIZE);
530
// pthread_mutex_lock(&mm_mutex); It was locked above
531
if ((mm = mm_find_core_ptr(oldptr + MEM_DEBUG_HDR_SIZE)) < 0) {
532
pthread_mutex_unlock(&mm_mutex);
533
CSException::throwOSError(CS_CONTEXT, ENOMEM);
536
mm_replace_core_ptr(mm, pnew + MEM_DEBUG_HDR_SIZE);
537
pthread_mutex_unlock(&mm_mutex);
542
((MemoryDebugPtr) pnew)->check = MEM_HEADER;
543
((MemoryDebugPtr) pnew)->size = (u_int) newsize;
544
*(pnew + newsize + MEM_DEBUG_HDR_SIZE) = MEM_TRAILER_BYTE;
545
*(pnew + newsize + MEM_DEBUG_HDR_SIZE + 1L) = MEM_TRAILER_BYTE;
547
*ptr = pnew + MEM_DEBUG_HDR_SIZE;
550
void cs_mm_free(void *ptr)
552
bool my_pointer = false;
555
pthread_mutex_lock(&mm_mutex);
556
if (mm_find_pointer(ptr) >= 0) {
558
mm_remove_core_ptr(ptr);
560
pthread_mutex_unlock(&mm_mutex);
563
mm_check_and_free(NULL, ptr, true);
568
void cs_mm_pfree(void **ptr)
578
size_t cs_mm_malloc_size(void *ptr)
583
pthread_mutex_lock(&mm_mutex);
584
mm_find_core_ptr(ptr);
585
pthread_mutex_unlock(&mm_mutex);
587
size = mm_check_and_free(NULL, ptr, false);
591
void cs_mm_print_track(const char *func, const char *file, u_int line, void *p, bool inc, u_int ref_cnt, int track_me)
593
unsigned char *ptr = (unsigned char *) p - MEM_DEBUG_HDR_SIZE;
594
MemoryDebugPtr debug_ptr = (MemoryDebugPtr) ptr;
595
CSThread *self = CSThread::getSelf();
599
if (!track_me && !mm_tracking_id)
603
cs_format_context(300, buffer, func, file, line);
604
printf("TRACKING (%"PRIu32"): %s %2"PRIu32" %s", debug_ptr->md_id, inc ? "INC" : "DEC", ref_cnt, buffer);
607
printf("TRACKING (%"PRIu32"): %s %2"PRIu32"", debug_ptr->md_id, inc ? "INC" : "DEC", ref_cnt);
609
for (int i = self->callTop-1; i>=0 && cnt < 4; i--) {
610
cs_format_context(300, buffer, self->callStack[i].cs_func, self->callStack[i].cs_file, self->callStack[i].cs_line);
611
printf(" %s", buffer);
617
void cs_mm_track_memory(const char *func, const char *file, u_int line, void *p, bool inc, u_int ref_cnt, int track_me)
619
unsigned char *ptr = (unsigned char *) p - MEM_DEBUG_HDR_SIZE;
620
MemoryDebugPtr debug_ptr = (MemoryDebugPtr) ptr;
622
if (track_me || (mm_tracking_id && debug_ptr->md_id == mm_tracking_id))
623
cs_mm_print_track(func, file, line, p, inc, ref_cnt, track_me);
629
* -----------------------------------------------------------------------
633
bool cs_init_memory(void)
636
pthread_mutex_init(&mm_mutex, NULL);
637
mm_addresses = (MissingMemoryRec *) malloc(sizeof(MissingMemoryRec) * ADD_TOTAL_ALLOCS);
639
mm_println("MM ERROR: Insuffient memory to allocate MM table");
640
pthread_mutex_destroy(&mm_mutex);
644
memset(mm_addresses, 0, sizeof(MissingMemoryRec) * ADD_TOTAL_ALLOCS);
645
mm_total_allocated = ADD_TOTAL_ALLOCS;
652
void cs_exit_memory(void)
660
pthread_mutex_lock(&mm_mutex);
661
for (mm=0; mm<mm_nr_in_use; mm++)
662
mm_throw_assertion(&mm_addresses[mm], mm_addresses[mm].ptr, "Not freed");
666
mm_total_allocated = 0L;
668
pthread_mutex_unlock(&mm_mutex);
670
pthread_mutex_destroy(&mm_mutex);