Here is a simple example. Let's emulate this with the following test case code:
/*
* A demo: this function allocates memory internally; the caller
* is responsible for freeing it!
*/
static void silly_getpath(char **ptr)
{
#include <linux/limits.h>
*ptr = malloc(PATH_MAX);
if (!ptr)
FATAL("malloc failed ");
strcpy(*ptr, getenv("PATH"));
if (!*ptr)
FATAL("getenv failed ");
}
/* test case 13 : memory leak test case 3: "lib" API leak */
static void leakage_case3(int cond)
{
char *mypath=NULL;
printf(" ## Leakage test: case 3: "lib" API"
": runtime cond = %d ", cond);
/* Use C's illusory 'pass-by-reference' model */
silly_getpath(&mypath);
printf("mypath = %s ", mypath);
if (cond) /* Bug: if cond==0 then we have a leak! */
free(mypath);
}
We invoke it as:
[...]
case 13:
leakage_case3(0);
leakage_case3(1);
break;
As usual, no compiler or runtime warnings result. Here is the output (recognize that the first invocation is the buggy case, as cond has the value of 0 and thus the free(3) will not be called):
$ ./membugs 13
## Leakage test: case 3: "lib" API: runtime cond = 0
mypath = /usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/sbin:/usr/sbin:/usr/local/sbin:/home/kai/MentorGraphics/Sourcery_CodeBench_Lite_for_ARM_GNU_Linux/bin/:/mnt/big/scratchpad/buildroot-2017.08.1/output/host/bin/:/sbin:/usr/sbin:/usr/local/sbin
## Leakage test: case 3: "lib" API: runtime cond = 1
mypath = /usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/sbin:/usr/sbin:/usr/local/sbin:/home/kai/MentorGraphics/Sourcery_CodeBench_Lite_for_ARM_GNU_Linux/bin/:/mnt/big/scratchpad/buildroot-2017.08.1/output/host/bin/:/sbin:/usr/sbin:/usr/local/sbin
$
There is no bug apparent by looking at the output—and that is partly what makes these bugs so dangerous!
This case is critical for developers and testers to understand; it warrants checking out a couple of real-world examples.