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.
mgtest1
Here 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.
mgtest2
We 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.)
mgtest3
Here’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.)