Monday, February 24, 2014

Valgrind's Memcheck: Detect user space run time memory errors


In my last post, I covered Valgrind's high level overview. In this post, I will cover Valgrind's popular sub-tool: memcheck.

memcheck Overview 

memcheck helps in detecting:
  • Memory corruptions
    • Writing/Reading to unallocated/freed memory, post heap blocks (overrun)
    • Writing/Reading  to unallocated stack
    • buffer overrun: Passes overlapping source and destination memory blocks to memcpy() and related functions 
  • Incorrect Memory operations
    • Reading uninitialized memory 
    • Double free 
    • Mismatched free (c++ relevant, not c)
  • Passing inaccessible memory to system call 
  • Memory leaks 

memcheck Usage


  • Step1: Recompile the program enabling gdb & turning off compiler optimizations:
gcc -g prog.c -o <prog_name>

  • Step2: Run the program in valgrind emulator:
valgrind --track-origins=yes <prog_name> <prog_args>
    ------ Outputs memcheck's dynamic analysis information to console.

valgrind --log-file=<log_file> --track-origins=yes <prog_name> <prog_args>
    ------ Stores memcheck's dynamic analysis information in log_file. memcheck's output is not easily readable, so I prefer storing the info in a log file for offline analysis.

Usage Example:
  
I used the code at https://github.com/babuneelam/valgrind_tests/blob/master/vg_tests.c to explore 10 of the 11 tests:
  1. uninitialized use
  2. Read/Write after free
  3. buffer overrun
  4. Read/Write bad stack location (underrun)
  5. Memory Leak
  6. c++related test (ignore this)
  7. Overlapping memcpy
  8. double free
  9. pass unaddressable memory to system call
  10. Read/Write invalid stack location (overrun)
  11. Read/Write invalid global data location (overrun) 

Here are the results:

root@babu-VirtualBox:~/valgrind_tests# gcc -g vg_test.c -o vg_test.o
root@babu-VirtualBox:~/valgrind_tests#
root@babu-VirtualBox:~/valgrind_tests# valgrind --track-origins=yes --leak-check=full ./vg_test.o 1 2 3 4 5 7 8 9 10 11
.
.
.
root@babu-VirtualBox:~/valgrind_tests# valgrind --log-file=vg_log --track-origins=yes --leak-check=full ./vg_test.o 1 2 3 4 5 7 8 9 10 11
10
*num = 0
i[-1] = 0
Please type a bunch of characters and hit enter.
34

root@babu-VirtualBox:~/valgrind_tests#

Valgrind expects the process to be terminated before reporting memory leak. I am yet to come up with a procedure that helps in collecting memory information without terminating the process. 

Reporting and Analysis of memcheck results
I placed the above generated log file at https://github.com/babuneelam/valgrind_tests/blob/master/vg_log.

Memcheck's dynamic analysis results are output to console/log file as and when the running program encounters a run time memory error. As we can see in the above log, it also displays the entire stack trace of each memory error. Memcheck tracks addressability at the byte-level, and initialisation of values at the bit-level. As a result, it can detect the use of single uninitialised bits, and does not report spurious errors on bitfield operations.

Drawbacks

  • Valgrind doesn't work well with linked libraries - static libraries seem to be working now, but dynamic libraries are still are not working. I am yet to come up with tests that show these deficiencies in memcheck.
  • Performance impact of memcheck: The user space applications run 10-30x slower with  memcheck. I am yet to come up with tests that measure the slowdown.
  • The log file of memcheck is not intuitive. In my other post, I covered a GUI tool - Valkyrie - that addresses this issue.
  • Requires recompilation of user space application for useful reporting. Valgrind works even on stock binaries. I tried memcheck without recompiling the sources. Here is the log: https://github.com/babuneelam/valgrind_tests/blob/master/vg_log_without_sources. The report is not that bad, but misses out line number information for the reported errors. 

Reference:
http://valgrind.org/docs/manual/mc-manual.html

No comments:

UA-48797665-1