Memory leak caused by agwrite

Hello!

I was implementing a C-function converting abstract syntax tree to Agraph_t * to output it then in the DOT format.

I called the agwrite function to print the converted tree out as a graph and used the agclose to clean the graph up. But I noticed the valgrind indicates that there is memory leak caused by the agwrite. There is the listing presenting its output below:

==53084== HEAP SUMMARY:
==53084==     in use at exit: 8,192 bytes in 1 blocks
==53084==   total heap usage: 329 allocs, 328 frees, 117,472 bytes allocated
==53084== 
==53084== 8,192 bytes in 1 blocks are still reachable in loss record 1 of 1
==53084==    at 0x483877F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==53084==    by 0x4A0D3D7: ??? (in /usr/lib/x86_64-linux-gnu/libcgraph.so.6.0.0)
==53084==    by 0x4A0DB58: agcanonStr (in /usr/lib/x86_64-linux-gnu/libcgraph.so.6.0.0)
==53084==    by 0x4A0DEAF: ??? (in /usr/lib/x86_64-linux-gnu/libcgraph.so.6.0.0)
==53084==    by 0x4A0E2DA: ??? (in /usr/lib/x86_64-linux-gnu/libcgraph.so.6.0.0)
==53084==    by 0x4A0EA1D: ??? (in /usr/lib/x86_64-linux-gnu/libcgraph.so.6.0.0)
==53084==    by 0x4A0EE68: agwrite (in /usr/lib/x86_64-linux-gnu/libcgraph.so.6.0.0)
==53084==    by 0x10E7E5: fprintASTAsDOT (ast-dot.c:16)
==53084==    by 0x10A3D0: main (main.c:18)
==53084== 
==53084== LEAK SUMMARY:
==53084==    definitely lost: 0 bytes in 0 blocks
==53084==    indirectly lost: 0 bytes in 0 blocks
==53084==      possibly lost: 0 bytes in 0 blocks
==53084==    still reachable: 8,192 bytes in 1 blocks
==53084==         suppressed: 0 bytes in 0 blocks

I put the link to the file here (/src/ast-dot.c:17).

If somebody wants to run it on a local machine there are code samples at /test/samples which can be parsed by the parser.

I want to get rid of any possible leaks. Help me to handle this please.

valgrind says 0 bytes were leaked. But It appears graphviz had a pointer to a dynamically allocated buffer at the time the process exited. It’s not hard to find code that does this in lib/cgraph/write.c

We were accustomed to relying on the operating system to recover any memory-related resources at process exit time. I’m not sure if this is considered acceptable in C programming in 2025. There was some similar issue raised a few years ago. I am pretty sure this involved releasing the “proto” graph in graph.c and I remember fixing this. I don’t see that code in the repo now. I can try to track down the MR and see what happened. I don’t have time right now but can put it on the stack.

Dealing with this ixing this may also involve making sure finalization functions are called for all 3rd parties libraries that we invoke. This is a nontrivial job.

I see. I’d like you to put that task on the stack.
I will try to trace the issue myself by building the library locally, but I’m not sure I am skilled enough to perform such thing.
However, the problem is not critical, so consider that task a low-priority one.

agcanonStr was removed in 266622069cd502fc6a1940d092b5998cc17b92bc which landed in Graphviz 14.0.0. So yes, this allocation path is no longer reachable.

I installed the libgraphviz-dev package on my Debian 11 machine using apt. The last displayed version of the package is 2.42.2.
Does it mean the library is outdated?
How the version number of Graphviz related to the libgraphviz’s one exactly?

Yes, Debian’s package is significantly behind the current Graphviz release. AFAIK the Debian numbers correspond to Graphviz’ own versioning. I.e. Debian’s libgraphviz-dev 2.42.2 indeed is Graphviz 2.42.2.

To conclude, the issue has already been resolved in the current version of Graphviz, and the easiest way to avoid memory leaks in my project is to wait for the apt package to be updated, isn’t it?

2.42.2 is several (5+) years old. Waiting for a current version from Debian might be a very long wait.
You might consider building it from source - not rocket surgery, but admittedly a big unpleasant loop of:

  • what tool or library am I missing?
  • what does Debian (or whatever distro) call that tool/libraru?
  • install the tool/library using the appropriate listall tool
  • did I install the “right” (needed) tool/library?

Here is a quick/dirty script to install many of the needed tools & libraries that worked on Ubuntu. It would probably also work on Debian.

#set -x

echo "
autoconf
automake
bison
flex
gcc
gcc-g++
ghostscript
libtool
pkg-config
swig
cairo
expat
freetype
gd
libgd
fontconfig
urw-fonts
glib
libglib
libpng16
pango
libpangocairo 
zlib
GTS
libgts
GTK+
libgtk
libgtkextra
GtkGLExt
Glade
Glut
" | while read X;do if [[ $X != "" ]];then  sudo apt-get -y install $X  ;fi;done

Why not apt-get build-deps graphviz?

Robert Hart

I have no experience with this command. If it works, all the better.

Perhaps a higher level question to ask is what your goal is here. The leak we’re discussing is a single allocation (O(1)), so it’s unlikely to cause memory exhaustion problems. It’s arguably not even leaked, as agcanonStr still has a pointer to it internally. Are you trying to satisfy some surrounding leak-checking tool?

This is my study project and it is required to avoid any kind of memory leak if possible. However, I suppose the issue we are discussing may be a special case, so I think I should consider the leak to be both acceptable and unavoidable.

I guess this is the stack of the graphviz project, isn’t it?
I wonder why there is no some development container for such project?

Anyway, building the libgraphviz-dev from source seems a good approach.

However, it is not suitable for my project as it would require compiling the library many times on different machines, so it would be inefficient.