Hi,
This is going to be long, sorry for that. Also, I'll be going over this in pretty close detail since this is actually a pretty interesting case and can maybe be of help to others in the future as well. So if you are familiar with most of the stuff, you can probably skip to the end :)
OK, so let's take a look at the valgrind report in detail. So we have our valgrind report, the first error of which is
==389== 448 bytes in 16 blocks are definitely lost in loss record 77 of 79
==389== at 0x4C28C20: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==389== by 0x401E2A: fieldFromString (test_source.c:107)
==389== by 0x401FEA: test_printField (test_source.c:176)
==389== by 0x406787: srunner_run (in /tmc/test/test)
==389== by 0x4025B1: tmc_run_tests (tmc-check.c:122)
==389== by 0x402271: main (test_source.c:225)
==389==
Reading from top to bottom, we first get a description of the problem. Some allocated blocks are getting lost, meaning that we are allocating some memory that is not getting free'd during the lifetime of the program run, or in this case the test run. The next lines are a stack trace that details where the memory was allocated. So it was allocated using a malloc that happens on line 107 of test_source.c in the function fieldFromString, which was called from line 176 of the same file, from the function test_printField etc. But to actually understand what is going on, we need to figure out where that memory ends up.
test_source.c is the file that defines (some) of the tests used to assess your program and it can be found in the /test folder of the project. So let's look at line 107 of that, together with some surrounding lines (some comments added and parts omitted).
Field *fieldFromString(const char *s)
{
// <omitted>
// set up field
Field *f = malloc(sizeof(Field));
if (!f)
return NULL;
f->cells = malloc(sizeof(State*) * ysize);
if (!f->cells) {
free(f);
return NULL;
}
for (unsigned int i = 0; i < ysize; i++) {
f->cells[i] = malloc(sizeof(State) * xsize); // <- line 107
}
// <omitted>
return f;
}
We see that as part of the tests, the tests are allocating a Field using a non-contingous malloc.
Looking at the surroundings of line 176 next, we see the following (comments added):
START_TEST(test_printField)
{
Field *f;
for (unsigned int i = 0; i < sizeof(fields) / sizeof(char *); i++) {
f = fieldFromString(fields[i]); // <- line 176, generates a known Field
char str[400];
fieldToString(f, str, sizeof(str)); // <- this calls your code, transforming it to a string
char infostr[400];
if (mycompare(str, fields[i], infostr) != 0) { // <- checks that the string is as expected
releaseField(f); # <- line 183, this calls your code, releasing the Field
fail("[M4.02.c] Your output:\n%s\nReference output:\n%s\nReason: %s\n",
str, fields[i], infostr);
}
releaseField(f); // <- line 187, this also calls your code, releasing the field
}
}
END_TEST
This is one of the test cases. So the tests allocate a Field using the method in the tests. This Field is then compared to what your code generates given the same input. So essentially we are checking that your function fieldToString produces the expected output given a known Field. So far all good.
But then we notice lines 183 and 187. The tests use *your code* to free the Field it created using multiple calls to malloc! And **that** is the problem. Your code assumes that the Field it free's was malloc'd in a certain way, which is not the same way the test mallocs its Field.
**So in essence**: your code works correctly, **given that the Field is created using a contiguous malloc**, but the tests call your code using a Field created using a non-contiguous malloc. Just running your code in isolation, this issue will naturally never crop up. The issue is only in the interaction between the test cases and your code :)
Hopefully this clears the issue :) I'll email the person behind the tests to see if we could either make the test files also free their own memory (Which has some issues vis-a-vis the test file having most of the solution) or adding a note to the exercise prompt.
-L