Parasoft Insure++

Recently my employer purchased a license for Parasoft’s Insure++ for my use.

The idea of Insure++ is that you build your C/C++ application with their Insure++ tool, and it instruments your application to identify buffer overruns, etc.

NOTE BENE: The Insure++ instrumented build will only run on the machine on which Insure++ is licensed. You can’t build your application with Insure++ on your development machine and execute it on any other machine (e.g. a ‘lab rat’ test machine) without purchasing an additional license.

NOTE BENE: The license only covers one OS. It’s $4000 for the Linux version. And another $4000 for the Windows version. Etc.

Installing Insure++

I’m currently running Ubuntu 16.04. There were dependencies not covered in the installation documentation: specifically you will need to install ‘motif’ and another ‘.so’ (an X Printing Extension: Xprint) client library. Perform the following to get Parasoft Insure++ to work:

apt install libmotif-dev

And, append this line to /etc/apt/sources.list:
deb http://security.ubuntu.com/ubuntu precise-security main

Then:
apt update
apt install libxp6

A Simple Example

Parasoft includes an example makefile that compiles numerous example projects. It was not immediately obvious to me how to apply the given example(s) to my particular project. So, for an initial example, I still think it’s hard to beat K&R’s “Hello world”. Here’s how to instrument that with Insure++:

#include

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

You will need the following voodoo (not covered in the documentation that I could find) to successfully build this trivial program:

insure gcc -Wl,--no-as-needed -g main.c -o main

Insure++ and CMake

Insure++ assumes you are using old-school make files. Being an old-school developer I’m quite comfortable with those. Meanwhile, today I also use the JetBrains line of IDEs, including CLion, which depends on CMake for its underlying make engine.

Enabling Insure++ requires you to modify your ‘makefile’, basically replacing ‘gcc’ with ‘insure gcc’. Even after a Google search it was far from obvious how to accomplish that with CMake. So I called tech support to find out how to implement Insure++ with CMake. Mind you, theJetBrains/Clion IDE (depending as it does on mainstream technologies like gcc and CMake) is a dominant player in Linux C/C++ development. So imagine my surprise when the support tech’s questions made it clear that he had no idea what CMake was about.

In the end I ended up creating a make file (in parallel with our existing CMake CMakeLists.txt file) just so I could implement Insure++.

Insure++ and a Real C++ Program

Armed with the above, I was still unable to build a real C++ application. The following additional voodoo was required:

OPTIONS="-O0 -g"
SOURCE="*.cpp"
insure gcc $OPTIONS $SOURCE -Zvm -Zvm -Zvm -Zvm -o myapp

(That is not a typo: tech support said I needed ‘-Zvm -Zvm -Zvm -Zvm’ in my command line. Which resulted in successfully compiling the program. So far no useful/actionable results.)

Tentative Conclusion

Purchasing Insure++ was motivated by tracking down a segmentation fault that occurs occasionally. (A seg fault that Valgrind wasn’t finding either.) In parallel with implementing Insure++ I did deeper research on existing capabilities of gcc (and other open source resources). To my pleasant surprise there is much more debug instrumentation available with gcc than I knew. (See my blog C/C++ Stack & Heap Testing with gcc). So far this additional gcc instrumentation has flushed out several issues, where Insure++ has yet to flush out even one. And I personally have five ‘labrat’ test machines at my disposal, and they can all run gcc-instrumentation-enhanced debug builds of our app, whereas I can’t apply Insure++ to ANY of those testing resources without a considerable additional fee. Which might be OK if it were delivering results.

Even when it’s my own personal wallet, I have no problem paying for software that is useful. So far Insure++ has yet to deliver anything close to the results of [free] gcc capabilities. I’ll revise this blog if that assessment changes.

C/C++ Stack & Heap Checking with gcc

Stack, heap, and memory issues in general are a chronic problem with C/C++.

For Linux, there’s Valgrind, which is a truly useful tool. But it requires that one explicitly run the application under development under Valgrind. And we were experiencing a segmentation fault issue that Valgrind wasn’t identifying. (Nobody’s perfect!)

It turns out that gcc itself includes debugging support for this class of issues. One huge advantage of these sorts of ‘built in tests’ (also true of assert()s) is that you get ‘free’ testing every time you run a debug build. It’s practically free testing! Who doesn’t want THAT?

Here’s a list of these options (not entirely mutually exclusive). To use, say, -fmydebugoption you would compile with

gcc -fmydebugoption main.c -o main

-fstack-check

If the two macros associated with this feature, namely STACK_CHECK_BUILTIN and STACK_CHECK_STATIC_BUILTIN are left at the default 0, this option inserts a NULL byte every 4kb (page) when the stack grows. By default only one 4K page, but when the stack can grow more than one page (the most dangerous case), every 4KB. See https://gcc.gnu.org/onlinedocs/gcc-4.8.4/gccint/Stack-Checking.html for details.

-fstack-protector

A family of checks involving the same concept, with different degrees of thoroughness/performance-cost. The idea is to put a ‘canary’ — a randomly generated number/signature at the end of each function call, and check that this canary is uncorrupted when the function exits. That is, if a function overwrites the end of a local array (of any type), it will also overwrite the ‘canary’ and when the function exits this can be checked, and the program aborted if necessary.

  • fstack-protector: Add a ‘canary’ (see ‘-fstack-protector’) to functions that call malloc/calloc/etc, and functions with buffers larger than 8 bytes.
  • fstack-protector-all: Add a ‘canary’ to every function (whether it has local arrays or memory allocations).
  • fstack-protector-string: Add a canary under any of the following circumstances:
    • Local variable’s address used as part of the right hand side of an assignment or function argument
    • Local variable is an array (or union containing an array), regardless of array type or length
    • Uses register local variables

    -finstrument-functions

    Generate instrumentation calls for entry and exit to functions. Just after function entry and just before function exit, the following profiling functions are called with the address of the current function and its call site. (On some platforms, __builtin_return_address does not work beyond the current function, so the call site information may not be available to the profiling functions otherwise.)


    void __cyg_profile_func_enter (void *this_fn,
    void *call_site);
    void __cyg_profile_func_exit (void *this_fn,
    void *call_site);

    The first argument is the address of the start of the current function, which may be looked up exactly in the symbol table.

    -fsanitize=address

    Enable AddressSanitizer, a fast memory error detector. Memory access instructions are instrumented to detect out-of-bounds and use-after-free bugs. The option enables -fsanitize-address-use-after-scope. See https://github.com/google/sanitizers/wiki/AddressSanitizer for more details. The option cannot be combined with -fsanitize=thread.

    -fsanitize=leak

    Enable LeakSanitizer, a memory leak detector. This option only matters for linking of executables and the executable is linked against a library that overrides malloc and other allocator functions. See https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer for more details. The run-time behavior can be influenced using the LSAN_OPTIONS environment variable. The option cannot be combined with -fsanitize=thread.

    -fsanitize=undefined

    A family of functions enabled by ‘sanitize=undefined’. Options include (not a complete list):

    • -fsanitize=integer-divide-by-zero:
      Detect integer division by zero as well as INT_MIN / -1 division.
    • -fsanitize=vla-bound
      This option instructs the compiler to check that the size of a variable length array is positive.

      For example:

      void fun(int n)
      {
      int arr[n];
      // ......
      }
      int main()
      {
      fun(6);
      }

    • -fsanitize=null
      This option enables pointer checking. Particularly, the application built with this option turned on will issue an error message when it tries to dereference a NULL pointer, or if a reference (possibly an rvalue reference) is bound to a NULL pointer, or if a method is invoked on an object pointed by a NULL pointer.
    • -fsanitize=return
      This option enables return statement checking. Programs built with this option turned on will issue an error message when the end of a non-void function is reached without actually returning a value. This option works in C++ only.
    • -fsanitize=signed-integer-overflow
      This option enables signed integer overflow checking. We check that the result of +, *, and both unary and binary – does not overflow in the signed arithmetics. Note, integer promotion rules must be taken into account. That is, the following is not an overflow:

      signed char a = SCHAR_MAX;
      a++;
    • -fsanitize=bounds
      This option enables instrumentation of array bounds. Various out of bounds accesses are detected. Flexible array members, flexible array member-like arrays, and initializers of variables with static storage are not instrumented.
    • -fsanitize=bounds-strict
      This option enables strict instrumentation of array bounds. Most out of bounds accesses are detected, including flexible array members and flexible array member-like arrays. Initializers of variables with static storage are not instrumented.
    • -fsanitize=object-size
      This option enables instrumentation of memory references using the __builtin_object_size function. Various out of bounds pointer accesses are detected.
    • -fsanitize=float-divide-by-zero
      Detect floating-point division by zero. Unlike other similar options, -fsanitize=float-divide-by-zero is not enabled by -fsanitize=undefined, since floating-point division by zero can be a legitimate way of obtaining infinities and NaNs.
    • -fsanitize=float-cast-overflow
      This option enables floating-point type to integer conversion checking. Check that the result of the conversion does not overflow. Unlike other similar options, -fsanitize=float-cast-overflow is not enabled by -fsanitize=undefined. This option does not work well with FE_INVALID exceptions enabled.
    • fsanitize=bool
      This option enables instrumentation of loads from bool. If a value other than 0/1 is loaded, a run-time error is issued.

    • -fsanitize=enum
      This option enables instrumentation of loads from an enum type. If a value outside the range of values for the enum type is loaded, a run-time error is issued.
    • -fsanitize=vptr
      This option enables instrumentation of C++ member function calls, member accesses and some conversions between pointers to base and derived classes, to verify the referenced object has the correct dynamic type.
    • -fsanitize=pointer-overflow
      This option enables instrumentation of pointer arithmetics. If the pointer arithmetics overflows, a run-time error is issued.

    -fno-omit-frame-pointer

    Generally speaking makes life easier for debuggers by putting frame pointers in a CPU register.

    Based on the above, I’m currently using


    gcc ... -fstack-check -stack-protector-strong -finstrument-functions -fsanitize=address -fsanitize=leak -fsanitize-undefined ...