Tutorials are great. We all love them and they help so much. But always double-check code you learn to write from a tutorial because there is no guarantee that they are free from bugs or even complete. Some authors post a disclaimer while others do not. I watched this awesome video on creating a StringList type for C recently:
The other has some great points, explains them well, and the code works fine as shown.
However, I quickly realized that the code contains a bunch of memory leaks. He only has one routine which is used to free memory, and it only runs if the library user calls the stringlist_rm
function. Even then, the remove function only frees the memory of the string. It does not free the memory used to store the array of strings nor does it free the StringList object at all!
Thus, when run as shown in the video using valgrind we have:
=14589== in use at exit: 70 bytes in 4 blocks
==14589== total heap usage: 8 allocs, 4 frees, 1,126 bytes allocated
==14589==
==14589== 70 (24 direct, 46 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==14589== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14589== by 0x108B42: sl_new (in /home/moveax41h/c/stringlist)
==14589== by 0x108896: main (in /home/moveax41h/c/stringlist)
==14589==
==14589== LEAK SUMMARY:
==14589== definitely lost: 24 bytes in 1 blocks
==14589== indirectly lost: 46 bytes in 3 blocks
==14589== possibly lost: 0 bytes in 0 blocks
==14589== still reachable: 0 bytes in 0 blocks
==14589== suppressed: 0 bytes in 0 blocks
==14589==
==14589== For counts of detected and suppressed errors, rerun with: -v
==14589== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
I added and called the following routine on the StringList pointer at the end of the test code:
void sl_destroy(StringList *pSl)
{
assert(pSl);
size_t i;
//First free all strings
for(i = 0; i < pSl->size; i++)
{
free(pSl->data[i]);
pSl->data[i] = NULL;
}
//Free the pointer to the array of strings
free(pSl->data);
pSl->data = NULL;
//Free StringList pointer itself
free(pSl);
pSl = NULL;
}
When this routine is implemented and used, the same program now produces the following in valgrind:
==14532== Memcheck, a memory error detector
==14532== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==14532== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==14532== Command: ./stringlist_test
==14532==
hello
goodbye
Test #1 find result: -1
Test #2 find result: 0
==14532==
==14532== HEAP SUMMARY:
==14532== in use at exit: 0 bytes in 0 blocks
==14532== total heap usage: 8 allocs, 8 frees, 1,126 bytes allocated
==14532==
==14532== All heap blocks were freed -- no leaks are possible
==14532==
==14532== For counts of detected and suppressed errors, rerun with: -v
==14532== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
To check your own programs simply apt get valgrind
and then run the command valgrind --leak-check=full [your program here]
.
Mac users can use brew install valgrind
(Only up to macOS 10.13) and Windows users can use Dr. Memory.
Here is another example, this time, 23 leaks. This is a PR where I provide a fix and explain the issues.
Memory leaks can cause huge reliability issues with large workloads and even some security vulnerabilities.