HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / wmem / wmem_allocator_strict.c
bloba67720c7a47c556800f6e4735408bcb69585b18f
1 /* wmem_allocator_strict.c
2 * Wireshark Memory Manager Strict Allocator
3 * Copyright 2012, Evan Huus <eapache@gmail.com>
5 * $Id$
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "config.h"
28 #include <string.h>
30 #include <glib.h>
32 #include "wmem_core.h"
33 #include "wmem_allocator.h"
35 /* In this allocator, we do everything we can to catch invalid memory accesses.
36 * This includes using canaries (what Valgrind calls redzones) and
37 * filling allocated and freed memory with garbage. Valgrind is still the
38 * better tool on the platforms where it is available - use it instead if
39 * possible.
42 #define WMEM_CANARY_SIZE 4 /* in bytes */
43 #define WMEM_CANARY_VALUE 0x9E
45 #define WMEM_PREFILL 0xA1
46 #define WMEM_POSTFILL 0x1A
48 typedef struct _wmem_strict_allocator_block_t {
49 /* Just the length of real_data, not counting the canaries */
50 gsize data_len;
52 guint8 *leading_canary;
53 guint8 *real_data;
54 guint8 *trailing_canary;
55 } wmem_strict_allocator_block_t;
57 typedef struct _wmem_strict_allocator_t {
58 GHashTable *block_table;
59 } wmem_strict_allocator_t;
62 * some internal helper functions
64 static void
65 wmem_strict_block_check_canaries(wmem_strict_allocator_block_t *block)
67 guint i;
69 for (i=0; i<WMEM_CANARY_SIZE; i++) {
70 g_assert(block->leading_canary[i] == WMEM_CANARY_VALUE);
71 g_assert(block->trailing_canary[i] == WMEM_CANARY_VALUE);
75 /* wrapper for use with g_hash_table_foreach() */
76 static void
77 wmem_strict_ghash_check_canaries(gpointer key _U_, gpointer value,
78 gpointer user_data _U_)
80 wmem_strict_block_check_canaries((wmem_strict_allocator_block_t *)value);
83 static void
84 wmem_strict_block_free(wmem_strict_allocator_block_t *block)
86 memset(block->real_data, WMEM_POSTFILL, block->data_len);
88 wmem_free(NULL, block->leading_canary);
89 wmem_free(NULL, block);
92 /* wrapper for use with g_hash_table_new_full() */
93 static void
94 wmem_strict_ghash_block_free(gpointer data)
96 wmem_strict_block_free((wmem_strict_allocator_block_t *)data);
99 static wmem_strict_allocator_block_t *
100 wmem_strict_block_new(const size_t size)
102 wmem_strict_allocator_block_t *block;
103 guint i;
105 block = wmem_new(NULL, wmem_strict_allocator_block_t);
107 block->data_len = size;
108 block->leading_canary = (guint8 *)wmem_alloc(NULL, block->data_len + (2 * WMEM_CANARY_SIZE));
109 block->real_data = block->leading_canary + WMEM_CANARY_SIZE;
110 block->trailing_canary = block->real_data + block->data_len;
112 memset(block->real_data, WMEM_PREFILL, block->data_len);
113 for (i=0; i<WMEM_CANARY_SIZE; i++) {
114 block->leading_canary[i] = WMEM_CANARY_VALUE;
115 block->trailing_canary[i] = WMEM_CANARY_VALUE;
118 return block;
122 * public API functions
124 static void *
125 wmem_strict_alloc(void *private_data, const size_t size)
127 wmem_strict_allocator_t *allocator;
128 wmem_strict_allocator_block_t *block;
130 allocator = (wmem_strict_allocator_t*) private_data;
132 block = wmem_strict_block_new(size);
134 /* we store a pointer to our header, keyed by a pointer to the actual
135 * block we return to the user */
136 g_hash_table_insert(allocator->block_table, block->real_data, block);
138 return block->real_data;
141 static void
142 wmem_strict_free(void *private_data, void *ptr)
144 wmem_strict_allocator_t *allocator;
145 wmem_strict_allocator_block_t *block;
147 allocator = (wmem_strict_allocator_t*) private_data;
149 block = (wmem_strict_allocator_block_t *)g_hash_table_lookup(allocator->block_table, ptr);
151 g_assert(block);
153 wmem_strict_block_check_canaries(block);
155 g_hash_table_remove(allocator->block_table, ptr);
158 static void *
159 wmem_strict_realloc(void *private_data, void *ptr, const size_t size)
161 gsize copy_len;
162 wmem_strict_allocator_t *allocator;
163 wmem_strict_allocator_block_t *block, *newblock;
165 allocator = (wmem_strict_allocator_t*) private_data;
167 /* retrieve and check the old block */
168 block = (wmem_strict_allocator_block_t *)g_hash_table_lookup(allocator->block_table, ptr);
169 g_assert(block);
170 wmem_strict_block_check_canaries(block);
172 /* create a new block */
173 newblock = wmem_strict_block_new(size);
175 /* copy from the old block to the new */
176 if (block->data_len > newblock->data_len) {
177 copy_len = newblock->data_len;
179 else {
180 copy_len = block->data_len;
183 memcpy(newblock->real_data, block->real_data, copy_len);
185 /* update the hash table */
186 g_hash_table_remove(allocator->block_table, ptr);
187 g_hash_table_insert(allocator->block_table, newblock->real_data, newblock);
189 return newblock->real_data;
192 void
193 wmem_strict_check_canaries(wmem_allocator_t *allocator)
195 wmem_strict_allocator_t *private_allocator;
197 if (allocator->type != WMEM_ALLOCATOR_STRICT) {
198 return;
201 private_allocator = (wmem_strict_allocator_t*) allocator->private_data;
203 g_hash_table_foreach(private_allocator->block_table,
204 &wmem_strict_ghash_check_canaries, NULL);
207 static void
208 wmem_strict_free_all(void *private_data)
210 wmem_strict_allocator_t *allocator;
212 allocator = (wmem_strict_allocator_t*) private_data;
214 g_hash_table_foreach(allocator->block_table,
215 &wmem_strict_ghash_check_canaries, NULL);
217 g_hash_table_remove_all(allocator->block_table);
220 static void
221 wmem_strict_gc(void *private_data _U_)
223 /* We don't really have anything to garbage-collect, but it might be worth
224 * checking our canaries at this point? */
227 static void
228 wmem_strict_allocator_cleanup(void *private_data)
230 wmem_strict_allocator_t *allocator;
232 allocator = (wmem_strict_allocator_t*) private_data;
234 g_hash_table_destroy(allocator->block_table);
235 wmem_free(NULL, allocator);
238 void
239 wmem_strict_allocator_init(wmem_allocator_t *allocator)
241 wmem_strict_allocator_t *strict_allocator;
243 strict_allocator = wmem_new(NULL, wmem_strict_allocator_t);
245 allocator->alloc = &wmem_strict_alloc;
246 allocator->realloc = &wmem_strict_realloc;
247 allocator->free = &wmem_strict_free;
249 allocator->free_all = &wmem_strict_free_all;
250 allocator->gc = &wmem_strict_gc;
251 allocator->cleanup = &wmem_strict_allocator_cleanup;
253 allocator->private_data = (void*) strict_allocator;
255 strict_allocator->block_table = g_hash_table_new_full(
256 &g_direct_hash, &g_direct_equal,
257 NULL, &wmem_strict_ghash_block_free);
261 * Editor modelines - http://www.wireshark.org/tools/modelines.html
263 * Local variables:
264 * c-basic-offset: 4
265 * tab-width: 8
266 * indent-tabs-mode: nil
267 * End:
269 * vi: set shiftwidth=4 tabstop=8 expandtab:
270 * :indentSize=4:tabSize=8:noTabs=true: