/c-plus-plus-array-bounds-checker

C++ std::array bounds checking, multidimensional

Primary LanguageC++GNU General Public License v2.0GPL-2.0

Simple C++ 11 std::array and std::vector bounds checking

Do you want to enable bounds checking of std::array and std::vector without the overhead of valgrind?

Do you want to be able to turn checks on and then off for max perf? Of course you do!

This little hack adds set() and get() accessors e.g.:

    std::array< std::array< std::array< int, zdim >, ydim >, xdim > c;
    set(c, 0, 0, 0, 42);
    (void) get(c, 0, 0, 0);

If you want to include a trace of set() and get() calls, enable:

#define DEBUG

To print an assertion on out of bounds (and continue):

#define ENABLE_ASSERT

To call abort() on assertion:

#undef ENABLE_ABORT

Which should drop you into your debugger. If you do not enable this, then the code will continue and likely crash anyway.

To enable in your code

#define DEBUG
#define ENABLE_ASSERT
#define ENABLE_ABORT
#include "array_bounds_check.h"

std::array example

#define ENABLE_ASSERT
#define ENABLE_ABORT
#include "array_bounds_check.h"

int main (void) {
    const auto xdim = 3;
    const auto ydim = 2;
    const auto zdim = 1;

    //
    // One dimensional array
    //
    std::array< int, xdim > a;
    for (auto i = 0; i < xdim; i++) {
        set(a, i, i);
        ASSERT(get(a, i) == i);
    }

    //
    // Two dimensional array
    //
    std::array< std::array< int, ydim >, xdim > b;
    for (auto x = 0; x < xdim; x++) {
        for (auto y = 0; y < ydim; y++) {
            set(b, x, y, x+y);
            ASSERT(get(b, x, y) == x+y);
        }
    }

    //
    // Three dimensional array
    //
    std::array< std::array< std::array< int, zdim >, ydim >, xdim > c;
    for (auto x = 0; x < xdim; x++) {
        for (auto y = 0; y < ydim; y++) {
            for (auto z = 0; z < zdim; z++) {
                set(c, x, y, z, x+y);
                ASSERT(get(c, x, y, z) == x+y+z);
            }
        }
    }
}

std::vector example

#define ENABLE_ASSERT
#define ENABLE_ABORT
#include "vector_bounds_check.h"

int main (void) {
    const auto xdim = 3;
    const auto ydim = 2;
    const auto zdim = 1;

    //
    // One dimensional vector
    //
    std::vector< int > a;
    a.resize(xdim);
    for (auto i = 0; i < xdim; i++) {
	set(a, i, i);
        ASSERT(get(a, i) == i);
    }

    //
    // Two dimensional vector
    //
    std::vector< std::vector< int> > b;
    b.resize(xdim);
    for (auto x = 0; x < b.size(); x++) {
        b[x].resize(ydim);
    }
    for (auto x = 0; x < xdim; x++) {
	for (auto y = 0; y < ydim; y++) {
	    set(b, x, y, x+y);
	    ASSERT(get(b, x, y) == x+y);
	}
    }

    //
    // Three dimensional vector
    //
    std::vector< std::vector< std::vector<int> > > c;
    c.resize(xdim);
    for (auto x = 0; x < b.size(); x++) {
        c[x].resize(ydim);
        for (auto y = 0; y < b[x].size(); y++) {
            c[x][y].resize(zdim);
        }
    }
    for (auto x = 0; x < xdim; x++) {
	for (auto y = 0; y < ydim; y++) {
	    for (auto z = 0; z < zdim; z++) {
		set(c, x, y, z, x+y);
		ASSERT(get(c, x, y, z) == x+y+z);
	    }
	}
    }
}

Sample error

Assert 'X < arr.size()' failed at line 85, file ./array_bounds_check.h, function set()

And in a debugger:

lldb array_bounds_check
(lldb) r
Assert 'X < arr.size()' failed at line 85, file ./array_bounds_check.h, function set()
Process 39381 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    frame #0: 0x00007fff5d422b66 libsystem_kernel.dylib`__pthread_kill + 10
libsystem_kernel.dylib`__pthread_kill:
->  0x7fff5d422b66 <+10>: jae    0x7fff5d422b70            ; <+20>
    0x7fff5d422b68 <+12>: movq   %rax, %rdi
    0x7fff5d422b6b <+15>: jmp    0x7fff5d419ae9            ; cerror_nocancel
    0x7fff5d422b70 <+20>: retq
Target 0: (array_bounds_check) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
  * frame #0: 0x00007fff5d422b66 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00007fff5d5ed080 libsystem_pthread.dylib`pthread_kill + 333
    frame #2: 0x00007fff5d37e1ae libsystem_c.dylib`abort + 127
    frame #3: 0x0000000100002112 array_bounds_check`void set(std::__1::array, 2ul>, 3ul>&, unsigned long, unsigned long, unsigned long, int) [inlined] std::__1::basic_ostream >& std::__1::endl >(__os=) at ostream:1002
    frame #4: 0x00000001000020f4 array_bounds_check`void set(std::__1::array, 2ul>, 3ul>&, unsigned long, unsigned long, unsigned long, int) [inlined] std::__1::basic_ostream >::operator<<(this=)(std::__1::basic_ostream >&)) at ostream:195
    frame #5: 0x00000001000020f4 array_bounds_check`void set(arr=0x00007ffeefbfeac8, X=3, Y=1, Z=0, v=42) at array_bounds_check.h:85
    frame #6: 0x0000000100000f50 array_bounds_check`main at array_bounds_check.cpp:43
    frame #7: 0x00007fff5d2d2015 libdyld.dylib`start + 1

Building

Do

    sh ./RUNME

Or, if that fails, manual build:

    c++ -std=c++11 -Werror -g -ggdb3 -O2 -Wall -Wall -c -o .o/main.o main.cpp
    c++ -std=c++11 -Werror -g -ggdb3 -O2 -Wall -Wall -c -o .o/array_bounds_check.o array_bounds_check.cpp
    c++ -std=c++11 -Werror -g -ggdb3 -O2 -Wall -Wall -c -o .o/vector_bounds_check.o vector_bounds_check.cpp

To test:

    ./bounds_check