File: my_malloc.c

package info (click to toggle)
snappea 3.0d3-20.1
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 5,896 kB
  • ctags: 3,582
  • sloc: ansic: 33,469; sh: 8,293; python: 7,623; makefile: 240
file content (213 lines) | stat: -rw-r--r-- 5,248 bytes parent folder | download | duplicates (11)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/*
 *	my_malloc.c
 *
 *	This file provides an interface to malloc() and free() which
 *
 *	(1)	Keeps track of the number of calls to malloc() minus the number
 *		of calls to free().  This allows easy detection of programming
 *		errors which allocate more memory than they free (or vice versa).
 *
 *	(2)	Aborts the program if malloc() returns NULL.  This saves having
 *		to check whether malloc() == NULL at each point where malloc()
 *		is called.
 *
 *	All kernel routines use my_malloc() and my_free();
 *	no UI routines do so.
 *
 *	The UI should call verify_my_malloc_usage() upon exit, to verify
 *	that the number of calls to my_malloc() was exactly balanced by
 *	the number of calls to my_free().
 *
 *	The remainder of this comment deals with a debugging feature, and
 *	may be safely ignored until such time as you start freeing memory
 *	you haven't allocated, or writing off the ends of arrays.
 *
 *	If the constant DEBUG_MALLOC is #defined to be 1 (see below) then
 *	my_malloc() and my_free() maintain a linked list
 *	of the addresses of the blocks of memory which have been allocated.
 *	If some other part of the kernel attempts to free memory which has
 *	not been allocated (or free the same memory twice), free() generates
 *	and error message and exits.  Because this feature is for debugging
 *	purposes only, no attempt is made to be efficient.  (Obviously a
 *	binary tree would be more efficient than a linked list, but you'd have
 *	to account for the fact that the memory is most likely allocated
 *	in linear order.  Reversing the order of the bytes would be simpler
 *	than implementing a balanced tree.)
 *
 *	Note that the DEBUG_MALLOC feature itself uses memory, but does not
 *	record its own usage in the linked list.  This is OK.  Its purpose
 *	is to help debug SnapPea, not malloc().
 *
 *	If DEBUG_MALLOC is turned on, my_malloc() tacks four extra bytes on
 *	the end of every requested block of memory, and writes in an
 *	arbitrary (but well defined) sequence of four characters.  When the
 *	memory is freed, my_free() checks those four characters to see whether
 *	they've been overwritten.  This is not a perfect guarantee against
 *	writing past the ends of array, but it should detect at least some
 *	errors.
 */


#include "kernel.h"
#include <stdlib.h>	/* needed for malloc()  */
#include <stdio.h>	/* needed for sprintf() */

static int	net_malloc_calls = 0;

/*
 *	The debugging feature is normally off.
 */
#define DEBUG_MALLOC 1

#if DEBUG_MALLOC

#define MAX_BYTES	50000

typedef struct memnode
{
	void			*address;
	size_t			bytes;
	struct memnode	*next;
} MemNode;

static MemNode		mem_list = {NULL, 0, NULL};

static const char	secret_code[5] = "Adam";

static Boolean		message_given = FALSE;

#endif


void *my_malloc(
	size_t	bytes)
{
	void	*ptr;
#if DEBUG_MALLOC
	MemNode	*new_mem_node;
	char	*error_bytes;
	int		i;
#endif

#if DEBUG_MALLOC
	if (message_given == FALSE)
	{
		uAcknowledge("The my_malloc() memory allocator is in debugging mode.");
		message_given = TRUE;
	}
#endif

#if DEBUG_MALLOC
	if (bytes < 0)
	{
		uAcknowledge("A negative number of bytes were requested in my_malloc().");
		exit(3);
	}
	if (bytes > MAX_BYTES)
		uAcknowledge("Too many bytes were requested in my_malloc().");
#endif

	/*
	 *	Most likely malloc() and free() would correctly handle
	 *	a request for zero bytes, but why take chances?
	 */
	if (bytes == 0)
		bytes = 1;
	
#if DEBUG_MALLOC
	ptr = malloc(bytes + 4);
#else
	ptr = malloc(bytes);
#endif

	if (ptr == NULL)
		uAbortMemoryFull();

	net_malloc_calls++;

#if DEBUG_MALLOC

	error_bytes = (char *) ptr + bytes;
	for (i = 0; i < 4; i++)
		error_bytes[i] = secret_code[i];

	new_mem_node = (MemNode *) malloc((size_t) sizeof(MemNode));
	if (new_mem_node == NULL)
	{
		uAcknowledge("out of memory");
		exit(4);
	}
	new_mem_node->address	= ptr;
	new_mem_node->bytes		= bytes;
	new_mem_node->next		= mem_list.next;
	mem_list.next = new_mem_node;
#endif

	return ptr;
}


void my_free(
	void	*ptr)
{
#if DEBUG_MALLOC
	Boolean	old_node_found;
	MemNode	*old_mem_node,
			*prev_mem_node;
	size_t	bytes;
	char	*error_bytes;
	int		i;
#endif

#if DEBUG_MALLOC
	old_node_found = FALSE;
	for (	prev_mem_node = &mem_list, old_mem_node = mem_list.next;
			old_mem_node != NULL;
			old_mem_node = old_mem_node->next, prev_mem_node = prev_mem_node->next)
		if (old_mem_node->address == ptr)
		{
			old_node_found = TRUE;
			bytes = old_mem_node->bytes;
			prev_mem_node->next = old_mem_node->next;
			free(old_mem_node);
			break;
		}
	if (old_node_found == FALSE)
	{
		uAcknowledge("A bad address was passed to my_free().");
		exit(5);
	}

	error_bytes = (char *) ptr + bytes;
	for (i = 0; i < 4; i++)
		if (error_bytes[i] != secret_code[i])
		{
			uAcknowledge("my_free() received a corrupted array.");
			exit(6);
		}
#endif

	free(ptr);

	net_malloc_calls--;
}


int malloc_calls()
{
	return net_malloc_calls;
}


void verify_my_malloc_usage()
{
	char	the_message[256];

	if (net_malloc_calls != 0)
	{
		sprintf(the_message, "Memory allocation error:\rThere were %d %s calls to my_malloc() than to my_free().",
			net_malloc_calls > 0 ? net_malloc_calls : - net_malloc_calls,
			net_malloc_calls > 0 ? "more" : "fewer");
		uAcknowledge(the_message);
	}
}