-
Notifications
You must be signed in to change notification settings - Fork 1
/
validator.h
executable file
·314 lines (264 loc) · 8.77 KB
/
validator.h
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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
#ifndef MM_VALIDATOR_H
#define MM_VALIDATOR_H
/*
* validator.h - 6.172 Malloc Validator
*
* Validates a malloc/free/realloc implementation.
*
* Copyright (c) 2010, R. Bryant and D. O'Hallaron, All rights reserved.
* May not be used, modified, or copied without permission.
*/
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "config.h"
#include "mdriver.h"
#include "memlib.h"
#include "validator.h"
/* Returns true if p is ALIGNMENT-byte aligned */
#if (__WORDSIZE == 64 )
#define IS_ALIGNED(p) ((((uint64_t)(p)) % ALIGNMENT) == 0)
#else
#define IS_ALIGNED(p) ((((uint32_t)(p)) % ALIGNMENT) == 0)
#endif
/*
* IMPORTANT: this implementation returns 0 if there's an error
* 1 if no errors
*/
/***************************
* Range list data structure
**************************/
/* Records the extent of each block's payload */
typedef struct range_t {
char *lo; /* low payload address */
char *hi; /* high payload address */
struct range_t *next; /* next list element */
} range_t;
/*****************************************************************
* The following routines manipulate the range list, which keeps
* track of the extent of every allocated block payload. We use the
* range list to detect any overlapping allocated blocks.
****************************************************************/
/*
* add_range - As directed by request opnum in trace tracenum,
* we've just called the student's malloc to allocate a block of
* size bytes at addr lo. After checking the block for correctness,
* we create a range struct for this block and add it to the range list.
*/
template <class Type>
static int add_range(Type *impl, range_t **ranges, char *lo,
int size, int tracenum, int opnum)
{
char *hi = lo + size - 1;
range_t * p = (range_t *)malloc(sizeof(range_t));
/* You can use this as a buffer for writing messages with sprintf. */
char msg[MAXLINE];
assert(size > 0);
/* Payload addresses must be ALIGNMENT-byte aligned */
//We don't check whether hi address is aligned or not because we have no way of knowing what is the high address that has been passed to us
if (!IS_ALIGNED(lo)) {
int ret = sprintf(msg, "Low payload address %p is not aligned\n", lo);
printf("%s", msg);
return 0;
}
/* The payload must lie within the extent of the heap */
if (lo < mem_heap_lo() || hi > mem_heap_hi()) {
int ret = sprintf(msg, "Payload must lie within the extent of the heap\n the payload addresses are %p and %p, and the heapsize is %lu\n heap lies between %p and %p\n", lo, hi, mem_heapsize(), mem_heap_lo(), mem_heap_hi());
printf("%s", msg);
return 0;
}
/* The payload must not overlap any other payloads */
// Get the range in ranges
range_t *range = *ranges;
if (range == NULL) {
p->lo = lo;
p->hi = hi;
p->next = NULL;
*ranges = p;
} else {
range_t *prev = NULL;
while (range != NULL) {
/* The range in ranges and the current range don't overlap
only in two cases:
lo and hi addresses of the current range are
1) smaller than lo and hi of the range
2) larger than lo and hi of the range
*/
if ((range->lo < lo && range->hi < hi) || (range->lo > lo && range->hi > hi)) {
// The regions do not overlap
prev = range;
range = range->next;
} else {
// The regions overlap
int ret = sprintf(msg, "The payload overlaps with some other payload\n");
}
}
/* Everything looks OK, so remember the extent of this block by creating a
* range struct and adding it the range list.
*/
//range_t p = {.lo = lo, .hi = hi, .next = NULL};
p->lo = lo;
p->hi = hi;
p->next = NULL;
prev->next = p;
}
return 1;
}
/*
* remove_range - Free the range record of block whose payload starts at lo
*/
static void remove_range(range_t **ranges, char *lo)
{
// range_t **prevpp = ranges;
/* Iterate the linked list until you find the range with a matching lo
* payload and remove it. Remember to properly handle the case where the
* payload is in the first node, and to free the node after unlinking it.
*/
range_t * curr = *ranges;
// If the list of ranges is empty, there's nothing to find and remove
if (curr == NULL) {
return;
}
// We keep track of the curr and prev elements
// to be able to unlink and relink nodes
range_t *prev = NULL;
while (curr != NULL) {
if (curr->lo == lo) {
// Match found, remove the node
if (curr == *ranges) {
// The address lo matches the head of the list
// Set the head of the list to curr.next
*ranges = curr->next;
// Free the node after unlinking it
free(curr);
return;
} else {
// Unlink the curr node
prev->next = curr->next;
// Free the node after unlinking it
free(curr);
}
} else {
// No match found, continue
prev = curr;
curr = curr->next;
}
}
}
/*
* clear_ranges - free all of the range records for a trace
*/
static void clear_ranges(range_t **ranges)
{
range_t *p;
range_t *pnext;
for (p = *ranges; p != NULL; p = pnext) {
pnext = p->next;
free(p);
}
*ranges = NULL;
}
/*
* eval_mm_valid - Check the malloc package for correctness
*/
template <class Type>
int eval_mm_valid(Type *impl, trace_t *trace, int tracenum)
{
int i = 0;
int index = 0;
int size = 0;
int oldsize = 0;
char *newp = NULL;
char *oldp = NULL;
char *p = NULL;
range_t *ranges = NULL;
/* Reset the heap. */
impl->reset_brk();
/* Call the mm package's init function */
if (impl->init() < 0) {
malloc_error(tracenum, 0, "impl init failed.");
return 0;
}
/* Interpret each operation in the trace in order */
for (i = 0; i < trace->num_ops; i++) {
index = trace->ops[i].index;
size = trace->ops[i].size;
switch (trace->ops[i].type) {
case ALLOC: /* malloc */
/* Call the student's malloc */
if ((p = (char *) impl->malloc(size)) == NULL) {
malloc_error(tracenum, i, "impl malloc failed.");
return 0;
}
/*
* Test the range of the new block for correctness and add it
* to the range list if OK. The block must be be aligned properly,
* and must not overlap any currently allocated block.
*/
if (add_range(impl, &ranges, p, size, tracenum, i) == 0)
return 0;
/* Fill the allocated region with some unique data that you can check
* for if the region is copied via realloc.
*/
assert(p != NULL);
// prev range_t contains the most recently allocated range
memset(p, 0xA5, size);
// for (int ii=0; ii < oldsize; ii++) {
// assert((*(newp + i) == 0xA5));
// }
/* Remember region */
trace->blocks[index] = p;
trace->block_sizes[index] = size;
break;
case REALLOC: /* realloc */
/* Call the student's realloc */
oldp = trace->blocks[index];
if ((newp = (char *) impl->realloc(oldp, size)) == NULL) {
malloc_error(tracenum, i, "impl realloc failed.");
return 0;
}
/* Remove the old region from the range list */
remove_range(&ranges, oldp);
/* Check new block for correctness and add it to range list */
if (add_range(impl, &ranges, newp, size, tracenum, i) == 0)
return 0;
/* Make sure that the new block contains the data from the old block,
* and then fill in the new block with new data that you can use to
* verify the block was copied if it is resized again.
*/
oldsize = trace->block_sizes[index];
if (size < oldsize)
oldsize = size;
for (int i=0; i < oldsize; i++) {
// printf("newp=%f\n", *(double *)(newp + i));
if (*(newp + i) != (char)(0xA5)) {
malloc_error(tracenum, i, "newly allocated memory has different content than the one before reallocation.");
return 0;
}
}
memset(newp, 0xA5, size);
/* Remember region */
trace->blocks[index] = newp;
trace->block_sizes[index] = size;
break;
case FREE: /* free */
/* Remove region from list and call student's free function */
p = trace->blocks[index];
remove_range(&ranges, p);
impl->free(p);
break;
default:
app_error("Nonexistent request type in eval_mm_valid");
}
}
/* Free ranges allocated and reset the heap. */
impl->reset_brk();
clear_ranges(&ranges);
/* As far as we know, this is a valid malloc package */
return 1;
}
#endif /* MM_VALIDATOR_H */