You can find the code and solutions for this recitation on CLAC, here:
$ git clone ~j-hui/cs3157-pub/examples/malgrind
Consider malgrind.c, which defines MALLOC() and FREE():
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
static uint64_t MAGIC = ~((uint64_t) 0);
const size_t WAD = sizeof(MAGIC);
void *MALLOC(size_t n) {
char *p = malloc(2 * WAD + n);
if (p == NULL)
return NULL;
uint32_t *head = (uint32_t *)p;
head[0] = head[1] = n;
memcpy(p + WAD + n, &MAGIC, WAD);
return p + WAD;
}
void FREE(void *p) {
if (p == NULL) {
fprintf(stderr, "%s\n", "NULL");
return;
}
uint32_t *head = (uint32_t *)p - 2;
if (head[0] != head[1] || memcmp((char *)p + head[0], &MAGIC, WAD) != 0)
fprintf(stderr, "%s\n", "OOPS");
else
fprintf(stderr, "%s\n", "OKAY");
free((char *)p - WAD);
}
MALLOC() and FREE() provide the same interface as the underlying malloc()
and free() functions, in that they allocate and release heap memory.
Which following describe the potential benefits of using MALLOC() and
FREE() instead of the malloc() and free() functions they wrap?
MALLOC() and FREE() can make the program run faster.MALLOC() and FREE() can make the program use less memory.MALLOC() and FREE() can help detect memory leaks.MALLOC() and FREE() can help detect invalid writes.MALLOC() and FREE() can help detect invalid reads.MALLOC() and FREE() can help detect invalid free()s.Select zero or more of the above. You do not have to answer this right now; work on some of the problems below before returning to these questions.
mgtest1Here is a test program, mgtest1.c, which uses the MALLOC() and FREE()
functions:
#include <stdio.h>
void *MALLOC(size_t n);
void FREE(void *p);
int main(void) {
int *a = MALLOC(4 * sizeof(int));
for (int i = 0; i < 5; i++)
a[i] = i;
for (int i = 0; i < 5; i++)
fprintf(stderr, "%d, ", a[i]);
FREE(a);
return 0;
}
We compiled and linked the mgtest1 program, and ran it with and without
Valgrind:
$ gcc -g -Wall mgtest1.c malgrind.c -o mgtest1
$ valgrind --leak-check=yes ./mgtest1 # with Valgrind
(( output not shown ))
$ ./mgtest1 # without Valgrind
(( output not shown ))
What is the outcome of running mgtest1 with Valgrind? Choose from one of the
following:
What is the output of the program, when run without Valgrind?
Assume that the program doesn’t crash due to invalid reads and writes.
The output of the program contains a comma-separated sequence of integers,
read from memory; if you think an integer is read from an invalid or
uninitialized memory location, write X instead of a decimal value.
The sequence of integers is terminated by OKAY, OOPS, or NULL,
printed when calling FREE(). Make sure to include this your output.
mgtest2We replace mgtest1.c with a modified version of the test, mgtest2.c:
#include <stdio.h>
#include <assert.h>
void *MALLOC(size_t n);
void FREE(void *p);
int main(void) {
assert(sizeof(long) == sizeof(void *));
long *a = MALLOC(4 * sizeof(long));
for (long i = 0; i < 4; i++)
a[i] = i;
for (long *p = a; *p >= 0; p++)
fprintf(stderr, "%ld, ", p[1]);
FREE((void *) *a);
return 0;
}
Like before, we compiled and linked the mgtest2 program, and ran it with and
without Valgrind:
$ gcc -g -Wall mgtest2.c malgrind.c -o mgtest2
$ valgrind --leak-check=yes ./mgtest2 # with Valgrind
(( output not shown ))
$ ./mgtest2 # without Valgrind
(( output not shown ))
What is the outcome of running mgtest2 with Valgrind? (ERROR/LEAK/GOOD)
What is the output of the mgtest2 program, when run without Valgrind?
(Comma-separated decimal integers + word, same rules as before.)
mgtest3Here’s another variation of the test program, mgtest3.c:
#include <stdio.h>
#include <assert.h>
void *MALLOC(size_t n);
void FREE(void *p);
int main(void) {
assert(sizeof(int) == 4);
int *a = MALLOC(4 * sizeof(int));
for (int i = 0; i < 4; i++)
a[i] = i;
for (int *p = a - 2; p < a + 6; p++)
fprintf(stderr, "%d, ", *p);
FREE(a);
return 0;
}
Like before, we compiled and linked the mgtest3 program, and ran it with and
without Valgrind:
$ gcc -g -Wall mgtest3.c malgrind.c -o mgtest3
$ valgrind --leak-check=yes ./mgtest3 # with Valgrind
(( output not shown ))
$ ./mgtest3 # without Valgrind
(( output not shown ))
What is the outcome of running mgtest3 with Valgrind? (ERROR/LEAK/GOOD)
What is the output of the mgtest3 program, when run without Valgrind?
(Comma-separated decimal integers + word, same rules as before.)