-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathvalidator.h
executable file
·259 lines (220 loc) · 7.42 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
/*
* 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.
*/
#ifndef MM_VALIDATOR_H
#define MM_VALIDATOR_H
#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"
// 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
// 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 *pnext;
// 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
if (!IS_ALIGNED(lo)) {
sprintf(msg, "Memory pointer %p is not aligned correctly.\n", lo);
malloc_error(tracenum, opnum, msg);
return 0;
}
// The payload must lie within the extent of the heap
if (impl->heap_lo() > lo || impl->heap_hi() < hi) {
sprintf(msg, "Returned range is not within heap boundary.\n");
malloc_error(tracenum, opnum, msg);
return 0;
}
// The payload must not overlap any other payloads
for (p = *ranges; p != NULL; p = pnext) {
if (hi == p->lo || hi == p->hi || lo == p->lo || lo == p->hi) {
sprintf(msg, "Returned range overlaps with an existing range.\n");
malloc_error(tracenum, opnum, msg);
return 0;
}
if ((hi >= p->lo && lo <= p->lo) ||
(hi <= p->hi && lo >= p->lo) ||
(hi >= p->hi && lo <= p->lo) ||
(lo <= p->hi && hi >= p->hi)) {
sprintf(msg, "Returned range overlaps with an existing range.\n");
malloc_error(tracenum, opnum, msg);
return 0;
}
pnext = p->next;
}
// Everything looks OK, so remember the extent of this block by creating a
// range struct and adding it the range list.
range_t * new_range = (range_t *) malloc(sizeof(range_t));
new_range->hi = hi;
new_range->lo = lo;
new_range->next = *ranges;
*ranges = new_range;
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 *p = NULL;
// 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 *p;
range_t *pprev;
p = *ranges;
if (p->lo == lo) {
*ranges = p->next;
free(p);
return;
}
for(pprev = p, p = p->next; p != NULL; pprev = p, p = p->next) {
if (p->lo == lo) {
pprev->next = p->next;
free(p);
return;
}
}
}
// 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;
int count;
// 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.
count = -13;
for(char * inc = p; inc < p + size; inc += sizeof(int)) {
*((int *) inc) = count;
count--;
}
// 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;
count = -13;
for(char * inc = newp; inc < newp + oldsize; inc += sizeof(int)) {
if (*((int *) inc) != count) {
char msg[MAXLINE];
sprintf(msg, "The memory bock value: %d was not equal to the expected value(%d).\n", *((int *) inc), count);
malloc_error(tracenum, i, msg);
return 0;
}
count--;
}
count = -13;
for(char * inc = newp; inc < newp + size; inc += sizeof(int)) {
*((int *) inc) = count;
count--;
}
// 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