Valgrind Container for Mac
Published:
In one of my computer science classes, we were introduced to using Valgrind for unveiling memory leaks in C. I found this was a well-made tool that I wanted accessible on all my systems. There was however the limitation of being made for Linux based systems, with limited support for macOS. Implementing a container based solution could however be the simplest way of overcoming the limited platform support.

Setup
The source code for this project is available on GitHub.
The implementation consists of three main parts. All three of them have many potential areas of improvements, however, let’s keep it simple.
Refer to the docker installation for how to install docker.
The procedure is as follows:
- Create a docker image
- In this image we will install all dependencies and the base operating system.
- Set up an alias to run the container.
- Running the container with Valgrind commands.
Docker image
Start by creating a Dockerfile in your projects root. Using the latest alpine Linux image we also add Valgrind, g++ and make.
from alpine:latest
# Add valgrind and g++
run apk add g++ valgrind make
# Set working directory
workdir /code
The last step above is not very important but makes the process cleaner, set a working directory for the image as well.
Building the image is as simple as using the docker build command:
docker build -t [image-name]:[version] .
I used Valgrind for the image name and 1.0 for the version tag.
Alias setup
Using an alias for running the container makes the process a little more lightweight. Another option here would be to create a bash script or similar, but then again, I wanted this to be as simple as possible.
alias valgrind='docker run -it --rm -v $PWD:/code [image-name]:[version]'
As you may be familiar with, alias definitions are defined per session. Therefore, to permanently set the alias, put the line above into your .zshrc (or equivalent configuration file).
Usage
It really is as straight forward as typing:
valgrind /bin/sh -c "gcc src.c; valgrind [options] ./a.out; rm ./a.out"
The above command uses our alias valgrind, which will start the container, mapping the current working directory to the /code directory within the container.
/bin/sh -c is executing the command to follow inside the container using its built in shell, stopping the container afterward. Remember the --rm flag we specified in the alias definition, this will completely remove the container once it is stopped.
Notice that in the command we are running inside our container we are first compiling the source file. This is because our docker image is on another platform. Had we already compiled a binary and tried to execute it inside the container, we would get an error. The next command (delimited by semicolons) is actually executing Valgrind with any options on the compiled output. In the end we also remove the output binary as this has no value to us. Because the container is mapped to the working directory, it will appear on our host system, but not be possible to execute without compiling the source again.
Example
Valgrind supports many levels of depth when checking for memory leaks. Check out the documentation over at Valgrind.
An example usage is provided in the source code:
From the repository, move into the example.
cd example
Test the program:
valgrind /bin/sh -c "gcc main.c; \
valgrind --leak-check=full \
--show-leak-kinds=all \
--track-origins=yes \
--verbose ./a.out; \
rm ./a.out"
The output will show the memory leaks, refer to quickstart for further explanations of the memory leaks.
