]>
Commit | Line | Data |
---|---|---|
83ff05c3 | 1 | /* alloc-x3.c - Debug allocation wrapper |
ec1a68c8 | 2 | * Copyright 2005 srvx Development Team |
3 | * | |
2f61d1d7 | 4 | * This file is part of srvx. |
ec1a68c8 | 5 | * |
d0f04f71 | 6 | * x3 is free software; you can redistribute it and/or modify |
ec1a68c8 | 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" | |
0d16e639 | 18 | #include "log.h" |
ec1a68c8 | 19 | |
20 | #undef malloc | |
21 | #undef free | |
2f61d1d7 | 22 | |
ec1a68c8 | 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 * | |
83ff05c3 | 58 | x3_malloc(const char *file, unsigned int line, size_t size) |
ec1a68c8 | 59 | { |
60 | struct alloc_header *block; | |
2f61d1d7 | 61 | |
ec1a68c8 | 62 | block = malloc(sizeof(*block) + size + sizeof(redzone)); |
63 | assert(block != NULL); | |
0d16e639 | 64 | if (block->magic == ALLOC_MAGIC && block->file_id < file_ids_used) { |
65 | /* Only report the error, due to possible false positives. */ | |
2f61d1d7 | 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); | |
0d16e639 | 69 | } |
ec1a68c8 | 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 * | |
83ff05c3 | 82 | x3_realloc(const char *file, unsigned int line, void *ptr, size_t size) |
2f61d1d7 | 83 | { |
ec1a68c8 | 84 | struct alloc_header *block, *newblock; |
2f61d1d7 | 85 | |
ec1a68c8 | 86 | if (!ptr) |
83ff05c3 | 87 | return x3_malloc(file, line, size); |
ec1a68c8 | 88 | |
89 | verify(ptr); | |
90 | block = (struct alloc_header *)ptr - 1; | |
91 | ||
92 | if (block->size >= size) | |
93 | return block + 1; | |
2f61d1d7 | 94 | |
ec1a68c8 | 95 | newblock = malloc(sizeof(*newblock) + size + sizeof(redzone)); |
2f61d1d7 | 96 | assert(newblock != NULL); |
ec1a68c8 | 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; | |
2f61d1d7 | 107 | |
83ff05c3 | 108 | x3_free(file, line, block + 1); |
ec1a68c8 | 109 | |
110 | return newblock + 1; | |
111 | } | |
112 | ||
113 | char * | |
83ff05c3 | 114 | x3_strdup(const char *file, unsigned int line, const char *src) |
ec1a68c8 | 115 | { |
116 | char *target; | |
117 | size_t len; | |
118 | ||
119 | len = strlen(src) + 1; | |
83ff05c3 | 120 | target = x3_malloc(file, line, len); |
ec1a68c8 | 121 | memcpy(target, src, len); |
122 | return target; | |
123 | } | |
124 | ||
2f61d1d7 | 125 | void |
83ff05c3 | 126 | x3_free(UNUSED_ARG(const char *file), UNUSED_ARG(unsigned int line), void *ptr) |
ec1a68c8 | 127 | { |
128 | struct alloc_header *block; | |
129 | size_t size; | |
130 | ||
131 | if (!ptr) | |
132 | return; | |
0d16e639 | 133 | verify(ptr); |
2f61d1d7 | 134 | block = (struct alloc_header *)ptr - 1; |
ec1a68c8 | 135 | size = block->size; |
136 | memset(block + 1, 0xde, size); | |
137 | block->magic = FREE_MAGIC; | |
138 | free(block); | |
2f61d1d7 | 139 | alloc_count--; |
140 | alloc_size -= size; | |
ec1a68c8 | 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 | } |