code hardening

Hey! Since the 0.01 Release of Astera I’ve been working on making the code more reliable and efficient. I’ve fortunately not lost much motivation as to moving towards 0.02 and the added features which that will bring along with it.

A lot of this information exists online, but this post is meant to be a sort of introduction & combination of a few different sources. Just as a preface, this is meant for code hardening with clang & gcc. The two have many of the same features, tho some are not interchangable. As I’m making a cross platform game library/framework/thing, I test everything I can on whichever popular compilers I can get my hands on. The windows process for this is something that is tailored to that as well as MSVC’s respective flags.

Also please keep in mind that these are all tools I use in my own workflow. As I work primarily in C99 and more towards Linux / Unix environment. Thus they’ll tend to reflect that as well. However, most of these concepts / tools have direct analogs to Windows as well.

ASAN

ASAN is the shorter form of saying, “AdressSanitizer”. It’s an open source tool created by Google that helps detect memory leaks, overflows, and various other memory issues. If you’re working on something and it seems like you have a memory bug, you’re gonna want this in your toolkit. Keep in mind, when using the tool, it’ll increase the memory footprint of the program overall substantially. You’ll want to make sure you have plenty of overhead.

Installation

Depending on your operating system, you might have to install AddressSanitizer or asan of some sort. Since I’m on Void Linux I had to install libsanitizer (and the -devel package, just to be safe) in order for it to work with GCC correctly. Clang seems to sometimes bundle it on it’s own as well, however without the package it was giving me incomplete output. So double check you have the library installed!

Other than that, you’re pretty much good to go. Any updated / modern (ish) compiler should have support for asan.

Usage

Configuration for this tool is surprisingly simple for what it provides. For my specific configuration I added these compilation options (flags):

-fsanitize=address -fno-omit-frame-pointer -O2 -g

If you’re using cmake, you’ll want to make sure you add -fsanitize=address to your link options as well.

in CMake this looks a little like the following:

target_compile_options(${PROJECT_NAME}
  PUBLIC
  -fsanitize=address -fno-omit-frame-pointer -O2 -g)
target_link_options(${PROJECT_NAME}
  PUBLIC
  -fsanitize=address)

Now let’s break down each of the flags, a good reference for these is GCC’s page on Instrumentation Options.

From the documentation you can see that -fsanitize=address is what’s enabling the memory error detector, it’s the primary flag of the list. On top of this, -fno-omit-frame-pointer ensures that the stack frame pointer isn’t omitted for functions that require it. -O2 enables all optimizations, which is ultimately what you want to debug memory leaks with since they’ll start appearing with more optimizations and less leniant standards of compilation / language usage.

Side tip: If you really want to have fun and harden functionality of the code, enable -fsanitize=undefined. This enables the UndefinedBehaviorSanitizer which, really, really goes into detail about precision of your program. You can find more info on different sanitizers at the link for Instrumentation Options.

Valgrind

Checking for memory leaks is often one half of the equation that is memory optimization. Profiling it can prove to be a mysterious and somewhat magical thing for programmers that haven’t used tools for it before. You might have heard of Valgrind before, it’s a relatively popular tool. If you haven’t used it before it’s relatively straighforward to use.

Installation

Many operating systems don’t come with it installed, so definitely make sure you have it installed. (xbps-install valgrind for me on void linux)

Ubuntu installation would be something like

sudo apt-get install valgrind

Usage

The general usage is pretty easy to grasp, it’s usually as follows:

valgrind --tool=toolname program

There are a few different tools valgrind has, such as memcheck (for memory profiling), massif (heap profiler), or cachegrind (cache & branch prediction profiler).

For more in depth on how to use these tools, check out the valgrind manual.

Other useful flags

Many of these flags are gathered from Red Hat’s page on Recommended compiler and linker flags for GCC. I’ll just go over a few of them which you might really benefit from.

-D_FORTIFY_SOURCE=2 - Fortify Source enables some lightweight checks to be used on various string & memory manipulation functions. Some of these checks are run at compile time which will manifest as compiler warnings, others are runtime. The 2 Option just means to use more / most checks.

-Wall -pedantic -Wextra - This is maybe the most insanity condusive of them all. I try to only do this to myself once or twice a week at most. It enables all recommended compiler warnings (-Wall)

-fplugin=annobin - annobin is meant to be a binary tool which helps generate data about the binary, how it was made, what was used to make it, stuff like that. Red Hat has a good post that goes into detail on the usage of it.

-fstack-protector-all / -fstack-protector - This causes more code to be emitted to check for buffer overflows. It does some fun stuff with adding guard variables and more checks, if one of the checks fails, it’ll print an error and exit the program.

-O2 - I referenced this earlier, but it enables the compiler’s recommended optimizations. Definitely make sure you have this enabled for anything you’re trying to ship.

-g - I’m pretty sure a lot, if not most, of us have heard / used this flag before. It causes the compiler to generate debugging information. Inverse to the O2 flag, maybe don’t have this enabled when you’re compiling something to ship!

Wrapping up

I hope this proves useful for you, if you want more of these style posts, be sure to let me know.


footer_iconDevon