72fca5a6e10947d9b8437d8936a05149e7a66014
[srvx.git] / src / alloc-srvx.c
1 /* alloc-srvx.c - Debug allocation wrapper
2  * Copyright 2005 srvx Development Team
3  *
4  * This file is part of srvx.
5  *
6  * srvx is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16
17 #include "common.h"
18
19 #undef malloc
20 #undef free
21
22 #define ALLOC_MAGIC 0x1acf
23 #define FREE_MAGIC  0xfc1d
24 const char redzone[] = { '\x03', '\x47', '\x76', '\xc7' };
25
26 struct alloc_header {
27     unsigned int file_id : 8;
28     unsigned int size : 24;
29     unsigned int line : 16;
30     unsigned int magic : 16;
31 };
32
33 static char file_id_map[256][32];
34 static unsigned int file_ids_used;
35 unsigned long alloc_count, alloc_size;
36
37 static int
38 file_id_cmp(const void *a_, const void *b_)
39 {
40     return strcmp(a_, b_);
41 }
42
43 static unsigned int
44 get_file_id(const char *fname)
45 {
46     void *entry;
47
48     entry = bsearch(fname, file_id_map, file_ids_used, sizeof(file_id_map[0]), file_id_cmp);
49     if (entry)
50         return ((char*)entry - file_id_map[0]) / sizeof(file_id_map[0]);
51     strcpy(file_id_map[file_ids_used++], fname);
52     qsort(file_id_map, file_ids_used, sizeof(file_id_map[0]), file_id_cmp);
53     return file_ids_used - 1;
54 }
55
56 void *
57 srvx_malloc(const char *file, unsigned int line, size_t size)
58 {
59     struct alloc_header *block;
60
61     block = malloc(sizeof(*block) + size + sizeof(redzone));
62     assert(block != NULL);
63     memset(block, 0, sizeof(*block) + size);
64     memcpy((char*)(block + 1) + size, redzone, sizeof(redzone));
65     block->file_id = get_file_id(file);
66     block->line = line;
67     block->size = size;
68     block->magic = ALLOC_MAGIC;
69     alloc_count++;
70     alloc_size += size;
71     return block + 1;
72 }
73
74 void *
75 srvx_realloc(const char *file, unsigned int line, void *ptr, size_t size)
76 {
77     struct alloc_header *block, *newblock;
78
79     if (!ptr)
80         return srvx_malloc(file, line, size);
81
82     verify(ptr);
83     block = (struct alloc_header *)ptr - 1;
84
85     if (block->size >= size)
86         return block + 1;
87
88     newblock = malloc(sizeof(*newblock) + size + sizeof(redzone));
89     assert(newblock != NULL);
90     memset(newblock, 0, sizeof(*newblock));
91     memcpy(newblock + 1, block + 1, block->size);
92     memset((char*)(newblock + 1) + block->size, 0, size - block->size);
93     memcpy((char*)(newblock + 1) + size, redzone, sizeof(redzone));
94     newblock->file_id = get_file_id(file);
95     newblock->line = line;
96     newblock->size = size;
97     newblock->magic = ALLOC_MAGIC;
98     alloc_count++;
99     alloc_size += size;
100
101     srvx_free(file, line, block + 1);
102
103     return newblock + 1;
104 }
105
106 char *
107 srvx_strdup(const char *file, unsigned int line, const char *src)
108 {
109     char *target;
110     size_t len;
111
112     len = strlen(src) + 1;
113     target = srvx_malloc(file, line, len);
114     memcpy(target, src, len);
115     return target;
116 }
117
118 void
119 srvx_free(const char *file, unsigned int line, void *ptr)
120 {
121     struct alloc_header *block;
122     size_t size;
123
124     if (!ptr)
125         return;
126     block = (struct alloc_header *)ptr - 1;
127     assert(block->magic == ALLOC_MAGIC);
128     assert(0 == memcmp((char*)(block + 1) + block->size, redzone, sizeof(redzone)));
129     size = block->size;
130     memset(block + 1, 0xde, size);
131     block->magic = FREE_MAGIC;
132     free(block);
133     alloc_count--;
134     alloc_size -= size;
135     (void)file; (void)line;
136 }
137
138 void
139 verify(const void *ptr)
140 {
141     const struct alloc_header *header;
142     if (!ptr)
143         return;
144     header = (const struct alloc_header*)ptr - 1;
145     assert(header->magic == ALLOC_MAGIC);
146     assert(!memcmp((char*)(header + 1) + header->size, redzone, sizeof(redzone)));
147 }