]>
Commit | Line | Data |
---|---|---|
1 | /* alloc-x3.c - Debug allocation wrapper | |
2 | * Copyright 2005 srvx Development Team | |
3 | * | |
4 | * This file is part of srvx. | |
5 | * | |
6 | * x3 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 | #include "log.h" | |
19 | ||
20 | #undef malloc | |
21 | #undef free | |
22 | ||
23 | #define ALLOC_MAGIC 0x1acf | |
24 | #define FREE_MAGIC 0xfc1d | |
25 | const char redzone[] = { '\x03', '\x47', '\x76', '\xc7' }; | |
26 | ||
27 | struct alloc_header { | |
28 | unsigned int file_id : 8; | |
29 | unsigned int size : 24; | |
30 | unsigned int line : 16; | |
31 | unsigned int magic : 16; | |
32 | }; | |
33 | ||
34 | static char file_id_map[256][32]; | |
35 | static unsigned int file_ids_used; | |
36 | unsigned long alloc_count, alloc_size; | |
37 | ||
38 | static int | |
39 | file_id_cmp(const void *a_, const void *b_) | |
40 | { | |
41 | return strcmp(a_, b_); | |
42 | } | |
43 | ||
44 | static unsigned int | |
45 | get_file_id(const char *fname) | |
46 | { | |
47 | void *entry; | |
48 | ||
49 | entry = bsearch(fname, file_id_map, file_ids_used, sizeof(file_id_map[0]), file_id_cmp); | |
50 | if (entry) | |
51 | return ((char*)entry - file_id_map[0]) / sizeof(file_id_map[0]); | |
52 | strcpy(file_id_map[file_ids_used++], fname); | |
53 | qsort(file_id_map, file_ids_used, sizeof(file_id_map[0]), file_id_cmp); | |
54 | return file_ids_used - 1; | |
55 | } | |
56 | ||
57 | void * | |
58 | x3_malloc(const char *file, unsigned int line, size_t size) | |
59 | { | |
60 | struct alloc_header *block; | |
61 | ||
62 | block = malloc(sizeof(*block) + size + sizeof(redzone)); | |
63 | assert(block != NULL); | |
64 | if (block->magic == ALLOC_MAGIC && block->file_id < file_ids_used) { | |
65 | /* Only report the error, due to possible false positives. */ | |
66 | log_module(MAIN_LOG, LOG_WARNING, "Detected possible reallocation: %p (called by %s:%u/%lu; allocated by %u:%u/%u).", | |
67 | block, file, line, (unsigned long)size, | |
68 | block->file_id, block->line, block->size); | |
69 | } | |
70 | memset(block, 0, sizeof(*block) + size); | |
71 | memcpy((char*)(block + 1) + size, redzone, sizeof(redzone)); | |
72 | block->file_id = get_file_id(file); | |
73 | block->line = line; | |
74 | block->size = size; | |
75 | block->magic = ALLOC_MAGIC; | |
76 | alloc_count++; | |
77 | alloc_size += size; | |
78 | return block + 1; | |
79 | } | |
80 | ||
81 | void * | |
82 | x3_realloc(const char *file, unsigned int line, void *ptr, size_t size) | |
83 | { | |
84 | struct alloc_header *block, *newblock; | |
85 | ||
86 | if (!ptr) | |
87 | return x3_malloc(file, line, size); | |
88 | ||
89 | verify(ptr); | |
90 | block = (struct alloc_header *)ptr - 1; | |
91 | ||
92 | if (block->size >= size) | |
93 | return block + 1; | |
94 | ||
95 | newblock = malloc(sizeof(*newblock) + size + sizeof(redzone)); | |
96 | assert(newblock != NULL); | |
97 | memset(newblock, 0, sizeof(*newblock)); | |
98 | memcpy(newblock + 1, block + 1, block->size); | |
99 | memset((char*)(newblock + 1) + block->size, 0, size - block->size); | |
100 | memcpy((char*)(newblock + 1) + size, redzone, sizeof(redzone)); | |
101 | newblock->file_id = get_file_id(file); | |
102 | newblock->line = line; | |
103 | newblock->size = size; | |
104 | newblock->magic = ALLOC_MAGIC; | |
105 | alloc_count++; | |
106 | alloc_size += size; | |
107 | ||
108 | x3_free(file, line, block + 1); | |
109 | ||
110 | return newblock + 1; | |
111 | } | |
112 | ||
113 | char * | |
114 | x3_strdup(const char *file, unsigned int line, const char *src) | |
115 | { | |
116 | char *target; | |
117 | size_t len; | |
118 | ||
119 | len = strlen(src) + 1; | |
120 | target = x3_malloc(file, line, len); | |
121 | memcpy(target, src, len); | |
122 | return target; | |
123 | } | |
124 | ||
125 | void | |
126 | x3_free(UNUSED_ARG(const char *file), UNUSED_ARG(unsigned int line), void *ptr) | |
127 | { | |
128 | struct alloc_header *block; | |
129 | size_t size; | |
130 | ||
131 | if (!ptr) | |
132 | return; | |
133 | verify(ptr); | |
134 | block = (struct alloc_header *)ptr - 1; | |
135 | size = block->size; | |
136 | memset(block + 1, 0xde, size); | |
137 | block->magic = FREE_MAGIC; | |
138 | free(block); | |
139 | alloc_count--; | |
140 | alloc_size -= size; | |
141 | } | |
142 | ||
143 | void | |
144 | verify(const void *ptr) | |
145 | { | |
146 | const struct alloc_header *header; | |
147 | if (!ptr) | |
148 | return; | |
149 | header = (const struct alloc_header*)ptr - 1; | |
150 | assert(header->magic == ALLOC_MAGIC); | |
151 | assert(!memcmp((char*)(header + 1) + header->size, redzone, sizeof(redzone))); | |
152 | } | |
153 | ||
154 |