aramadia
aramadia

Reputation: 1726

Runtime array bounds checking in C++ built with g++

Is there any way to do array bounds checking in C++ compiled using g++?

Ideally, the source code shouldn't be modified in any way. Using std::vector, std::tr1::array or boost::array is not an option because the codebase is large and such shift would be infeasible.

Upvotes: 22

Views: 17896

Answers (4)

qwr
qwr

Reputation: 10929

-D_GLIBCXX_DEBUG to turn on GCC debug mode. This will replace the standard containers with debug versions that do some runtime bound checking.

For example, if you declare a vector with

std::vector<int> v; 

then try to access v[0], you will get a runtime error like

/usr/include/c++/11/debug/vector:438:
In function:
    std::debug::vector<_Tp, _Allocator>::reference std::debug::vector<_Tp, 
    _Allocator>::operator[](std::debug::vector<_Tp, _Allocator>::size_type) 
    [with _Tp = int; _Allocator = std::allocator<int>; std::
    debug::vector<_Tp, _Allocator>::reference = int&; std::
    debug::vector<_Tp, _Allocator>::size_type = long unsigned int]

Error: attempt to subscript container with out-of-bounds index 0, but 
container only holds 0 elements.

Objects involved in the operation:
    sequence "this" @ 0x63bd2befb120 {
      type = std::debug::vector<int, std::allocator<int> >;
    }
Aborted (core dumped)

which gives you a much better hint than "Segmentation fault (core dumped)". AddressSanitizer with -fsanitize=address will tell you only

AddressSanitizer:DEADLYSIGNAL
=================================================================
==1555027==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x5657630479af bp 0x000000000001 sp 0x7fff872f6180 T0)
==1555027==The signal is caused by a WRITE memory access.
==1555027==Hint: address points to the zero page.
...

See Bound checking of std::array in "Debug" version of GCC

Upvotes: 0

Sam Watkins
Sam Watkins

Reputation: 8319

GCC mudflap (-fmudflap) can do bounds checking for C, but can't handle all C++ code as of mid-2012 (e.g. std::vector). It was removed in GCC 4.9 in mid-2015, superseded by Address Sanitizer. The mudflap options remain, but do nothing.

There is the MIRO patch – Mudflap Improved with Referent Objects. See its homepage for more information. Also, there is a paper about it.

I have tried MIRO briefly. It seems to be very good, but perhaps will not work with 100% of C++ code. I intend to use MIRO during development, then turn it off (and use the regular compiler) for release. If you are writing your own code, it should be fairly easy to make it work with MIRO.

Upvotes: 2

Dimiter Georgiev
Dimiter Georgiev

Reputation: 151

Google's AddressSanitizer is a compiler instrumentation module and runtime library that can check out-of-bound access to heap, stack and globals, among other things. It is available in Clang 3.1+ and in GCC 4.8+.

To use it, pass -fsanitize=address (or -faddress-sanitizer in old Clang 3.1) among the arguments to the compiler and to the linker (links asan; no need for explicit -lasan). To get nicer stack traces in error messages, pass -fno-omit-frame-pointer to the compiler.

It was initially used for Chromium testing, and since 2012, it is used by Firefox devs, too. There is a good blog post on how to get it running with Qt. You may also want to read some more context on Wikipedia.

Upvotes: 15

Demi
Demi

Reputation: 6227

There is a Valgrind tool called SGCheck (formerly known as Ptrcheck) that does check stack array bounds overrun.

valgrind --tool=exp-sgcheck <program> <arguments>

The tool is still labeled experimental and it comes with several limitations. One of them is:

Platforms: the stack/global checks won't work properly on PowerPC, ARM or S390X platforms, only on X86 and AMD64 targets. That's because the stack and global checking requires tracking function calls and exits reliably, and there's no obvious way to do it on ABIs that use a link register for function returns.

Upvotes: 6

Related Questions