I have a simple piece of a program thats currently producing some memory leaks according to valgrind and I'm not sure why:
char *filename = strrchr(argv[3], "/") + 1;
file = fopen(fileName, "w");
So as far as I know, I give the program an argv[3] of "test/test2", and the first line finds the last occurrence of "/", and then moves one character forward (to "t"). Then the second line opens a file that is a pointer to the char array "test".
Why is this causing a memory leak?
If you use the opened file stream, there's a good chance that the Standard I/O library will allocate a buffer for the stream. If you don't explicitly close the stream, there's a good chance that valgrind will regard that memory as still in use; there is an outside chance it would be regarded as leaked.
What is the exact message from valgrind? Why are you pointing at fopen()?
Consider this trivial program:
#include <stdio.h>
static void leaky(void)
{
FILE *fp = fopen("/etc/passwd", "r");
char buffer[2048];
while (fgets(buffer, sizeof(buffer), fp) != 0)
fputs(buffer, stdout);
/* fclose(fp); */
}
int main(void)
{
leaky();
return 0;
}
It produces the summary output:
==6169==
==6169== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 5 from 1)
==6169== malloc/free: in use at exit: 568 bytes in 1 blocks.
==6169== malloc/free: 1 allocs, 0 frees, 568 bytes allocated.
==6169== For counts of detected errors, rerun with: -v
==6169== searching for pointers to 1 not-freed blocks.
==6169== checked 69,424 bytes.
==6169==
==6169== LEAK SUMMARY:
==6169== definitely lost: 0 bytes in 0 blocks.
==6169== possibly lost: 0 bytes in 0 blocks.
==6169== still reachable: 568 bytes in 1 blocks.
==6169== suppressed: 0 bytes in 0 blocks.
==6169== Reachable blocks (those to which a pointer was found) are not shown.
==6169== To see them, rerun with: --show-reachable=yes
With the fclose(fp) not commented out, the output is:
==7125==
==7125== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 5 from 1)
==7125== malloc/free: in use at exit: 0 bytes in 0 blocks.
==7125== malloc/free: 1 allocs, 1 frees, 568 bytes allocated.
==7125== For counts of detected errors, rerun with: -v
==7125== All heap blocks were freed -- no leaks are possible.
Well, your code would leak a file handle (the latter fopen is not closed). However, without a more complete example its hard to tell.
Related
The following program:
#include <stdlib.h>
int main(void)
{
char *my_str = malloc(42 * sizeof(char));
return 0;
}
Compiled as such:
gcc -g -o prog prog.c
And executed with Valgrind as such:
valgrind --leak-check=full ./prog
Produces the following (truncated) output:
...
==18424== HEAP SUMMARY:
==18424== in use at exit: 42 bytes in 1 blocks
==18424== total heap usage: 1 allocs, 0 frees, 42 bytes allocated
==18424==
==18424== 42 bytes in 1 blocks are definitely lost in loss record 1 of 1
==18424== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18424== by 0x10865B: main (main.c:5)
==18424==
==18424== LEAK SUMMARY:
==18424== definitely lost: 42 bytes in 1 blocks
==18424== indirectly lost: 0 bytes in 0 blocks
==18424== possibly lost: 0 bytes in 0 blocks
==18424== still reachable: 0 bytes in 0 blocks
==18424== suppressed: 0 bytes in 0 blocks
...
Why does Valgrind say that the unfreed memory is "definitely lost"?
From the Valgrind Memcheck docs:
This means that no pointer to the block can be found. The block is classified as "lost", because the programmer could not possibly have freed it at program exit, since no pointer to it exists. This is likely a symptom of having lost the pointer at some earlier point in the program.
However, it's pretty clear that I could have easily freed the block before program exit. What am I missing here? Shouldn't the memory be "still reachable"?
Here's an example of "definitely lost" vs. "still reachable":
#include <stdio.h>
#include <stdlib.h>
void *p;
int main()
{
p = malloc(10);
p = malloc(100);
void *m = malloc(50);
return 0;
}
What happens in this code is the following:
10 bytes are allocated and the pointer to this memory is assigned to the global p.
100 bytes are allocated and the pointer to this memory is assigned to the global p. This overwrites the pointer value that pointed to 10 allocated bytes, and there is no other reference to it. So that memory is "definitely lost".
50 bytes are allocated and the pointer to this memory is assigned to the local m.
main returns causing the lifetime of m to end. As a result there is no reference stored to the memory pointer to 50 bytes so that memory is "definitely lost".
The pointer value pointing to 100 bytes still lives in the global p, so cleanup routines such as those called by atexit or other compiler specific methods could still clean up that memory. So it is "still reachable".
When running valgrind on this code, it outputs the following:
==60822== Memcheck, a memory error detector
==60822== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==60822== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==60822== Command: ./x1
==60822==
==60822==
==60822== HEAP SUMMARY:
==60822== in use at exit: 160 bytes in 3 blocks
==60822== total heap usage: 3 allocs, 0 frees, 160 bytes allocated
==60822==
==60822== LEAK SUMMARY:
==60822== definitely lost: 60 bytes in 2 blocks
==60822== indirectly lost: 0 bytes in 0 blocks
==60822== possibly lost: 0 bytes in 0 blocks
==60822== still reachable: 100 bytes in 1 blocks
==60822== suppressed: 0 bytes in 0 blocks
==60822== Rerun with --leak-check=full to see details of leaked memory
==60822==
==60822== For counts of detected and suppressed errors, rerun with: -v
==60822== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Which is consistent with the description above.
So to summarize, memory is "still reachable" if a pointer to it is stored either in a file scope variable or is pointed to by any "still reachable" memory. Otherwise it is lost.
Why does Valgrind say that the unfreed memory is "definitely lost"?
Because - once main returns the variable my_str doesn't exist anymore. Consequently, there is no way to free the allocated memory. And there is no way to reach the memory. No one know where the memory is. It's lost.
Note: All modern OS systems will however take care of the memory clean up so it's not a real problem.
Valgrind is checking for memory leaks, and you are leaking memory as you didn't free the pointer before exit. You should free(my_str) .
int main(void)
{
char *my_str = malloc(42 * sizeof(char));
free (my_str);
return 0;
}
Definitely Lost mean that nobody has a reference to that memory location anymore, so nobody could free that memory. In a context of a running program that will be a segment of memory that nobody could reuse (so it is lost). Of course at the end of the program nobody will ever use it again, but some of the memory could be referenced by another leaking object (and will be an indirect lost), so with those hints you can debug your program. The link bellow shows a discussion on the topic.
This is a complete response on why you should free memory before exit
I recognize that many do not consider "still reachable" memory leaks to be true memory leaks. However, I'm trying to get Valgrind to report errors whenever an error is "still reachable". To be more specific, this is my current output:
HEAP SUMMARY:
in use at exit: 23,221,680 bytes in 25 blocks
total heap usage: 27 allocs, 2 frees, 23,222,816 bytes allocated
Searching for pointers to 25 not-freed blocks
Checked 49,347,544 bytes
672 bytes in 24 blocks are still reachable in loss record 1 of 2
at 0x4C29792: malloc (** DETAILS OMITTED **)
by 0x2011F54: (** DETAILS OMITTED **)
by 0x405C75: main (** DETAILS OMITTED **)
23,221,008 bytes in 1 blocks are still reachable in loss record 2 of 2
at 0x4C29792: malloc (** DETAILS OMITTED **)
by 0x2011F54: (** DETAILS OMITTED **)
by 0x21B34CC: (** DETAILS OMITTED **)
by 0x20125DF: (** DETAILS OMITTED **)
by 0x406D14: main (** DETAILS OMITTED **)
LEAK SUMMARY:
definitely lost: 0 bytes in 0 blocks
indirectly lost: 0 bytes in 0 blocks
possibly lost: 0 bytes in 0 blocks
still reachable: 23,221,680 bytes in 25 blocks
suppressed: 0 bytes in 0 blocks
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
The two suppressed errors are coming from "still reachable" errors. I would like these to be considered proper errors so that the program returns an error code.
The two suppressed errors are coming from "still reachable" errors.
Almost surely not. The results of the leak check performed at program exit are largely separate from the analysis of erroneous memory accesses performed as the program runs. You can test with a dummy program such as this one that still-reachable memory does not produce a suppressed error:
#include <stdlib.h>
int main(void) {
void *p = malloc(8);
return (int) p;
}
I get
==22685== LEAK SUMMARY:
==22685== definitely lost: 0 bytes in 0 blocks
==22685== indirectly lost: 0 bytes in 0 blocks
==22685== possibly lost: 0 bytes in 0 blocks
==22685== still reachable: 8 bytes in 1 blocks
==22685== suppressed: 0 bytes in 0 blocks
==22685==
==22685== For counts of detected and suppressed errors, rerun with: -v
==22685== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Note well that 8 bytes are reported still reachable, and there are zero suppressed (or unsuppressed) errors.
I would like these to be considered proper errors so that the program returns an error code.
The point of suppressions is to ignore known, believed-harmless erroneous behavior, typically of system libraries. Although you can write your own suppression files, the suppressions you get by default arise from components out of your control.
It's an altogether different thing to exit with an error code in the event of various kinds of leak. You wrote in comments that you are running your valgrind test like so:
valgrind --leak-check=full --show-reachable=yes --show-leak-kinds=all --error-exitcode=1 \
--track-origins=yes --log-file=LOG_FILE_NAME -v EXECUTABLE_NAME
Notably missing from the options you are providing is --errors-for-leak-kinds, which is separate from --show-leak-kinds, and defaults to definite,possible. The combination --error-exitcode=1 --errors-for-leak-kinds=all should cause valgrind to count (and report) all classes of leaks as errors, and therefore to exit with status 1 in the event that it detects any memory still allocated when the program exits.
Is there a way to let valgrind to report "where" a "definitely lost" happens?
What I want is not "where it's allocated", but "where that poor piece of memory got leaked".
For example, this piece of code has a "definitely lost" leak when f() returns:
#include <stdlib.h>
void f () {
void *ptr = malloc(42);
}
int main () {
f();
return 0;
}
But valgrind only reports the origin of allocation:
==9772== HEAP SUMMARY:
==9772== in use at exit: 42 bytes in 1 blocks
==9772== total heap usage: 1 allocs, 0 frees, 42 bytes allocated
==9772==
==9772== 42 bytes in 1 blocks are definitely lost in loss record 1 of 1
==9772== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9772== by 0x40053E: f (test.c:4)
==9772== by 0x400552: main (test.c:8)
==9772==
==9772== LEAK SUMMARY:
==9772== definitely lost: 42 bytes in 1 blocks
==9772== indirectly lost: 0 bytes in 0 blocks
==9772== possibly lost: 0 bytes in 0 blocks
==9772== still reachable: 0 bytes in 0 blocks
==9772== suppressed: 0 bytes in 0 blocks
==9772==
==9772== For counts of detected and suppressed errors, rerun with: -v
==9772== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
I'm using --leak-check=full and --track-origins=yes.
What I want is not "where it's allocated", but "where that poor piece
of memory got leaked".
No, Valgrind only reports where the memory was allocated, but not when how or why it was leaked. This behavior is documented in Memcheck manual:
If --leak-check=full is specified, Memcheck will give details for each
definitely lost or possibly lost block, including where it was
allocated. (Actually, it merges results for all blocks that have the
same leak kind and sufficiently similar stack traces into a single
"loss record". The --leak-resolution lets you control the meaning of
"sufficiently similar".) It cannot tell you when or how or why the
pointer to a leaked block was lost; you have to work that out for
yourself.
Also --track-origins has nothing to do with memory leaks. It is used for tracking the origin of uninitialised values.
I am using Valgrind tool to understand the different types of memory leaks:
Directly lost,Indirectly lost Still reachable and possibly lost.
Ex1:
#include<stdio.h>
#include <stdlib.h>
main() {
int *p, i;
p = malloc(10*sizeof(int));
for(i = 0;i < 10;i++)
p[i] = i;
//free(p);
printf("Freed\n ");
}
LEAK SUMMARY:
==31770== definitely lost: 0 bytes in 0 blocks
==31770== indirectly lost: 0 bytes in 0 blocks
==31770== possibly lost: 20 bytes in 1 blocks
==31770== still reachable: 0 bytes in 0 blocks
==31770== suppressed: 0 bytes in 0 blocks
eg2:
main() {
int *p, i;
p = malloc(10*sizeof(int));
// printf("freed");
}
LEAK SUMMARY:
==14950== definitely lost: 0 bytes in 0 blocks
==14950== indirectly lost: 0 bytes in 0 blocks
==14950== possibly lost: 0 bytes in 0 blocks
==14950== still reachable: 40 bytes in 1 blocks
==14950== suppressed: 0 bytes in 0 blocks
If a uncomment the printf statement:
LEAK SUMMARY:
==15889== definitely lost: 40 bytes in 1 blocks
==15889== indirectly lost: 0 bytes in 0 blocks
==15889== possibly lost: 0 bytes in 0 blocks
==15889== still reachable: 0 bytes in 0 blocks
==15889== suppressed: 0 bytes in 0 blocks
Please explain me exactly about those different memory leaks.
A quick internet search leads to the following site:
http://valgrind.org/docs/manual/faq.html#faq.deflost
The details are in the Memcheck section of the user manual.
In short:
"definitely lost" means your program is leaking memory -- fix
those leaks!
"indirectly lost" means your program is leaking memory in a
pointer-based structure. (E.g. if the root node of a binary tree is
"definitely lost", all the children will be "indirectly lost".) If you
fix the "definitely lost" leaks, the "indirectly lost" leaks should go
away.
"possibly lost" means your program is leaking memory, unless
you're doing unusual things with pointers that could cause them to
point into the middle of an allocated block; see the user manual for
some possible causes. Use --show-possibly-lost=no if you don't want to
see these reports.
"still reachable" means your program is probably ok -- it didn't
free some memory it could have. This is quite common and often
reasonable. Don't use --show-reachable=yes if you don't want to see
these reports.
"suppressed" means that a leak error has been suppressed. There
are some suppressions in the default suppression files. You can ignore
suppressed errors.
Update:
The difference between "definitely lost" and "still reachable" is as follows:
Your memory is definitely lost if all references to it are gone and you did not free it before - the classical case of a memory leak.
It is still reachable when, at the end of your program's lifetime, you did not free all memory that was dynamically allocated but there are still valid references to it, so that it could have been freed.
Since all of the program's memory is freed at program termination anyway, this isn't usually a problem. However for a long running program and large memory allocations, it might be worth manually freeing those if you don't need them anymore.
Let me show you a simple example:
#include <stdio.h>
#include <stdlib.h>
char *still_reachable;
char *definitely_lost_global;
int main()
{
char *definitely_lost_local;
// allocate 10 bytes of memory -> will get lost
definitely_lost_local = malloc(10 * sizeof *definitely_lost_local);
// allocate 20 bytes of memory -> will get lost
definitely_lost_global = malloc(20 * sizeof *definitely_lost_global);
definitely_lost_global = NULL;
// Now there aren't any references to those 20 bytes anymore, so memory is lost.
// allocate 40 bytes of memory. The global pointer has static storage duration.
// We do not change the pointer, so the respective memory will
// be still reachable by the end of program lifetime
still_reachable = malloc(40 * sizeof *still_reachable);
} // scope of definitely_lost_local ends here --> 10 bytes are lost!
We can guess that 10+20 = 30 bytes will be lost in this example, while 40 bytes will be still reachable. So let's check with valgrind:
==19474== Memcheck, a memory error detector
==19474== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==19474== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==19474== Command: ./prog
==19474==
==19474==
==19474== HEAP SUMMARY:
==19474== in use at exit: 70 bytes in 3 blocks
==19474== total heap usage: 3 allocs, 0 frees, 70 bytes allocated
==19474==
==19474== LEAK SUMMARY:
==19474== definitely lost: 30 bytes in 2 blocks
==19474== indirectly lost: 0 bytes in 0 blocks
==19474== possibly lost: 0 bytes in 0 blocks
==19474== still reachable: 40 bytes in 1 blocks
==19474== suppressed: 0 bytes in 0 blocks
==19474== Rerun with --leak-check=full to see details of leaked memory
==19474==
==19474== For counts of detected and suppressed errors, rerun with: -v
==19474== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Voilá, as expected.
So I have a php, ruby and python background and got started with C. I'm using Valgrind to check if my programs are not doing silly things but I get this kind of output quite frequently:
14072== <...VALGRIND HEADER & COPYRIGHT...>
14158== HEAP SUMMARY:
14158== in use at exit: 137,084 bytes in 196 blocks
14158== total heap usage: 247 allocs, 51 frees, 149,496 bytes allocated
14158==
14158== 7 bytes in 1 blocks are definitely lost in loss record 3 of 74 at
14158== 0x4C2745D: malloc in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so
14158== by 0x50F3369: strdup in /usr/lib64/libc-2.18.so
14158== by 0x4E51B34: readline in /usr/lib64/libedit.so.0.0.43
14158== by 0x40083C: main in /home/<program location>/
14158==
14158== LEAK SUMMARY:
14158== definitely lost: 7 bytes in 1 blocks
14158== indirectly lost: 0 bytes in 0 blocks
14158== possibly lost: 0 bytes in 0 blocks
14158== still reachable: 137,077 bytes in 195 blocks
14158== suppressed: 0 bytes in 0 blocks
14158== Reachable blocks (those to which a pointer was found) are not shown.
14158== To see them, rerun with: --leak-check=full --show-leak-kinds=all
14158==
14158== For counts of detected and suppressed errors, rerun with: -v
14158== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)
This valgrind debug output is from this quick REPL that simply shouts back user input on the screen or quits in case input equals to :exit:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <editline/readline.h>
static char prompt[5] = "repl>";
static char* cmd_exit = ":exit";
int main(int argc, char** argv) {
puts("Press Ctrl+c to Exit\n");
while(1) {
char* input = readline(prompt);
add_history(input);
if(strcmp(input,cmd_exit) == 0) {
puts("Bye!");
return 0;
}
printf("%s\n", input);
free(input);
}
return 0;
}
I've already tried to free both prompt and cmd_exit variables before function main returns a value but leak is still there according to Valgrind.
...
free(prompt);
free(cmd_exit);
return 0;
}
Some questions:
How to get rid of this reported memory leak?
Should I be using static variables in this situation?
Should I free those static variables too?
Any good advice or material is welcome.
You only need to free things you malloced, so you don't need to free the static variables.
As your readline function seems to use strdup and that uses malloc/calloc, you need to free input. You do this in the loop which is good, but you missed it when you exit the loop:
if(strcmp(input,cmd_exit) == 0) {
puts("Bye!");
free(input);
return 0;
}
By the way:
static char prompt[6] = "repl>";
The text "repl>" has 6 chars, r, e, p, l, > and a nul byte to mark the end of the string.