1

I am grading a bunch of student assignments.

They are designing their own dynamic array data type. I am looking for a good way to test to make sure that they malloc the correct amount of memory for an array when re-sizing.

Other than inspecting the code is there some way to easily test the amount of memory created by a malloc call? They are supposed to keep track of the capacity but I need to test that they are doing so correctly.

I would also like it if the test didn't end in a segfault if they did not allocate enough memory so that I could continue running other tests.

Thanks!

Justin
  • 2,322
  • 1
  • 16
  • 22
  • 3
    Provide your own implementation of `malloc` and have them link against that? Or run their code through valgrind? – jamesdlin Jul 07 '11 at 22:24
  • I'm not sure what you're asking. Do you want to put in a line of code into each student's assignment so that it checks whether or not it's been correctly malloc'd? – Chris Gregg Jul 07 '11 at 22:24
  • 2
    [couple methods for wrapping malloc here](http://stackoverflow.com/questions/262439/create-a-wrapper-function-for-malloc-and-free-in-c) – jspcal Jul 07 '11 at 22:25
  • I was writing a program that would call functions from their library and compare it to a known correct implementation. And it is easy enough to test the contents of the array this way, but I was unsure how to actually test the memory allocation aspects. – Justin Jul 07 '11 at 22:41

2 Answers2

4

You can provide your own version of malloc(), calloc(), realloc(), and free() for your tests by re-defining the standard function names.

With gcc, I'd create an object file with the replacement functions

gcc -c myfunctions.c -omyfunctions.o

and compile the test files with a redefiniton and link to the replacement

gcc myfunctions.o -Dmalloc=mymalloc -Dcalloc=mycalloc -Drealloc=myrealloc -Dfree=myfree testfile.c

instead of what the students use

gcc testfile.c

The implementation of the my*() functions shouldn't be too difficult. Basically they check the parameters and call the original functions.

/* myfunctions.c */
#include <stdlib.h>
void *mymalloc(size_t s) {
    /* test s */
    return malloc(s);
}
void *mycalloc(size_t n, size_t s) {
    /* test n and s */
    return calloc(n, s);
}
void *myrealloc(void *p, size_t s) {
    /* test p and s */
    return realloc(p, s);
}
void myfree(void *p) {
    /* test p */
    free(p);
}
pmg
  • 106,608
  • 13
  • 126
  • 198
  • Simplest way to do it, and if the students manage to write code that stops this working, they're probably doing something else wrong. With the arguable exception that it'd be reasonable for them to call some function of their own `mymalloc`, so maybe stick a pseudo-random string in the name, or use a reserved name like `__mymalloc` that you just so happen to know your implementation doesn't use for anything. – Steve Jessop Jul 07 '11 at 22:32
  • Apparently one has to define the macros first and undefine them next: I couldn't manage to correctly compile a test without the `-U` option – pmg Jul 07 '11 at 22:44
  • Oh, didn't think of that. Mentally I think I compiled `myfunctions.c` separately anyway, rather than once per student. – Steve Jessop Jul 07 '11 at 22:54
  • With further testing I couldn't manage all of it with a single compilation: answer edited again – pmg Jul 07 '11 at 23:03
  • But... how will these wrappers know what the size *should* be? In my opinion, that's the tricky part (or am I missing something?). – Michael Burr Jul 08 '11 at 01:02
  • @Michael: sort of depends on the assignment, but for example if the student's array code is being driven by the teacher's test code, and the test code calls for an array of size 100, then the mock can test whether an allocation of size at least 100 was requested. Doesn't prove the student actually used it as the data storage in the dynamic array, although if that interface will give you a pointer to the first element then with co-operation between the mock and the test code that can be checked too. – Steve Jessop Jul 08 '11 at 08:39
  • @Michael: like @Steve says, it depends on the problem. Suppose the students have to calculate the sum of differences between all the numbers (0 to INT_MAX) in a file and their average. The teacher know how many numbers are in the files, so the (last) realloc must allow for that many numbers ... and that pointer must be used in `free` later. – pmg Jul 08 '11 at 09:04
1

I think the problems you are expecting should be caught by running the students' programs in Valgrind. That's a good idea anyway as it might also catch other unwanted issues, e.g. out-of-bounds accesses.

BjoernD
  • 4,720
  • 27
  • 32
  • +1: IMHO, this is the right answer. Rather than trying to wrap malloc to expect specific input conditions, simply use an existing tool to confirm that no illegal memory accesses occur. – Oliver Charlesworth Jul 08 '11 at 00:45
  • @Oli: tbh I think to be thorough you should mock `malloc` *and* use valgrind. There are errors that valgrind will miss but the mock could test, such as the student always using the same sized buffer that happens to be be big enough for all the test cases :-) – Steve Jessop Jul 08 '11 at 08:42