Search code examples
ccompilationvalgrinddiagnostics

How is Valgrind able to access line number of memory allocation in compiled C program, how I can I do the same?


When I run a simple Valgrind command, such as...

valgrind --leak-check=yes ./my_program

...the error output Valgrind produces shows where in the source code a memory allocation was made and where it was freed. How is Valgrind able to do this? How I could I do this myself, in the code of the program? If it helps, the CFLAGS parameters defined in my GCC makefile for the compilation are:

CFLAGS=-c -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -g -Og -std=c11 -pedantic

Solution

  • the error output Valgrind produces shows where in the source code a memory allocation was made and where it was freed. How is Valgrind able to do this?

    When you use valgrind, you do not launch your program directly. Instead, valgrind does it, in an environment and by means that permit it to do its monitoring in the first place. This includes, but is not limited to, substituting its own allocation functions for the standard library's normal implementations. It is these alternative allocation functions that give Valgrind the means to track the locations in the binary where allocations and frees occur.

    The information necessary to associate source line numbers with specific instructions in the compiled binary is part of the debug information included in the binary when you compile with the -g option. If you omit the -g you will find that Valgrind's output is less informative about the location of the error.

    How I could I do this myself, in the code of the program?

    You also can provide your own malloc etc. and free functions. You can cause them to be used throughout your program instead of the standard library's versions, though the details may depend in part on your C implementation. Doing this correctly is non-trivial and details are system-dependent.

    Means by which these functions can identify the point from which they are called is even more non-trivial and system dependent. The C language does not define any kind of introspective feature such as this would require, so you would need to provide that yourself.

    Standard C also does not define any way that a program could access debug information from its own binary, nor even any reliable way even to locate its own binary, nor, for that matter, "debug information". Valgrind has a distinct advantage over the program itself in this area: since valgrind launches the program, valgrind is in a position to know what binary it is launching.

    Overall, then, the answer is that if you have to ask the question in the first place then you probably are not equipped to do what you ask at all. You should instead look for an existing tool that does close enough to what you want (maybe valgrind itself), or change your requirements. In particular, you should consider whether the preprocessor-based mechanism described in @ryyker's answer provides a means to get close enough to what you have in mind.