|
1 | | -/* |
2 | | - * my_malloc.c |
3 | | - * |
4 | | - * This file provides an interface to malloc() and free() which |
5 | | - * |
6 | | - * (1) Keeps track of the number of calls to malloc() minus the number |
7 | | - * of calls to free(). This allows easy detection of programming |
8 | | - * errors which allocate more memory than they free (or vice versa). |
9 | | - * |
10 | | - * (2) Aborts the program if malloc() returns NULL. This saves having |
11 | | - * to check whether malloc() == NULL at each point where malloc() |
12 | | - * is called. |
13 | | - * |
14 | | - * All kernel routines use my_malloc() and my_free(); |
15 | | - * no UI routines do so. |
16 | | - * |
17 | | - * The UI should call verify_my_malloc_usage() upon exit, to verify |
18 | | - * that the number of calls to my_malloc() was exactly balanced by |
19 | | - * the number of calls to my_free(). |
20 | | - * |
21 | | - * The remainder of this comment deals with a debugging feature, and |
22 | | - * may be safely ignored until such time as you start freeing memory |
23 | | - * you haven't allocated, or writing off the ends of arrays. |
24 | | - * |
25 | | - * If the constant DEBUG_MALLOC is #defined to be 1 (see below) then |
26 | | - * my_malloc() and my_free() maintain a linked list |
27 | | - * of the addresses of the blocks of memory which have been allocated. |
28 | | - * If some other part of the kernel attempts to free memory which has |
29 | | - * not been allocated (or free the same memory twice), free() generates |
30 | | - * and error message and exits. Because this feature is for debugging |
31 | | - * purposes only, no attempt is made to be efficient. (Obviously a |
32 | | - * binary tree would be more efficient than a linked list, but you'd have |
33 | | - * to account for the fact that the memory is most likely allocated |
34 | | - * in linear order. Reversing the order of the bytes would be simpler |
35 | | - * than implementing a balanced tree.) |
36 | | - * |
37 | | - * Note that the DEBUG_MALLOC feature itself uses memory, but does not |
38 | | - * record its own usage in the linked list. This is OK. Its purpose |
39 | | - * is to help debug SnapPea, not malloc(). |
40 | | - * |
41 | | - * If DEBUG_MALLOC is turned on, my_malloc() tacks four extra bytes on |
42 | | - * the end of every requested block of memory, and writes in an |
43 | | - * arbitrary (but well defined) sequence of four characters. When the |
44 | | - * memory is freed, my_free() checks those four characters to see whether |
45 | | - * they've been overwritten. This is not a perfect guarantee against |
46 | | - * writing past the ends of array, but it should detect at least some |
47 | | - * errors. |
48 | | - */ |
49 | | - |
50 | | - |
51 | | -#include "kernel.h" |
52 | | -#include <stdlib.h> /* needed for malloc() */ |
53 | | -#include <stdio.h> /* needed for sprintf() */ |
54 | | - |
55 | | -static int net_malloc_calls = 0; |
56 | | - |
57 | | -/* |
58 | | - * The debugging feature is normally off. |
59 | | - */ |
60 | | -#define DEBUG_MALLOC 0 |
61 | | - |
62 | | -#if DEBUG_MALLOC |
63 | | - |
64 | | -#define MAX_BYTES 50000 |
65 | | - |
66 | | -typedef struct memnode |
67 | | -{ |
68 | | - void *address; |
69 | | - size_t bytes; |
70 | | - struct memnode *next; |
71 | | -} MemNode; |
72 | | - |
73 | | -static MemNode mem_list = {NULL, 0, NULL}; |
74 | | - |
75 | | -static const char secret_code[5] = "Adam"; |
76 | | - |
77 | | -static Boolean message_given = FALSE; |
78 | | - |
79 | | -#endif |
80 | | - |
81 | | - |
82 | | -void *my_malloc( |
83 | | - size_t bytes) |
84 | | -{ |
85 | | - void *ptr; |
86 | | -#if DEBUG_MALLOC |
87 | | - MemNode *new_mem_node; |
88 | | - char *error_bytes; |
89 | | - int i; |
90 | | -#endif |
91 | | - |
92 | | -#if DEBUG_MALLOC |
93 | | - if (message_given == FALSE) |
94 | | - { |
95 | | - uAcknowledge("The my_malloc() memory allocator is in debugging mode."); |
96 | | - message_given = TRUE; |
97 | | - } |
98 | | -#endif |
99 | | - |
100 | | -#if DEBUG_MALLOC |
101 | | - if (bytes < 0) |
102 | | - { |
103 | | - uAcknowledge("A negative number of bytes were requested in my_malloc()."); |
104 | | - exit(3); |
105 | | - } |
106 | | - if (bytes > MAX_BYTES) |
107 | | - uAcknowledge("Too many bytes were requested in my_malloc()."); |
108 | | -#endif |
109 | | - |
110 | | - /* |
111 | | - * Most likely malloc() and free() would correctly handle |
112 | | - * a request for zero bytes, but why take chances? |
113 | | - */ |
114 | | - if (bytes == 0) |
115 | | - bytes = 1; |
116 | | - |
117 | | -#if DEBUG_MALLOC |
118 | | - ptr = malloc(bytes + 4); |
119 | | -#else |
120 | | - ptr = malloc(bytes); |
121 | | -#endif |
122 | | - |
123 | | - if (ptr == NULL) |
124 | | - uAbortMemoryFull(); |
125 | | - |
126 | | - net_malloc_calls++; |
127 | | - |
128 | | -#if DEBUG_MALLOC |
129 | | - |
130 | | - error_bytes = (char *) ptr + bytes; |
131 | | - for (i = 0; i < 4; i++) |
132 | | - error_bytes[i] = secret_code[i]; |
133 | | - |
134 | | - new_mem_node = (MemNode *) malloc((size_t) sizeof(MemNode)); |
135 | | - if (new_mem_node == NULL) |
136 | | - { |
137 | | - uAcknowledge("out of memory"); |
138 | | - exit(4); |
139 | | - } |
140 | | - new_mem_node->address = ptr; |
141 | | - new_mem_node->bytes = bytes; |
142 | | - new_mem_node->next = mem_list.next; |
143 | | - mem_list.next = new_mem_node; |
144 | | -#endif |
145 | | - |
146 | | - return ptr; |
147 | | -} |
148 | | - |
149 | | - |
150 | | -void my_free( |
151 | | - void *ptr) |
152 | | -{ |
153 | | -#if DEBUG_MALLOC |
154 | | - Boolean old_node_found; |
155 | | - MemNode *old_mem_node, |
156 | | - *prev_mem_node; |
157 | | - size_t bytes; |
158 | | - char *error_bytes; |
159 | | - int i; |
160 | | -#endif |
161 | | - |
162 | | -#if DEBUG_MALLOC |
163 | | - old_node_found = FALSE; |
164 | | - for ( prev_mem_node = &mem_list, old_mem_node = mem_list.next; |
165 | | - old_mem_node != NULL; |
166 | | - old_mem_node = old_mem_node->next, prev_mem_node = prev_mem_node->next) |
167 | | - if (old_mem_node->address == ptr) |
168 | | - { |
169 | | - old_node_found = TRUE; |
170 | | - bytes = old_mem_node->bytes; |
171 | | - prev_mem_node->next = old_mem_node->next; |
172 | | - free(old_mem_node); |
173 | | - break; |
174 | | - } |
175 | | - if (old_node_found == FALSE) |
176 | | - { |
177 | | - uAcknowledge("A bad address was passed to my_free()."); |
178 | | - exit(5); |
179 | | - } |
180 | | - |
181 | | - error_bytes = (char *) ptr + bytes; |
182 | | - for (i = 0; i < 4; i++) |
183 | | - if (error_bytes[i] != secret_code[i]) |
184 | | - { |
185 | | - uAcknowledge("my_free() received a corrupted array."); |
186 | | - exit(6); |
187 | | - } |
188 | | -#endif |
189 | | - |
190 | | - free(ptr); |
191 | | - |
192 | | - net_malloc_calls--; |
193 | | -} |
194 | | - |
195 | | - |
196 | | -int malloc_calls() |
197 | | -{ |
198 | | - return net_malloc_calls; |
199 | | -} |
200 | | - |
201 | | - |
202 | | -void verify_my_malloc_usage() |
203 | | -{ |
204 | | - char the_message[256]; |
205 | | - |
206 | | - if (net_malloc_calls != 0) |
207 | | - { |
208 | | - sprintf(the_message, "Memory allocation error:\rThere were %d %s calls to my_malloc() than to my_free().", |
209 | | - net_malloc_calls > 0 ? net_malloc_calls : - net_malloc_calls, |
210 | | - net_malloc_calls > 0 ? "more" : "fewer"); |
211 | | - uAcknowledge(the_message); |
212 | | - } |
213 | | -} |
| 1 | +#include "extensions/SnapPy/kernel/kernel_code/my_malloc.c" |
0 commit comments