GCC Bounds Checking Example

$ cat example.c
main() {
char *malloc(); char *a = malloc(2);
a[2] = 'x';
}
$ ./bgcc -fbounds-checking example.c
$ ./a.out
Bounds Checking GCC v gcc-4.0.4-3.2 Copyright (C) 1995 Richard W.M. Jones
Bounds Checking comes with ABSOLUTELY NO WARRANTY. For details see file
`COPYING' that should have come with the source to this program.
Bounds Checking is free software, and you are welcome to redistribute it
under certain conditions. See the file `COPYING' for details.
For more information, set GCC_BOUNDS_OPTS to `-help'
example.c:3:Bounds error: attempt to reference memory overrunning the end of an object.
example.c:3:  Pointer value: 0x8431002, Size: 1
example.c:3:  Object `malloc':
example.c:3:    Address in memory:    0x8431000 .. 0x8431001
example.c:3:    Size:                 2 bytes
example.c:3:    Element size:         1 bytes
example.c:3:    Number of elements:   2
example.c:3:    Created at:           example.c, line 2
example.c:3:    Storage class:        heap

A Longer GCC Bounds Checking Example

This example shows some additional features:

$ cat example2.c
void test(char *p) { p[1] = 'x'; }	/* access a pointer out of range */

static char static_var[1];	/* example static variable */

main() {
char local_var[1];		/* example stack variable */
char *heap_var, *malloc();
struct { char *a; char *b; } s; /* example structure with pointers */
heap_var = malloc(1);		/* example heap variable */
test(local_var);		/* access a local variable out of range */
test(static_var);		/* access a static variable out of range */
test(heap_var);			/* access a heap variable out of range */
s.a = local_var;
s.b = static_var;
unchecked(&s);			/* pass to a routine in unchecked module */
}
$ cat example2u.c
/* example unchecked module mixed with checked module */
/*   No special preparation is required, even for */
/*   structures containing pointers. */

struct s_tag { char *a; char *b; };

void unchecked(struct s_tag *s) {
memset(s->a, 0, 2);		/* example of catching checked pointers in */
memcpy(s->b, s->a, 2);		/* library functions even from unchecked code */
}
$ gcc -c example2u.c
$ ./bgcc -fbounds-checking example2.c example2u.o
$ GCC_BOUNDS_OPTS="-never-fatal -print-heap" ./a.out
Bounds Checking GCC v gcc-4.0.4-3.2 Copyright (C) 1995 Richard W.M. Jones
Bounds Checking comes with ABSOLUTELY NO WARRANTY. For details see file
`COPYING' that should have come with the source to this program.
Bounds Checking is free software, and you are welcome to redistribute it
under certain conditions. See the file `COPYING' for details.
For more information, set GCC_BOUNDS_OPTS to `-help'
example2.c:1:Bounds error: attempt to reference memory overrunning the end of an object.
example2.c:1:  Pointer value: 0xbff63f6b, Size: 1
example2.c:1:  Object `local_var':
example2.c:1:    Address in memory:    0xbff63f6a .. 0xbff63f6a
example2.c:1:    Size:                 1 bytes
example2.c:1:    Element size:         1 bytes
example2.c:1:    Number of elements:   1
example2.c:1:    Created at:           example2.c, line 6
example2.c:1:    Storage class:        stack
example2.c:1:Bounds error: attempt to reference memory overrunning the end of an object.
example2.c:1:  Pointer value: 0x80691e9, Size: 1
example2.c:1:  Object `static_var':
example2.c:1:    Address in memory:    0x80691e8 .. 0x80691e8
example2.c:1:    Size:                 1 bytes
example2.c:1:    Element size:         1 bytes
example2.c:1:    Number of elements:   1
example2.c:1:    Created at:           example2.c, line 3
example2.c:1:    Storage class:        static
example2.c:1:Bounds error: attempt to reference memory overrunning the end of an object.
example2.c:1:  Pointer value: 0x8f46001, Size: 1
example2.c:1:  Object `malloc':
example2.c:1:    Address in memory:    0x8f46000 .. 0x8f46000
example2.c:1:    Size:                 1 bytes
example2.c:1:    Element size:         1 bytes
example2.c:1:    Number of elements:   1
example2.c:1:    Created at:           example2.c, line 9
example2.c:1:    Storage class:        heap
<unknown>:0:Bounds error: memset with this destination pointer and size 2 would overrun the end of the object's allocated memory.
<unknown>:0:  Pointer value: 0xbff63f6a
<unknown>:0:  Object `local_var':
<unknown>:0:    Address in memory:    0xbff63f6a .. 0xbff63f6a
<unknown>:0:    Size:                 1 bytes
<unknown>:0:    Element size:         1 bytes
<unknown>:0:    Number of elements:   1
<unknown>:0:    Created at:           example2.c, line 6
<unknown>:0:    Storage class:        stack
<unknown>:0:Bounds error: memcpy with this destination pointer and size 2 would overrun the end of the object's allocated memory.
<unknown>:0:  Pointer value: 0x80691e8
<unknown>:0:  Object `static_var':
<unknown>:0:    Address in memory:    0x80691e8 .. 0x80691e8
<unknown>:0:    Size:                 1 bytes
<unknown>:0:    Element size:         1 bytes
<unknown>:0:    Number of elements:   1
<unknown>:0:    Created at:           example2.c, line 3
<unknown>:0:    Storage class:        static
<unknown>:0:Bounds error: memcpy with this source pointer and size 2 would overrun the end of the object's allocated memory.
<unknown>:0:  Pointer value: 0xbff63f6a
<unknown>:0:  Object `local_var':
<unknown>:0:    Address in memory:    0xbff63f6a .. 0xbff63f6a
<unknown>:0:    Size:                 1 bytes
<unknown>:0:    Element size:         1 bytes
<unknown>:0:    Number of elements:   1
<unknown>:0:    Created at:           example2.c, line 6
<unknown>:0:    Storage class:        stack
Bounds library call frequency statistics:
  Calls to push, pop, param function:        1, 1, 0
  Calls to add, delete stack:                2, 2
  Calls to add, delete heap:                 1, 0
  Calls to check pointer +/- integer:        3
  Calls to check array references:           0
  Calls to check pointer differences:        0
  Calls to check object references:          3
  Calls to check component references:       0
  Calls to check truth, falsity of pointers: 0, 0
  Calls to check <, >, <=, >= of pointers:   0
  Calls to check ==, != of pointers:         0
  Calls to check p++, ++p, p--, --p:         0, 0, 0, 0
  Calls to add, find, delete oob pointers:   0, 0, 0
  References to unchecked static, stack:     0, 0
Filename = example2.c, Line = 9, Function = malloc, Count = 1 Avg Size = 1, Total = 1

GCC Bounds Checking Patches

Download the official bounds checking patches for GCC releases from Haj Ten Brugge on sourceforge. Download bounds checking patches for gcc-4.0.4.
Download older patches: gcc-3.4.6 gcc-4.0.2

To build a bounds checking gcc:


  cd /u/gnu				# go to a work area
  tar xzf gcc-x.y.tar.gz		# unpack gcc
  mv gcc-x.y bgcc-x.y			# rename the gcc directory
  cd bgcc-x.y				# go to the bgcc directory
  patch -p1 -T < gcc-x.y-bgcc-x.y.pat	# apply the patches
  touch gcc/c-parse.in			# force a rebuild of .y and .c
  mkdir objdir				# make an object file area
  cd objdir				# enter the area
  /u/gnu/bgcc-x.y/configure		# initialize the build
  make bootstrap			# do the build

You can run the bounds checking gcc from its build area using the script /u/gnu/bgcc-x.y/gcc/bounds/bgcc
For more build information, see the README file. or the files created by the patches in /u/gnu/bgcc-x.y/gcc/bounds/.

These patches add a -fbounds-checking flag that adds bounds checking tests to pointer and array accesses. Richard Jones developed the patches against gcc-2.7 in 1995. Herman ten Brugge is the current maintainer and updates patches to the boundschecking project at sourceforge. William Bader has unofficial updates.

You may freely mix object modules compiled with and without bounds checking. The bounds checker also includes replacements for mem* and str* routines and can detect invalid calls against checked memory objects, even from modules compiled without bounds checking.

These patches are unrelated to the fat pointer bounds checking patches by Greg McGary [email protected] which change the size of pointers and require building modified versions of libc and most other libraries that your program calls. Greg's patches will eventually be incorporated into GCC. If you can use Greg's fat pointer bounds checker, it has the advantage of better run-time performance and support for languages other than C.

Valgrind by Julian Seward is another open-source memory debugger for Intel x86-based Linux systems. Valgrind runs unmodified ELF x86 Linux executables within a Pentium emulator and detects accesses to uninitialized variables, accesses to unallocated memory, and memory leaks. In comparison to bounds checking gcc, valgrind has the advantages of detecting accesses to uninitialized variables, of not requiring recompilation or relinking, and of supporting C++. Valgrind has the disadvantages of working only on x86-based Linux systems and of not detecting out-of-bounds array accesses as long as the accesses still produce valid addresses (so it often misses off-by-one accesses to local arrays). Valgrind has more memory overhead than bounds checking gcc but about the same amount of cpu overhead. I regularly use both bounds checking gcc and valgrind.
Valgrind Home http://valgrind.kde.org/
Valgrind freshmeat project http://freshmeat.net/projects/valgrind/
Valgrind HowTo http://www.tldp.org/HOWTO/Valgrind-HOWTO/


Return to GCC extensions
Last modified 2007-05-12