Wednesday, January 13, 2016

Sanitizing Your C/C++ Code

GCC already has the capability to help with sanitizing your C/C++ code since version 4.9. This is probably one of GCC capability not known widely. Sanitizing in this context means cleaning up possible error, just in case you're not yet familiar with the terms. See: Defensive_programming for introduction.
This is a good introduction on GCC C/C++ "sanitizer":GCC Undefined Behavior Sanitizer – ubsan and for some details from GCC documentation (not really with exhaustive explanation, but complete) see: GCC Debugging Options -- see the section on -fsanitize=.. option.

Anyway, using the sanitizer option is not quite straightforward because you have to install the corresponding libraries for the sanitizer. These libraries will provide replacement for C library functions related to the sanitizer. For example: it provides malloc() replacement to provide memory leak detection. There are two libraries which you must install aside from GCC version >= 4.9, i.e. libasan (address sanitizer library) and libubsan (undefined behavour sanitizer library). I'll give you an example here in CentOS 7.

CentOS 7 comes with GCC 4.8 by default. Therefore, sanitizer support (especially libubsan) is missing. Therefore, we need to upgrade it. To do so, update the CentOS  repo data with ones for Fedora 23, so that we can upgrade to GCC 5.1.1, like so:
# cat << EOF > /etc/yum.repos.d/Fedora-Core23.repo
[warning:fedora]
name=fedora
mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-23&arch=$basearch
enabled=1
gpgcheck=1
gpgkey=https://getfedora.org/static/34EC9CBA.txt
EOF
# yum update gcc g++
# yum install libasan
# yum install libubsan
Now you have updated the C and C++ compiler and also installed the required libubsan and libasan. You can proceed to use -fsanitize option in GCC to add sanitizer option in your code.
Credits go to XakRu and sm1Ly for the script/command to add Fedora repo to CentOS (see: How To install gcc 5.2 on centos 7.1? [closed]).

Now let's proceed to learn how to use the flags in our build script. If you are using autotools, you can do these steps:
  1. Add -fsanitize=.. to your CFLAGS and/or CXXFLAGS
  2. Add -fsanitize=.. to your LDFLAGS as needed. Taking into account the GCC Debugging Options explanation.
  3. In some cases, you need to remove memory allocation function checks from configure.ac
This is an example build script (named build_debug.sh) which invokes configure script generated by autotools:
../configure CFLAGS="-DDEBUG -g -O0 -fsanitize=undefined -fsanitize=leak" \
 CXXFLAGS="-DDEBUG -g -O0 -fsanitize=undefined -fsanitize=leak" \
 LDFLAGS="-fsanitize=leak" --enable-debug \
 && make V=1
The build always failed when I enabled memory allocation function checks in configure.ac. Therefore, it needs to be disabled like so:
     ##AC_FUNC_MALLOC
     ##AC_FUNC_REALLOC
This happens because AC_FUNC_MALLOC and AC_FUNC_REALLOC are based on a runtime tests. See:https://github.com/LLNL/ior/issues/4

Hopefully, this is helpful for those developing software in C/C++ with GCC.
Post a Comment

No comments: