91d9035d2ecd2a4aa7cc154786c18d3ab285527d
[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 /* cookies for anybody who recognizes these bytes without help :) */
23 #define ALLOC_MAGIC 0x1acf
24 #define FREE_MAGIC  0xfc1d
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
36 static int
37 file_id_cmp(const void *a_, const void *b_)
38 {
39     return strcmp(a_, b_);
40 }
41
42 static unsigned int
43 get_file_id(const char *fname)
44 {
45     void *entry;
46
47     entry = bsearch(fname, file_id_map, file_ids_used, sizeof(file_id_map[0]), file_id_cmp);
48     if (entry)
49         return ((char*)entry - file_id_map[0]) / sizeof(file_id_map[0]);
50     strcpy(file_id_map[file_ids_used++], fname);
51     qsort(file_id_map, file_ids_used, sizeof(file_id_map[0]), file_id_cmp);
52     return file_ids_used - 1;
53 }
54
55 void *
56 srvx_malloc(const char *file, unsigned int line, size_t size)
57 {
58     struct alloc_header *block;
59
60     block = malloc(sizeof(*block) + size);
61     assert(block != NULL);
62     memset(block, 0, sizeof(*block) + size);
63     block->file_id = get_file_id(file);
64     block->line = line;
65     block->size = size;
66     block->magic = ALLOC_MAGIC;
67     return block + 1;
68 }
69
70 void *
71 srvx_realloc(const char *file, unsigned int line, void *ptr, size_t size)
72 {
73     struct alloc_header *block = NULL, *newblock;
74
75     if (ptr) {
76         block = (struct alloc_header *)ptr - 1;
77         assert(block->magic == ALLOC_MAGIC);
78         if (block->size >= size)
79             return block + 1;
80     }
81
82     newblock = malloc(sizeof(*newblock) + size);
83     assert(newblock != NULL);
84     memset(newblock, 0, sizeof(*newblock) + size);
85     newblock->file_id = get_file_id(file);
86     newblock->line = line;
87     newblock->size = size;
88     newblock->magic = ALLOC_MAGIC;
89
90     if (ptr) {
91         memcpy(newblock + 1, block + 1, block->size);
92         size = block->size + sizeof(*block);
93         memset(block, 0, size);
94         block->magic = FREE_MAGIC;
95         free(block);
96     }
97
98     return newblock + 1;
99 }
100
101 char *
102 srvx_strdup(const char *file, unsigned int line, const char *src)
103 {
104     char *target;
105     size_t len;
106
107     len = strlen(src) + 1;
108     target = srvx_malloc(file, line, len);
109     memcpy(target, src, len);
110     return target;
111 }
112
113 void
114 srvx_free(const char *file, unsigned int line, void *ptr)
115 {
116     struct alloc_header *block;
117     size_t size;
118
119     if (!ptr)
120         return;
121     block = (struct alloc_header *)ptr - 1;
122     assert(block->magic == ALLOC_MAGIC);
123     size = block->size + sizeof(*block);
124     memset(block, 0, size);
125     block->magic = FREE_MAGIC;
126     free(block);
127     (void)file; (void)line;
128 }