Search code examples
cmemory-leaksvalgrindcairo

Cairo Linking Causes Memory Leak


I was messing around with Cairo and quickly realized that even just linking the library (-I/usr/include/cairo) regularly without using it or allocating anything causes memory leaks. Has anyone had this issue? Is there a piece of cairo-specific code I need to include to avoid leaks when linking?

Sample Hello world program:

#include <stdio.h>

int main(){
  printf("Hello, world!\n");
  return 0;
}

Compiling regularly:

gcc -o test test.c -Wall

Hello, world!
==19531== 
==19531== HEAP SUMMARY:
==19531==     in use at exit: 0 bytes in 0 blocks
==19531==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==19531== 
==19531== All heap blocks were freed -- no leaks are possible
==19531== 
==19531== For counts of detected and suppressed errors, rerun with: -v
==19531== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Linking Cairo:

gcc -o test test.c -Wall $(pkg-config --cflags --libs cairo)

Hello, world!
==19538== 
==19538== HEAP SUMMARY:
==19538==     in use at exit: 12,384 bytes in 6 blocks
==19538==   total heap usage: 6 allocs, 0 frees, 12,384 bytes allocated
==19538== 
==19538== LEAK SUMMARY:
==19538==    definitely lost: 0 bytes in 0 blocks
==19538==    indirectly lost: 0 bytes in 0 blocks
==19538==      possibly lost: 0 bytes in 0 blocks
==19538==    still reachable: 12,384 bytes in 6 blocks
==19538==         suppressed: 0 bytes in 0 blocks
==19538== Rerun with --leak-check=full to see details of leaked memory
==19538== 
==19538== For counts of detected and suppressed errors, rerun with: -v
==19538== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Leak-check=full:

valgrind ./test --leak-check=full -v --tool=memcheck
==20390== Memcheck, a memory error detector
==20390== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==20390== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==20390== Command: ./test --leak-check=full -v --tool=memcheck
==20390== 
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/ld-2.22.so:
--20390-- Ignoring non-Dwarf2/3/4 block in .debug_info
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/ld-2.22.so:
--20390-- Last block truncated in .debug_info; ignoring
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/ld-2.22.so:
--20390-- parse_CU_Header: is neither DWARF2 nor DWARF3 nor DWARF4
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/libc-2.22.so:
--20390-- Ignoring non-Dwarf2/3/4 block in .debug_info
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/libc-2.22.so:
--20390-- Ignoring non-Dwarf2/3/4 block in .debug_info
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/libc-2.22.so:
--20390-- Ignoring non-Dwarf2/3/4 block in .debug_info
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/libc-2.22.so:
--20390-- Last block truncated in .debug_info; ignoring
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/libc-2.22.so:
--20390-- parse_CU_Header: is neither DWARF2 nor DWARF3 nor DWARF4
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/librt-2.22.so:
--20390-- Ignoring non-Dwarf2/3/4 block in .debug_info
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/librt-2.22.so:
--20390-- Last block truncated in .debug_info; ignoring
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/librt-2.22.so:
--20390-- parse_CU_Header: is neither DWARF2 nor DWARF3 nor DWARF4
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/libm-2.22.so:
--20390-- Ignoring non-Dwarf2/3/4 block in .debug_info
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/libm-2.22.so:
--20390-- Last block truncated in .debug_info; ignoring
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/libm-2.22.so:
--20390-- parse_CU_Header: is neither DWARF2 nor DWARF3 nor DWARF4
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/libdl-2.22.so:
--20390-- Ignoring non-Dwarf2/3/4 block in .debug_info
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/libdl-2.22.so:
--20390-- Last block truncated in .debug_info; ignoring
--20390-- WARNING: Serious error when reading debug info
--20390-- When reading debug info from /lib/x86_64-linux-gnu/libdl-2.22.so:
--20390-- parse_CU_Header: is neither DWARF2 nor DWARF3 nor DWARF4
Hello, world!
==20390== 
==20390== HEAP SUMMARY:
==20390==     in use at exit: 12,384 bytes in 6 blocks
==20390==   total heap usage: 6 allocs, 0 frees, 12,384 bytes allocated
==20390== 
==20390== LEAK SUMMARY:
==20390==    definitely lost: 0 bytes in 0 blocks
==20390==    indirectly lost: 0 bytes in 0 blocks
==20390==      possibly lost: 0 bytes in 0 blocks
==20390==    still reachable: 12,384 bytes in 6 blocks
==20390==         suppressed: 0 bytes in 0 blocks
==20390== Rerun with --leak-check=full to see details of leaked memory
==20390== 
==20390== For counts of detected and suppressed errors, rerun with: -v
==20390== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Solution

  • You're not seeing leaked memory, as such. You're seeing memory that wasn't deallocated via free() or the delete operator when the application exited, which might or might not be an intentional leak. In my mind, at least, "leaked memory" is memory that you could have intentionally deallocated, but didn't.

    From the diagnostic output you provided, you can't tell whether the 12,384 bytes were allocated by the C runtime or by Cairo. There's also the possibility that the 12K is dynamic linking overhead, which could be the case if Cairo is a .so object on your system. In that case, it's runtime overhead that you can't escape.

    Basically, without running with --leak-check=full, you can't conclusively prove or disprove that the memory is leaked or who leaked it.

    And (now) since valgrind doesn't provide further insight, and dmalloc says that the pointers are foreign, the old school method is: fire up gdb, set a breakpoint in malloc and look at the backtrace.