diff -rup gcc-2.8.1.org/Makefile.in gcc-2.8.1/Makefile.in
--- gcc-2.8.1.org/Makefile.in	Tue Mar  3 01:54:31 1998
+++ gcc-2.8.1/Makefile.in	Sat Jun 13 12:22:35 1998
@@ -129,8 +129,8 @@ USER_H = $(srcdir)/ginclude/stdarg.h $(s
     $(srcdir)/ginclude/va-m32r.h $(srcdir)/ginclude/va-sh.h \
     $(srcdir)/ginclude/va-v850.h $(srcdir)/ginclude/va-arc.h \
     $(srcdir)/ginclude/iso646.h $(srcdir)/ginclude/va-ppc.h \
-    $(srcdir)/ginclude/proto.h $(EXTRA_HEADERS) \
-    $(LANG_EXTRA_HEADERS)
+    $(srcdir)/ginclude/proto.h $(srcdir)/ginclude/unchecked.h \
+    $(EXTRA_HEADERS) $(LANG_EXTRA_HEADERS)
 
 # Target to use whe installing assert.h.  Some systems may
 # want to set this empty.
@@ -259,6 +259,11 @@ LIBGCC = libgcc.a
 # and the rule for installing it.
 INSTALL_LIBGCC = install-libgcc
 
+# Specify a rule for making the bounds checking library, (RWMJ)
+LIBCHECK = libcheck.a
+# and the rule for installing it.
+INSTALL_LIBCHECK = install-libcheck
+
 # Specify the rule for actually making libgcc1.a.
 # The value may be empty; that means to do absolutely nothing
 # with or for libgcc1.a.
@@ -373,7 +378,7 @@ GCC_PASSES=xgcc cc1 cpp $(EXTRA_PASSES)
 
 # List of things which should already be built whenever we try to use xgcc
 # to link anything.
-GCC_PARTS=$(GCC_PASSES) $(LIBGCC) $(EXTRA_PROGRAMS) $(USE_COLLECT2) $(EXTRA_PARTS)
+GCC_PARTS=$(GCC_PASSES) $(LIBGCC) $(LIBCHECK) $(EXTRA_PROGRAMS) $(USE_COLLECT2) $(EXTRA_PARTS)
 
 # Directory to link to, when using the target `maketest'.
 DIR = ../gcc
@@ -556,7 +561,7 @@ FLAGS_TO_PASS = \
 
 # Language-specific object files for C and Objective C.
 C_AND_OBJC_OBJS = c-lex.o c-pragma.o c-decl.o c-typeck.o c-convert.o \
-  c-aux-info.o c-common.o c-iterate.o @extra_c_objs@
+  c-aux-info.o c-common.o c-iterate.o c-bounds.o @extra_c_objs@
 
 # Language-specific object files for C.
 C_OBJS = c-parse.o c-lang.o $(C_AND_OBJC_OBJS)
@@ -1049,6 +1054,34 @@ libgcc.a: $(LIBGCC1) $(LIBGCC2)
 # so that libgcc.a itself remains nonexistent if compilation is aborted.
 	mv tmplibgcc.a libgcc.a
 
+# Build the bounds checking library for GCC.
+$(LIBCHECK): force
+	if [ -d bounds ]; then true; else mkdir bounds; fi; \
+	if [ -d bounds/lib ]; then true; else mkdir bounds/lib; fi; \
+	thisdir1=`pwd`; \
+	srcdir1=`cd $(srcdir); pwd`; \
+	cd bounds/lib; \
+	$(MAKE) -f $${srcdir1}/bounds/lib/Makefile libcheck.a \
+	  srcdir=$${srcdir1} tooldir=$(tooldir) AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" \
+	  GCC_FOR_TARGET="$${thisdir1}/xgcc -B$${thisdir1}/" \
+	  GCC_CFLAGS="$(GCC_CFLAGS)"
+	-rm -f $(LIBCHECK)
+	ln bounds/lib/libcheck.a . >/dev/null 2>&1 || cp bounds/lib/libcheck.a .
+	-if $(RANLIB_TEST) ; then $(RANLIB) $(LIBCHECK); else true; fi
+
+# This is used by bounds/lib/Makefile if the user runs that directly.
+sublibcheck.a: force
+	thisdir1=`pwd`; \
+	srcdir1=`cd $(srcdir); pwd`; \
+	cd bounds/lib; \
+	$(MAKE) -f $$srcdir1/bounds/lib/Makefile libcheck.a \
+	  srcdir=$$srcdir1 tooldir=$(tooldir) AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" \
+	  GCC_FOR_TARGET="$$thisdir1/xgcc -B$$thisdir1/" \
+	  GCC_CFLAGS="$(GCC_CFLAGS)"
+	-rm -f $(LIBCHECK)
+	ln bounds/lib/libcheck.a . >/dev/null 2>&1 || cp bounds/lib/libcheck.a .
+	-if $(RANLIB_TEST) ; then $(RANLIB) $(LIBCHECK); else true; fi
+
 # Use the genmultilib shell script to generate the information the gcc
 # driver program needs to select the library directory based on the
 # switches.
@@ -2082,6 +2115,14 @@ clean: mostlyclean bytecode.clean lang.c
 # but what better way is there?
 	-rm -f libgcc.a libgcc1.a libgcc1-asm.a libgcc2.a libgcc2.ready
 	-rm -f libgcc1.null
+# Clean up libcheck and bounds/ subdirectory. (RWMJ)
+	-rm -f $(LIBCHECK)
+	if [ -d bounds/lib ]; then \
+	  srcdir1=`cd $(srcdir); pwd`; \
+	  cd bounds/lib; \
+	  $(MAKE) -f $$srcdir1/bounds/lib/Makefile srcdir=$$srcdir1 mostlyclean; \
+	  else true; \
+	fi
 	-rm -f *.dvi
 	-rm -f */*.dvi
 	-if [ -f md.pre-cpp ]; then \
@@ -2151,6 +2192,7 @@ install: $(INSTALL_TARGET) ; @true
 # Install the driver last so that the window when things are
 # broken is small.
 install-normal: install-common $(INSTALL_HEADERS) $(INSTALL_LIBGCC) \
+    $(INSTALL_LIBCHECK) \
     install-man install-info lang.install-normal install-driver
 
 # Do nothing while making gcc with a cross-compiler. The person who
@@ -2300,6 +2342,16 @@ install-libgcc: libgcc.a installdirs
 	  if $(RANLIB_TEST) ; then \
 	    (cd $(libsubdir); $(RANLIB) libgcc.a); else true; fi; \
 	  chmod a-x $(libsubdir)/libgcc.a; \
+	else true; fi
+
+# Install the checking library.
+install-libcheck: libcheck.a installdirs
+	-if [ -f $(LIBCHECK) ]; then \
+	  rm -f $(libsubdir)/libcheck.a; \
+	  $(INSTALL_DATA) $(LIBCHECK) $(libsubdir)/libcheck.a; \
+	  if $(RANLIB_TEST); then \
+	    (cd $(libsubdir); $(RANLIB) libcheck.a); else true; fi; \
+	  chmod a-x $(libsubdir)/libcheck.a; \
 	else true; fi
 
 # Install multiple versions of libgcc.a.
diff -rup gcc-2.8.1.org/c-common.c gcc-2.8.1/c-common.c
--- gcc-2.8.1.org/c-common.c	Thu Feb 19 03:16:13 1998
+++ gcc-2.8.1/c-common.c	Sat Jun 13 12:22:35 1998
@@ -21,6 +21,8 @@ Boston, MA 02111-1307, USA.  */
 #include "config.h"
 #include <stdio.h>
 #include "tree.h"
+#include "rtl.h"
+#include "c-bounds.h"
 #include "c-lex.h"
 #include "c-tree.h"
 #include "flags.h"
@@ -2530,6 +2532,16 @@ truthvalue_conversion (expr)
 	     truthvalue_conversion (build_unary_op (REALPART_EXPR, expr, 0)),
 	     truthvalue_conversion (build_unary_op (IMAGPART_EXPR, expr, 0)),
 	     0));
+
+  /* In bounds checking mode, if we evaluate the truthvalue of a pointer we
+     want to check the pointer is not ILLEGAL or otherwise invalid. We build
+     the necessary code here.	-- RWMJ */
+  if (bounds_checking_enabled)
+    {
+      enum tree_code code = TREE_CODE (TREE_TYPE (expr));
+      if (code == POINTER_TYPE || code == ARRAY_TYPE || code == FUNCTION_TYPE)
+	return bounds_build_truthvalue_conversion (expr);
+    }
 
   return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
 }
diff -rup gcc-2.8.1.org/c-decl.c gcc-2.8.1/c-decl.c
--- gcc-2.8.1.org/c-decl.c	Tue Feb 10 01:49:09 1998
+++ gcc-2.8.1/c-decl.c	Sat Jun 13 12:22:35 1998
@@ -29,10 +29,12 @@ Boston, MA 02111-1307, USA.  */
 #include "config.h"
 #include <stdio.h>
 #include "tree.h"
+#include "rtl.h"
 #include "flags.h"
 #include "output.h"
 #include "c-tree.h"
 #include "c-lex.h"
+#include "c-bounds.h"
 
 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
 enum decl_context
@@ -183,7 +185,7 @@ tree default_function_type;
 /* function types `double (double)' and `double (double, double)', etc.  */
 
 tree double_ftype_double, double_ftype_double_double;
-tree int_ftype_int, long_ftype_long;
+tree int_ftype_int, int_ftype_any, long_ftype_long;
 tree float_ftype_float;
 tree ldouble_ftype_ldouble;
 
@@ -554,6 +556,11 @@ int warn_parentheses;
 
 int warn_missing_braces;
 
+/* Bounds checking is turned off temporarily inside static initializers by
+   c-typeck.c:start_init using the following flag.    (RWMJ) */
+
+int bounds_in_static_decl;
+
 /* Warn if main is suspicious.  */
 
 int warn_main;
@@ -783,6 +790,12 @@ c_decode_option (p)
 	 it off only if it's not explicit.  */
       warn_main = 2;
     }
+  /* Flags to handle bounds checking. (RWMJ). */
+  else if (!strcmp (p, "-fbounds-checking"))
+    {
+      bounds_checking_enabled = 1;
+      flag_no_builtin = 1;		/* So we can check mem* functions too*/
+    }
   else
     return 0;
 
@@ -3126,6 +3139,9 @@ init_decl_processing ()
     = build_function_type (integer_type_node,
 			   tree_cons (NULL_TREE, integer_type_node, endlink));
 
+  int_ftype_any
+    = build_function_type (integer_type_node, NULL_TREE);
+
   long_ftype_long
     = build_function_type (long_integer_type_node,
 			   tree_cons (NULL_TREE,
@@ -3448,6 +3464,255 @@ init_decl_processing ()
 		    NULL_PTR);
 #endif
 
+  if (bounds_checking_enabled) {
+    /* Create a prototype for the functions __bounds_check... (RWMJ) */
+    tree voidptr_ftype_any
+      = build_function_type (ptr_type_node, NULL_TREE);
+    tree int_ftype_any
+      = build_function_type (integer_type_node, NULL_TREE);
+
+    builtin_function ("__bounds_check_ptr_plus_int",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_array_reference",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_component_reference",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_ptr_diff",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_reference",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_ptr_lt_ptr",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_ptr_le_ptr",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_ptr_gt_ptr",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_ptr_ge_ptr",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_ptr_eq_ptr",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_ptr_ne_ptr",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_ptr_postinc",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_ptr_preinc",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_ptr_postdec",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_ptr_predec",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_ptr_true",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_ptr_false",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_note_constructed_object",
+		      void_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_note_constructed_private_table",
+		      void_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_push_function",
+		      void_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_pop_function",
+		      void_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_add_param_object",
+		      void_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_add_stack_object",
+		      void_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_delete_stack_object",
+		      void_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_initialize_library",
+		      void_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_malloc",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_realloc",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_memalign",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_calloc",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_valloc",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_memcpy",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_memmove",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_bcopy",
+		      void_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_memset",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_bzero",
+		      void_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_memcmp",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_bcmp",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strcpy",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strncpy",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strlen",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strcmp",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strncmp",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strcat",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strncat",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strpbrk",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strrchr",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_rindex",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strspn",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strcspn",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strstr",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strtok",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strdup",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strchr",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_index",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strcoll",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strxfrm",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strcasecmp",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_strncasecmp",
+		      int_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_memchr",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+    builtin_function ("__bounds_check_memccpy",
+		      voidptr_ftype_any,
+		      NOT_BUILT_IN,
+		      NULL_PTR);
+  }
+
   pedantic_lvalues = pedantic;
 
   /* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__.  */
@@ -3724,6 +3989,15 @@ start_decl (declarator, declspecs, initi
       DECL_INITIAL (decl) = error_mark_node;
     }
 
+  /* In bounds checking mode, we will always have an initializer for local
+     variable declarations. So set DECL_INITIAL to indicate this to `pushdecl'.
+     (RWMJ, 29/1/95) */
+  if (bounds_checking_enabled
+      && current_binding_level != global_binding_level
+      && TREE_CODE (decl) == VAR_DECL
+      && !DECL_EXTERNAL (decl))
+    DECL_INITIAL (decl) = error_mark_node;
+
   /* If this is a function declaration, write a record describing it to the
      prototypes file (if requested).  */
 
@@ -3922,6 +4196,16 @@ finish_decl (decl, init, asmspec_tree)
 	DECL_RTL (decl) = 0;
       }
 
+
+  /* In bounds checking mode, if this is a local variable declaration, then
+     we create or alter the initializer so that it has the side effect of
+     calling __bounds_add_stack_object. */
+  if (bounds_checking_enabled
+      && current_binding_level != global_binding_level
+      && TREE_CODE (decl) == VAR_DECL
+      && !DECL_EXTERNAL (decl))
+    bounds_frig_decl_initial (decl);
+
   /* Output the assembler code and/or RTL code for variables and functions,
      unless the type is an undefined structure or union.
      If not, it will get done when the type is completed.  */
@@ -3965,6 +4249,12 @@ finish_decl (decl, init, asmspec_tree)
 	  /* Compute and store the initial value.  */
 	  if (TREE_CODE (decl) != FUNCTION_DECL)
 	    expand_decl_init (decl);
+	  /* If bounds checking, compute and store a clean-up for it. */
+	  if (bounds_checking_enabled
+	      && TREE_CODE (decl) != FUNCTION_DECL
+	      && !DECL_EXTERNAL (decl)
+	      && !TREE_STATIC (decl))
+	    bounds_expand_decl_cleanup (decl);
 	}
     }
 
@@ -6886,6 +7176,11 @@ store_parm_decls ()
       && strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main") == 0
       && DECL_CONTEXT (fndecl) == NULL_TREE)
     expand_main_function ();
+
+  /* In bounds checking mode, emit various function calls here so we can
+     find the function's arguments. */
+  if (bounds_checking_enabled)
+    bounds_build_args ();
 }
 
 /* SPECPARMS is an identifier list--a chain of TREE_LIST nodes
@@ -7049,6 +7344,15 @@ finish_function (nested)
 {
   register tree fndecl = current_function_decl;
 
+  /* In bounds checking mode, we may have introduced an extra binding
+     contour in `bounds_build_args'. We pop it here. */
+  if (bounds_checking_enabled)
+    {
+      expand_end_bindings (getdecls (), 1, 0);
+      poplevel (1, 0, 0);
+      pop_momentary ();
+    }
+
 /*  TREE_READONLY (fndecl) = 1;
     This caused &foo to be of type ptr-to-const-function
     which then got a warning when stored in a ptr-to-function variable.  */
@@ -7092,6 +7396,18 @@ finish_function (nested)
 
   /* Generate rtl for function exit.  */
   expand_function_end (input_filename, lineno, 0);
+
+  /* We now have the complete rtl for the function. In bounds checking mode,
+     we want to delete redundant calls to:
+    	__bounds_push_function
+    	__bounds_pop_function
+    	__bounds_add_param_object
+    	__bounds_add_stack_object
+    	__bounds_delete_stack_object
+     if it turns out that these are unnecessary in this function. Do that
+     now.					(RWMJ) */
+  if (bounds_checking_enabled)
+    bounds_delete_redundant_calls (fndecl);
 
   /* So we can tell if jump_optimize sets it to 1.  */
   can_reach_end = 0;
diff -rup gcc-2.8.1.org/c-lang.c gcc-2.8.1/c-lang.c
--- gcc-2.8.1.org/c-lang.c	Sat Oct 18 14:42:55 1997
+++ gcc-2.8.1/c-lang.c	Sat Jun 13 12:22:35 1998
@@ -24,6 +24,9 @@ Boston, MA 02111-1307, USA.  */
 #include <stdio.h>
 #include "input.h"
 
+#include "rtl.h"
+#include "c-bounds.h"
+
 /* Each of the functions defined here
    is an alternative to a function in objc-actions.c.  */
    
@@ -139,6 +142,11 @@ finish_file ()
   extern tree static_ctors, static_dtors;
   extern tree build_function_call                 PROTO((tree, tree));
   tree void_list_node = build_tree_list (NULL_TREE, void_type_node);
+
+  /* Build bounds-checking constructors for this file. (RWMJ)*/
+  if (bounds_checking_enabled)
+    bounds_build_static_constructors ();
+
 #ifndef ASM_OUTPUT_CONSTRUCTOR
   if (static_ctors)
     {
diff -rup gcc-2.8.1.org/c-parse.in gcc-2.8.1/c-parse.in
--- gcc-2.8.1.org/c-parse.in	Sun Feb 15 00:58:10 1998
+++ gcc-2.8.1/c-parse.in	Sat Jun 13 12:22:35 1998
@@ -70,6 +70,9 @@ end ifc
 #include "c-tree.h"
 #include "flags.h"
 
+extern int bounds_checking_enabled, bounds_in_static_decl;
+tree bounds_build_component_indirect_ref PROTO((tree, tree));
+
 #ifdef MULTIBYTE_CHARS
 #include <stdlib.h>
 #include <locale.h>
@@ -854,19 +857,27 @@ end ifobjc
 		}
 	| primary POINTSAT identifier
 		{
-                  tree expr = build_indirect_ref ($1, "->");
+		  if (bounds_checking_enabled &&
+		      !bounds_in_static_decl)
+		    {
+		      $$ = bounds_build_component_indirect_ref ($1, $3);
+		    }
+		  else
+		    {
+		      tree expr = build_indirect_ref ($1, "->");
 
 ifobjc
-                  if (doing_objc_thang)
-                    {
-		      if (is_public (expr, $3))
-			$$ = build_component_ref (expr, $3);
+                      if (doing_objc_thang)
+			{
+			  if (is_public (expr, $3))
+			    $$ = build_component_ref (expr, $3);
+			  else
+			    $$ = error_mark_node;
+			}
 		      else
-			$$ = error_mark_node;
-		    }
-                  else
 end ifobjc
-                    $$ = build_component_ref (expr, $3);
+                        $$ = build_component_ref (expr, $3);
+		    }
 		}
 	| primary PLUSPLUS
 		{ $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); }
diff -rup gcc-2.8.1.org/c-parse.y gcc-2.8.1/c-parse.y
--- gcc-2.8.1.org/c-parse.y	Sun Mar  1 10:38:52 1998
+++ gcc-2.8.1/c-parse.y	Sat Jun 13 12:22:35 1998
@@ -66,6 +66,9 @@ State 434 contains 2 shift/reduce confli
 #include "c-tree.h"
 #include "flags.h"
 
+extern int bounds_checking_enabled, bounds_in_static_decl;
+tree bounds_build_component_indirect_ref PROTO((tree, tree));
+
 #ifdef MULTIBYTE_CHARS
 #include <stdlib.h>
 #include <locale.h>
@@ -730,9 +733,17 @@ primary:
 		}
 	| primary POINTSAT identifier
 		{
-                  tree expr = build_indirect_ref ($1, "->");
+		  if (bounds_checking_enabled &&
+		      !bounds_in_static_decl)
+		    {
+		      $$ = bounds_build_component_indirect_ref ($1, $3);
+		    }
+		  else
+		    {
+		      tree expr = build_indirect_ref ($1, "->");
 
-                    $$ = build_component_ref (expr, $3);
+                        $$ = build_component_ref (expr, $3);
+		    }
 		}
 	| primary PLUSPLUS
 		{ $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); }
diff -rup gcc-2.8.1.org/c-tree.h gcc-2.8.1/c-tree.h
--- gcc-2.8.1.org/c-tree.h	Fri Aug  8 21:09:02 1997
+++ gcc-2.8.1/c-tree.h	Sat Jun 13 12:22:35 1998
@@ -504,4 +504,8 @@ extern int system_header_p;
 
 extern int doing_objc_thang;
 
+/* Flag for bounds checking. (RWMJ). */
+
+extern int bounds_checking_enabled;
+
 #endif /* not _C_TREE_H */
diff -rup gcc-2.8.1.org/c-typeck.c gcc-2.8.1/c-typeck.c
--- gcc-2.8.1.org/c-typeck.c	Mon Feb  2 21:33:11 1998
+++ gcc-2.8.1/c-typeck.c	Sat Jun 13 12:22:35 1998
@@ -31,7 +31,9 @@ Boston, MA 02111-1307, USA.  */
 #include "config.h"
 #include <stdio.h>
 #include "tree.h"
+#include "rtl.h"
 #include "c-tree.h"
+#include "c-bounds.h"
 #include "flags.h"
 #include "output.h"
 
@@ -51,6 +53,9 @@ Boston, MA 02111-1307, USA.  */
    message within this initializer.  */
 static int missing_braces_mentioned;
 
+/* Nonzero in bounds checking mode when a bit field is tested */
+int bounds_disable_field_check = 0;
+
 #ifdef NEED_DECLARATION_INDEX
 extern char *index ();
 #endif
@@ -1330,7 +1335,14 @@ build_component_ref (datum, component)
 
 /* Given an expression PTR for a pointer, return an expression
    for the value pointed to.
-   ERRORSTRING is the name of the operator to appear in error messages.  */
+   ERRORSTRING is the name of the operator to appear in error messages.
+
+   For bounds checked code, we generate a call to:
+     void*  __bounds_check_reference (void *pointer, size_t size,
+                                      char *filename, int line);
+   This function checks that the reference will be successful (else
+   aborts with an error message). We then make the reference ourselves
+   as usual.  */
 
 tree
 build_indirect_ref (ptr, errorstring)
@@ -1349,30 +1361,41 @@ build_indirect_ref (ptr, errorstring)
 	return TREE_OPERAND (pointer, 0);
       else
 	{
-	  tree t = TREE_TYPE (type);
-	  register tree ref = build1 (INDIRECT_REF,
-				      TYPE_MAIN_VARIANT (t), pointer);
+          tree ref;
+          tree t = TREE_TYPE (type);	/* type pointed to */
 
-	  if (TYPE_SIZE (t) == 0 && TREE_CODE (t) != ARRAY_TYPE)
+          /* Look for expressions of the form &x and return x */
+          if (TREE_CODE (pointer) == ADDR_EXPR
+	      && !flag_volatile
+	      && (TREE_TYPE (TREE_OPERAND (pointer, 0))
+	          == TREE_TYPE (type)))
+	    return TREE_OPERAND (pointer, 0);
+          else if (bounds_checking_enabled
+	           && !bounds_in_static_decl)
+	    ref = bounds_build_reference (ptr);
+          else
+	    ref = build1 (INDIRECT_REF, TYPE_MAIN_VARIANT (t), pointer);
+
+          if (TYPE_SIZE (t) == 0 && TREE_CODE (t) != ARRAY_TYPE)
 	    {
 	      error ("dereferencing pointer to incomplete type");
 	      return error_mark_node;
 	    }
-	  if (TREE_CODE (t) == VOID_TYPE && skip_evaluation == 0)
+          if (TREE_CODE (t) == VOID_TYPE && skip_evaluation == 0)
 	    warning ("dereferencing `void *' pointer");
 
-	  /* We *must* set TREE_READONLY when dereferencing a pointer to const,
+          /* We *must* set TREE_READONLY when dereferencing a pointer to const,
 	     so that we get the proper error message if the result is used
 	     to assign to.  Also, &* is supposed to be a no-op.
 	     And ANSI C seems to specify that the type of the result
 	     should be the const type.  */
-	  /* A de-reference of a pointer to const is not a const.  It is valid
+          /* A de-reference of a pointer to const is not a const.  It is valid
 	     to change it via some other pointer.  */
-	  TREE_READONLY (ref) = TYPE_READONLY (t);
-	  TREE_SIDE_EFFECTS (ref)
+          TREE_READONLY (ref) = TYPE_READONLY (t);
+          TREE_SIDE_EFFECTS (ref)
 	    = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer) || flag_volatile;
-	  TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
-	  return ref;
+          TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
+          return ref;
 	}
     }
   else if (TREE_CODE (pointer) != ERROR_MARK)
@@ -1387,7 +1410,14 @@ build_indirect_ref (ptr, errorstring)
    If A is a variable or a member, we generate a primitive ARRAY_REF.
    This avoids forcing the array out of registers, and can work on
    arrays that are not lvalues (for example, members of structures returned
-   by functions).  */
+   by functions).
+
+   In bounds checked mode, we generate a call to the function:
+     __bounds_check_array_reference
+   which checks the offset. It returns the address of the object which we
+   then directly reference. (RWMJ).
+   In some cases, generates `ptr_plus_int, ref' even in the case
+   &p[i] where the ref is unnecessary. */
 
 tree
 build_array_ref (array, index)
@@ -1468,8 +1498,26 @@ build_array_ref (array, index)
 	    pedwarn ("ANSI C forbids subscripting non-lvalue array");
 	}
 
-      type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
-      rval = build (ARRAY_REF, type, array, index);
+      if (bounds_checking_enabled)
+	{
+	  /* In bounds checking modes, generate a call to __bounds_check_
+	     array_reference and an indirect ref. to that. */
+	  if (bounds_in_static_decl)
+	    {
+	      if (!bounds_can_test_array_reference_now (array, index))
+		warning ("cannot check this array reference");
+	      type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
+	      rval = build (ARRAY_REF, type, array, index);
+	    }
+	  else
+	    rval = bounds_build_array_reference (array, index);
+	}
+      else
+	{
+	  type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
+	  rval = build (ARRAY_REF, type, array, index);
+	}
+
       /* Array ref is const/volatile if the array elements are
          or if the array is.  */
       TREE_READONLY (rval)
@@ -1541,6 +1589,9 @@ build_function_call (function, params)
   register tree coerced_params;
   tree name = NULL_TREE, assembler_name = NULL_TREE;
 
+  if (bounds_checking_enabled)
+    bounds_convert_funcname(&function, &params);
+
   /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue.  */
   STRIP_TYPE_NOPS (function);
 
@@ -1987,6 +2038,10 @@ build_binary_op (code, orig_op0, orig_op
   /* Nonzero means set RESULT_TYPE to the common type of the args.  */
   int common = 0;
 
+  /* Nonzero means we may build bounds checking code for a comparison
+     operation (<, >, <=, >=, ==, !=) here. */
+  int bounds_checked_comparison = 0;
+
   if (convert_p)
     {
       op0 = default_conversion (orig_op0);
@@ -2269,24 +2324,30 @@ build_binary_op (code, orig_op0, orig_op
 
 	  if (result_type == NULL_TREE)
 	    result_type = ptr_type_node;
+
+	  bounds_checked_comparison = 1;
 	}
       else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
-	       && integer_zerop (op1))
+	       && integer_zerop (op1)) {
 	result_type = type0;
-      else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
-	       && integer_zerop (op0))
+	bounds_checked_comparison = 1;
+      } else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
+		 && integer_zerop (op0)) {
 	result_type = type1;
-      else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+	bounds_checked_comparison = 1;
+      } else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
 	{
 	  result_type = type0;
 	  if (! flag_traditional)
 	    pedwarn ("comparison between pointer and integer");
+	  bounds_checked_comparison = 1;
 	}
       else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
 	{
 	  result_type = type1;
 	  if (! flag_traditional)
 	    pedwarn ("comparison between pointer and integer");
+	  bounds_checked_comparison = 1;
 	}
       break;
 
@@ -2337,6 +2398,7 @@ build_binary_op (code, orig_op0, orig_op
 	      result_type = ptr_type_node;
 	      pedwarn ("comparison of distinct pointer types lacks a cast");
 	    }
+	  bounds_checked_comparison = 1;
 	}
       else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
 	       && integer_zerop (op1))
@@ -2344,6 +2406,7 @@ build_binary_op (code, orig_op0, orig_op
 	  result_type = type0;
 	  if (pedantic || extra_warnings)
 	    pedwarn ("ordered comparison of pointer with integer zero");
+	  bounds_checked_comparison = 1;
 	}
       else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
 	       && integer_zerop (op0))
@@ -2351,18 +2414,21 @@ build_binary_op (code, orig_op0, orig_op
 	  result_type = type1;
 	  if (pedantic)
 	    pedwarn ("ordered comparison of pointer with integer zero");
+	  bounds_checked_comparison = 1;
 	}
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
 	{
 	  result_type = type0;
 	  if (! flag_traditional)
 	    pedwarn ("comparison between pointer and integer");
+	  bounds_checked_comparison = 1;
 	}
       else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
 	{
 	  result_type = type1;
 	  if (! flag_traditional)
 	    pedwarn ("comparison between pointer and integer");
+	  bounds_checked_comparison = 1;
 	}
       break;
       
@@ -2643,10 +2709,17 @@ build_binary_op (code, orig_op0, orig_op
   if (build_type == NULL_TREE)
     build_type = result_type;
 
+  /* Build the final expression here. */
   {
-    register tree result = build (resultcode, build_type, op0, op1);
+    register tree result;
     register tree folded;
 
+    if (!bounds_checking_enabled
+	|| bounds_in_static_decl
+	|| !bounds_checked_comparison)
+      result = build (resultcode, build_type, op0, op1);
+    else
+      result = bounds_build_comparison (resultcode, build_type, op0, op1);
     folded = fold (result);
     if (folded == result)
       TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
@@ -2657,7 +2730,9 @@ build_binary_op (code, orig_op0, orig_op
 }
 
 /* Return a tree for the sum or difference (RESULTCODE says which)
-   of pointer PTROP and integer INTOP.  */
+   of pointer PTROP and integer INTOP.
+   (RWMJ): If bounds-checking is switched on, generate a call to
+   __bounds_check_ptr_plus_int to check the operation. */
 
 static tree
 pointer_int_sum (resultcode, ptrop, intop)
@@ -2688,6 +2763,17 @@ pointer_int_sum (resultcode, ptrop, into
   else
     size_exp = c_size_in_bytes (TREE_TYPE (result_type));
 
+  /* For bounds checked code, we have all the information necessary to
+     generate the function call here. We generate the call
+     __bounds_check_ptr_plus_int (void *pointer, int offset, size_t size,
+    				  int is_plus, char *filename, int line);
+     where pointer is the pointer value, offset is the int operand, size
+     is the size_exp, is_plus is resultcode == PLUS_EXPR, etc. */
+  if (bounds_checking_enabled
+      && !bounds_in_static_decl) {
+    return bounds_build_ptr_plus_int (resultcode, ptrop, intop, size_exp);
+  }
+
   /* If what we are about to multiply by the size of the elements
      contains a constant term, apply distributive law
      and multiply that constant term separately.
@@ -2765,6 +2851,13 @@ pointer_diff (op0, op1)
 	pedwarn ("pointer to a function used in subtraction");
     }
 
+  if (bounds_checking_enabled && !bounds_in_static_decl) {
+    /* Build a call to the following function here instead:	(RWMJ)
+      	   int	__bounds_check_ptr_diff (void *ptr1, void *ptr2, size_t size,
+      					 char *filename, int line); */
+    return bounds_build_ptr_diff (op0, op1, target_type);
+  }
+
   /* First do the subtraction as integers;
      then drop through to build the divide operator.
      Do not do default conversions on the minus operator
@@ -2873,8 +2966,20 @@ build_unary_op (code, xarg, noconvert)
 	  errstring = "wrong type argument to unary exclamation mark";
 	  break;
 	}
-      arg = truthvalue_conversion (arg);
-      return invert_truthvalue (arg);
+      /* In bounds checking mode, if we are inverting a pointer (ie. `!ptr')
+         we want to check that the pointer is not ILLEGAL and not pointing
+         to invalid memory. -- RWMJ. */
+      if (bounds_checking_enabled
+	  && (typecode == POINTER_TYPE || typecode == ARRAY_TYPE
+	      || typecode == FUNCTION_TYPE))
+	{
+	  return bounds_build_invert_truthvalue (arg);
+	}
+      else
+	{
+	  arg = truthvalue_conversion (arg);
+	  return invert_truthvalue (arg);
+	}
 
     case NOP_EXPR:
       break;
@@ -3022,7 +3127,18 @@ build_unary_op (code, xarg, noconvert)
 			      || code == POSTINCREMENT_EXPR)
 			     ? "increment" : "decrement"));
 
-	val = build (code, TREE_TYPE (arg), arg, inc);
+	/* If bounds checking, generate a function call to ensure the inc/dec-
+	   rement will be correct. (RWMJ) */
+	if (bounds_checking_enabled && !bounds_in_static_decl
+	    && typecode == POINTER_TYPE)
+	  {
+	    val = bounds_build_inc_or_dec (code, TREE_TYPE (arg), arg, inc);
+	  }
+	else
+	  {
+	    val = build (code, TREE_TYPE (arg), arg, inc);
+	  }
+
 	TREE_SIDE_EFFECTS (val) = 1;
 	val = convert (result_type, val);
 	if (TREE_CODE (val) != code)
@@ -3034,22 +3150,38 @@ build_unary_op (code, xarg, noconvert)
       /* Note that this operation never does default_conversion
 	 regardless of NOCONVERT.  */
 
-      /* Let &* cancel out to simplify resulting code.  */
-      if (TREE_CODE (arg) == INDIRECT_REF)
+      if (!(bounds_checking_enabled && !bounds_in_static_decl))
 	{
-	  /* Don't let this be an lvalue.  */
-	  if (lvalue_p (TREE_OPERAND (arg, 0)))
-	    return non_lvalue (TREE_OPERAND (arg, 0));
-	  return TREE_OPERAND (arg, 0);
-	}
+	  /* Let &* cancel out to simplify resulting code.  */
+	  if (TREE_CODE (arg) == INDIRECT_REF)
+	    {
+	      /* Don't let this be an lvalue.  */
+	      if (lvalue_p (TREE_OPERAND (arg, 0)))
+		return non_lvalue (TREE_OPERAND (arg, 0));
+	      return TREE_OPERAND (arg, 0);
+	    }
 
-      /* For &x[y], return x+y */
-      if (TREE_CODE (arg) == ARRAY_REF)
+	  /* For &x[y], return x+y */
+	  if (TREE_CODE (arg) == ARRAY_REF)
+	    {
+	      if (mark_addressable (TREE_OPERAND (arg, 0)) == 0)
+		return error_mark_node;
+	      return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
+				      TREE_OPERAND (arg, 1), 1);
+	    }
+	}
+      else
 	{
-	  if (mark_addressable (TREE_OPERAND (arg, 0)) == 0)
-	    return error_mark_node;
-	  return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
-				  TREE_OPERAND (arg, 1), 1);
+	  /* In bounds checking code, the patterns for '&*' and '&x[y]' are
+	     more complicated because we have already expanded the '*' or the
+	     'x[y]' expression. We sort this out in 'c-bounds.c' (RWMJ). */
+	  if (noconvert == 0)
+	    {
+	      tree cancelled_expr = bounds_cancel_address_expr (arg);
+
+	      if (cancelled_expr != NULL_TREE)
+	        return cancelled_expr;
+	    }
 	}
 
       /* Handle complex lvalues (when permitted)
@@ -3116,7 +3248,8 @@ build_unary_op (code, xarg, noconvert)
 
 	    addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
 
-	    if (DECL_C_BIT_FIELD (field))
+	    if (bounds_disable_field_check ? DECL_BIT_FIELD (field)
+					   : DECL_C_BIT_FIELD (field))
 	      {
 		error ("attempt to take address of bit-field structure member `%s'",
 		       IDENTIFIER_POINTER (DECL_NAME (field)));
@@ -3349,7 +3482,8 @@ mark_addressable (exp)
     switch (TREE_CODE (x))
       {
       case COMPONENT_REF:
-	if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
+	if (bounds_disable_field_check ? DECL_BIT_FIELD (TREE_OPERAND (x, 1))
+ 				       : DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
 	  {
 	    error ("cannot take address of bitfield `%s'",
 		   IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (x, 1))));
@@ -5199,6 +5333,10 @@ start_init (decl, asmspec_tree, top_leve
     = (struct initializer_stack *) xmalloc (sizeof (struct initializer_stack));
   char *asmspec = 0;
 
+  /* In a static initializer, temporarily turn off bounds checking. */
+  if (bounds_checking_enabled && decl != 0)
+    bounds_in_static_decl = TREE_STATIC (decl);
+
   if (asmspec_tree)
     asmspec = TREE_STRING_POINTER (asmspec_tree);
 
@@ -5218,7 +5356,7 @@ start_init (decl, asmspec_tree, top_leve
   initializer_stack = p;
 
   constructor_decl = decl;
-  constructor_incremental = top_level;
+  constructor_incremental = top_level && !bounds_checking_enabled; /* RWMJ */
   constructor_asmspec = asmspec;
   constructor_subconstants_deferred = 0;
   constructor_top_level = top_level;
@@ -5235,7 +5373,8 @@ start_init (decl, asmspec_tree, top_leve
 	       || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
 	       || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE));
       locus = IDENTIFIER_POINTER (DECL_NAME (decl));
-      constructor_incremental |= TREE_STATIC (decl);
+      constructor_incremental |= TREE_STATIC (decl)
+	&& !bounds_checking_enabled; /* RWMJ */
     }
   else
     {
@@ -5290,6 +5429,11 @@ finish_init ()
   constructor_top_level = p->top_level;
   initializer_stack = p->next;
   free (p);
+
+  /* If bounds checking was temporarily suspended in a static decl, turn it
+     back on. */
+  if (bounds_checking_enabled)
+    bounds_in_static_decl = 0;
 }
 
 /* Call here when we see the initializer is surrounded by braces.
diff -rup gcc-2.8.1.org/calls.c gcc-2.8.1/calls.c
--- gcc-2.8.1.org/calls.c	Wed Feb 11 13:53:57 1998
+++ gcc-2.8.1/calls.c	Sat Jun 13 12:22:35 1998
@@ -32,6 +32,8 @@ Boston, MA 02111-1307, USA.  */
 #endif
 #include "insn-flags.h"
 
+#include "c-bounds.h"
+
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
 
@@ -127,7 +129,7 @@ static int calls_function	PROTO((tree, i
 static int calls_function_1	PROTO((tree, int));
 static void emit_call_1		PROTO((rtx, tree, tree, HOST_WIDE_INT,
 				       HOST_WIDE_INT, rtx, rtx,
-				       int, rtx, int));
+				       int, rtx, int, int));
 static void store_one_arg	PROTO ((struct arg_data *, rtx, int, int,
 					tree, int));
 
@@ -344,7 +346,7 @@ prepare_call_address (funexp, fndecl, ca
 static void
 emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size, 
              next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
-	     is_const)
+	     is_const, is_bounds_libcall)
      rtx funexp;
      tree fndecl;
      tree funtype;
@@ -355,6 +357,7 @@ emit_call_1 (funexp, fndecl, funtype, st
      int old_inhibit_defer_pop;
      rtx call_fusage;
      int is_const;
+     int is_bounds_libcall;
 {
   rtx stack_size_rtx = GEN_INT (stack_size);
   rtx struct_value_size_rtx = GEN_INT (struct_value_size);
@@ -464,7 +467,8 @@ emit_call_1 (funexp, fndecl, funtype, st
 
   if (stack_size != 0)
     {
-      if (flag_defer_pop && inhibit_defer_pop == 0 && !is_const)
+      if (flag_defer_pop && inhibit_defer_pop == 0 &&
+	  !is_const && !is_bounds_libcall)
 	pending_stack_adjust += stack_size;
       else
 	adjust_stack (stack_size_rtx);
@@ -576,6 +580,13 @@ expand_call (exp, target, ignore)
   int is_const = 0;
   /* Nonzero if this is a call to a `volatile' function.  */
   int is_volatile = 0;
+
+  /* Nonzero if this is a call to '__bounds_add_param_object', '__bounds_add_
+     stack_object', '__bounds_delete_stack_object', '__bounds_push_function'
+     or '__bounds_pop_function' and we are in bounds checking mode. In that
+     case, we may delete the call later in `bounds_delete_redundant_calls'. */
+  int is_bounds_libcall = 0;
+
 #if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
   /* Define the boundary of the register parm stack space that needs to be
      save, if any.  */
@@ -811,15 +822,21 @@ expand_call (exp, target, ignore)
       mark_addressable (fndecl);
     }
 
-  /* When calling a const function, we must pop the stack args right away,
-     so that the pop is deleted or moved with the call.  */
-  if (is_const)
-    NO_DEFER_POP;
+  if (fndecl && DECL_NAME (fndecl))
+    name = IDENTIFIER_POINTER (DECL_NAME (fndecl));
 
   function_call_count++;
 
-  if (fndecl && DECL_NAME (fndecl))
-    name = IDENTIFIER_POINTER (DECL_NAME (fndecl));
+  /* If this is a call to the bounds checking library, we may delete it
+     later. Make this clear here. */
+  if (bounds_checking_enabled &&
+      bounds_is_deletable_fn_p (name))
+    is_bounds_libcall = 1;
+
+  /* When calling a const function, we must pop the stack args right away,
+     so that the pop is deleted or moved with the call.  */
+  if (is_const || is_bounds_libcall)
+    NO_DEFER_POP;
 
 #if 0
   /* Unless it's a call to a specific function that isn't alloca,
@@ -1372,7 +1389,7 @@ expand_call (exp, target, ignore)
 
   /* Now we are about to start emitting insns that can be deleted
      if a libcall is deleted.  */
-  if (is_const)
+  if (is_const || is_bounds_libcall)
     start_sequence ();
 
   /* If we have no actual push instructions, or shouldn't use them,
@@ -1938,7 +1955,8 @@ expand_call (exp, target, ignore)
   /* Generate the actual call instruction.  */
   emit_call_1 (funexp, fndecl, funtype, args_size.constant, struct_value_size,
 	       FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
-	       valreg, old_inhibit_defer_pop, call_fusage, is_const);
+	       valreg, old_inhibit_defer_pop, call_fusage, is_const,
+	       is_bounds_libcall);
 
   /* If call is cse'able, make appropriate pair of reg-notes around it.
      Test valreg so we don't crash; may safely ignore `const'
@@ -1968,6 +1986,22 @@ expand_call (exp, target, ignore)
 
       valreg = temp;
     }
+  else if (is_bounds_libcall)
+    {
+      /* In bounds checking mode, if this is one of the calls we may delete
+         later, then mark this list of insns in our private list so that
+         we may delete them later.		(RWMJ) */
+      rtx insns = get_insns ();
+      rtx first_in_call, last_in_call;
+
+      first_in_call = insns;
+      last_in_call = get_last_insn ();
+      end_sequence ();
+      emit_insns (insns);
+
+      bounds_note_call_for_deletion (first_in_call, last_in_call,
+				     name, exp);
+    }
   else if (is_const)
     {
       /* Otherwise, just write out the sequence without a note.  */
@@ -2705,7 +2739,7 @@ emit_library_call VPROTO((rtx orgfun, in
                args_size.constant, 0,
 	       FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
 	       outmode != VOIDmode ? hard_libcall_value (outmode) : NULL_RTX,
-	       old_inhibit_defer_pop + 1, call_fusage, no_queue);
+	       old_inhibit_defer_pop + 1, call_fusage, no_queue, 0);
 
   pop_temp_slots ();
 
@@ -3282,7 +3316,7 @@ emit_library_call_value VPROTO((rtx orgf
                args_size.constant, struct_value_size,
 	       FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
 	       mem_value == 0 ? hard_libcall_value (outmode) : NULL_RTX,
-	       old_inhibit_defer_pop + 1, call_fusage, is_const);
+	       old_inhibit_defer_pop + 1, call_fusage, is_const, 0);
 
   /* Now restore inhibit_defer_pop to its actual original value.  */
   OK_DEFER_POP;
diff -rup gcc-2.8.1.org/cp/Makefile.in gcc-2.8.1/cp/Makefile.in
--- gcc-2.8.1.org/cp/Makefile.in	Sat Feb 14 23:24:07 1998
+++ gcc-2.8.1/cp/Makefile.in	Sat Jun 13 12:22:35 1998
@@ -166,7 +166,7 @@ INCLUDES = -I. -I.. -I$(srcdir) -I$(srcd
 
 CXX_OBJS = call.o decl.o errfn.o expr.o pt.o sig.o typeck2.o \
  class.o decl2.o error.o lex.o parse.o ptree.o rtti.o spew.o typeck.o cvt.o \
- except.o friend.o init.o method.o search.o tree.o xref.o repo.o
+ except.o friend.o init.o method.o search.o tree.o xref.o repo.o bounds.o
 
 # Language-independent object files.
 OBJS = `cat ../stamp-objlist` ../c-common.o ../c-pragma.o
diff -rup gcc-2.8.1.org/extend.texi gcc-2.8.1/extend.texi
--- gcc-2.8.1.org/extend.texi	Tue Feb 17 18:46:18 1998
+++ gcc-2.8.1/extend.texi	Sat Jun 13 12:30:54 1998
@@ -62,6 +62,8 @@ C++ Language}, for extensions that apply
 * Incomplete Enums::    @code{enum foo;}, with details to follow.
 * Function Names::	Printable strings which are the name of the current
 			 function.
+* Bounds Checking::     Add full, fine-grained array & pointer checking to
+                         C programs.
 * Return Address::      Getting the return or frame address of a function.
 @end menu
 @end ifset
@@ -108,6 +110,8 @@ C++ Language}, for extensions that apply
 * Incomplete Enums::    @code{enum foo;}, with details to follow.
 * Function Names::	Printable strings which are the name of the current
 			 function.
+* Bounds Checking::     Add full, fine-grained array & pointer checking to
+                         C programs.
 * Return Address::      Getting the return or frame address of a function.
 @end menu
 @end ifclear
@@ -2836,6 +2840,667 @@ These names are not macros: they are pre
 For example, @samp{#ifdef __FUNCTION__} does not have any special
 meaning inside a function, since the preprocessor does not do anything
 special with the identifier @code{__FUNCTION__}.
+
+@node Bounds Checking
+@section Bounds Checking
+@cindex Bounds Checking
+
+The C part of the GNU compiler now supports full fine-grained pointer checking
+at runtime. This work was originally done by @w{Richard W.M. Jones}
+`rjones@@orchestream.com',
+and has been extended by the work of many other kind
+contributors.@footnote{See the file @file{bounds/CONTRIBUTORS} for a full
+list of the people who gave their effort for free to make all this possible.}
+
+The runtime checking library, test kit and various tools can be found in
+the @file{bounds/} subdirectory.
+
+The brief manual here is a distillation of the original paper that appeared
+at the same time as the original patches to GCC. The paper contains more
+details about the inner workings of bounds checking GCC. The paper can be
+found in PostScript format in @file{bounds/report/bcrep2.ps.gz}.
+
+@menu
+* Compiling with checks::       How to compile your programs with bounds
+                                 checks on at runtime.
+* Incompatibilities with checking:: You can't use setjmp/longjmp, and threads
+                                 and signal handlers need special attention.
+* Unchecked code and libraries:: You can freely mix unchecked source files and
+                                 libraries with your checked program.
+* Debugging with GDB::          You may debug bounds checked programs with
+                                 GDB and there are special breakpoints for this
+                                 purpose.
+* Environment at runtime::      Customizing the runtime environment by passing
+                                 options in @code{GCC_BOUNDS_OPTS}.
+* Managing the heap::           How bounds checking uses the heap at runtime.
+* Unchecked objects::           How unchecked objects work.
+* Miscellaneous features::      Other features that might be of interest.
+* Checking 2D array indices::   Notes about 2D array indices.
+* What errors are caught::      What errors are caught and what errors are
+                                 missed?
+* Performance::                 How fast (or slow) can you expect bounds
+                                 checked programs to go?
+* Stubborn bugs::               Special ``features'' you may need to know
+                                 about.
+* Using G77 with bounds checking:: A small patch you have to make to get a
+                                smooth compile with G77.
+@end menu
+
+@ignore
+
+NOT YET DOCUMENTED!!! ---
+
+bounds/tools subdirectory
+bounds/misc subdirectory
+bounds/report subdirectory
+bounds/tests subdirectory
+bounds/treestats subdirectory
+
+tidy up this menu - need to make it more hierarchical
+
+@end ignore
+
+@node Compiling with checks
+@subsection Compiling with checks
+
+To compile all or part of your program with bounds checking, simply add the
+@code{-fbounds-checking} flag when compiling and linking. In the simplest
+instance, you might do:
+
+@example
+gcc -fbounds-checking program.c -o program
+@end example
+
+@noindent
+Or, linking several checked files together:
+
+@example
+gcc -fbounds-checking -c file1.c -o file1.o
+gcc -fbounds-checking -c file2.c -o file2.o
+gcc -fbounds-checking -c file3.c -o file3.o
+gcc -fbounds-checking file1.o file2.o file3.o -o program
+@end example
+
+If your program uses a Makefile, you will probably only need to add the
+@code{-fbounds-checking} flag to @code{CFLAGS}, and remake the program
+from scratch.
+
+@node Incompatibilities with checking
+@subsection Incompatibilities with checking
+
+@itemize @bullet
+@item Programs that use setjmp and longjmp.
+
+Bounds checking is unfortunately incompatible with setjmp/longjmp. This is
+regrettable, but the problem is quite fundamental and it is unlikely that
+these functions will ever be permissable.
+
+@item Using signal handlers.
+
+If possible, move signal handlers to a separate source file and set checking
+off in that file. If this is not possible, then you will need to edit
+@file{bounds/lib/mutex.h} which provides mutual exclusion to vital
+internal structures in the checking library. Normally this mutual exclusion
+is turned off, for reasons of efficiency.
+
+@item Using threads.
+
+You may use threads with bounds checking. If more than one thread could
+ever run with bounds checking, you will need to provide mutual exclusion
+as with signal handlers above. Edit the file @file{bounds/lib/mutex.h} and
+add whatever code is necessary to give mutual exclusion.
+
+@item Checking C++ programs.
+
+Every so often, someone mails me to ask why their C++ program isn't checked
+when they do @code{g++ -fbounds-checking}. At the moment, the bounds checking
+changes are specific to the C front end, so you can't use them with the other
+GCC front ends (eg. C++, FORTRAN, Modula-2). There is no reason why bounds
+checking couldn't be added to the C++ front end. It would take perhaps one or
+two months to do. It is highly unlikely that I will ever do this, but if a
+keen beta-tester wants it enough, I may be willing to help them. In the
+meantime, it is possible to translate C++ programs to C and check them, but
+line number and other debugging information may get scrambled in the process.
+@end itemize
+
+
+@node Unchecked code and libraries
+@subsection Unchecked code and libraries
+
+You can normally freely mix unchecked and checked code. This is why you don't
+need to make any changes to your C or X11 libraries when you install GCC
+with bounds checking. The checking library will detect code compiled with
+and without checking automagically, and let the two run together. You
+can mix unchecked object files with checked ones for the same reason. Always
+pass the @code{-fbounds-checking} flag to the link stage.
+
+@example
+gcc -fbounds-checking -c file1.c -o file1.o
+gcc -c unchecked.c -o unchecked.o
+gcc -fbounds-checking file1.o unchecked.o -o program
+@end example
+
+The checking library will usually only know about variables that are
+declared in checked code, and about memory allocated with @code{malloc}. So
+if a variable is declared in @file{unchecked.c} above, then references
+to it will @emph{not} be checked, even when these references occur in
+checked code.
+
+Say that file @file{unchecked.c} contains the following code:
+
+@example
+int a[10];
+
+int *get_ptr_to_a () @{ return a; @}
+@end example
+
+and file @file{file1.c} contains:
+
+@example
+extern int *get_ptr_to_a ();
+
+main ()
+@{
+  int *ptr_to_a = get_ptr_to_a ();
+  int i;
+
+  for (i = 0; i < 20; ++i) ptr_to_a[i] = 0;
+@}
+@end example
+
+The references to @code{ptr_to_a} will not be checked. You can resolve
+this by adding @code{a}, either by hand, or semi-automatically.
+@xref{Unchecked objects}
+
+If you place @code{extern int a[10];} anywhere in @file{file1.c}, bounds
+checking GCC will also be able to find and check the array references
+properly.
+
+If you include @file{bounds/run-includes/unchecked.h}, you get facilities
+to turn bounds checking on and off over short stretches of code and
+within single expressions and statements. Even when bounds checking is
+switched off, you may still use these features. The macros are silently
+ignored if bounds checking is off, or if the compiler is not GCC.
+
+@itemize @bullet
+@item @code{BOUNDS_CHECKING_OFF} @dots{} @code{BOUNDS_CHECKING_ON}
+
+Turn off bounds checking over a section of code. For instance:
+@example
+/* This code is checked ... */
+BOUNDS_CHECKING_OFF;
+/* This code is unchecked ... */
+BOUNDS_CHECKING_ON;
+/* This code is checked again ... */
+@end example
+The unchecked code should not try to return from a function, or jump over
+the @code{BOUNDS_CHECKING_ON} statement with @code{goto}, else checking
+will be switched off for the rest of the program!
+
+@item @code{BOUNDS_CHECKING_OFF_DURING}
+
+Switch off checking in a single statement. For instance:
+@example
+BOUNDS_CHECKING_OFF_DURING (p += 5);
+@end example
+The statement should not (obviously) be goto, return, @dots{}
+
+@item @code{BOUNDS_CHECKING_OFF_IN_EXPR}
+
+Switch off checking while a single expression is being evaluated. For instance:
+@example
+p = BOUNDS_CHECKING_OFF_IN_EXPR (a + 5);
+@end example
+
+@end itemize
+
+@node Debugging with GDB
+@subsection Debugging with GDB
+
+If you have GDB (or another debugger) on your system, you will be able to
+debug bounds checked programs easily and efficiently. To help you catch
+bounds errors before the program aborts (which sometimes causes the
+program's stack to disappear), place a breakpoint at
+@code{__bounds_breakpoint}. The checking library always calls this
+breakpoint before aborting. If the @code{-never-fatal} flag has been supplied
+@xref{Environment at runtime}, you will need to place this
+breakpoint, since the program does not abort when it hits a bounds error.
+
+@node Environment at runtime
+@subsection Environment at runtime
+
+You can customize the way a bounds-checked program runs by passing options
+to it in the environment variable `GCC_BOUNDS_OPTS'. For instance, suppose
+you don't want the banner message that appears when bounds checked programs
+start up. With sh or ksh, you might type:
+
+@example
+% GCC_BOUNDS_OPTS='-no-message' program
+@end example
+
+With csh:
+
+@example
+% setenv GCC_BOUNDS_OPTS '-no-message'; program
+@end example
+
+You can put any combination of the following flags in GCC_BOUNDS_OPTS. Place
+spaces or tabs between each flag.
+
+@table @samp
+@item -no-message
+Don't print the introductory message.
+@item -no-statistics
+Don't print library call statistics with the program quits.
+@item -?, -help
+Print this list of options, then quit the program before it starts.
+@item -reuse-heap (*)
+@item -reuse-age=<age>
+@item -no-reuse-heap
+See the discussion of heap memory, @xref{Managing the heap}.
+@item -warn-unchecked-statics
+@item -no-warn-unchecked-statics (*)
+@item -warn-unchecked-stack
+@item -no-warn-unchecked-stack (*)
+See the discussion of unchecked objects, @xref{Unchecked objects}.
+@item -warn-free-null (*)
+@item -no-warn-free-null
+Give a warning if free (0) is called. Note that this may be correct in
+ANSI C, and some libraries, notably X11, do it quite often.
+@item -warn-misc-strings (*)
+@item -no-warn-misc-strings
+Miscellaneous warnings with str* and mem* functions, such as trying to call
+@code{memcpy} with size = 0.
+@item -warn-illegal
+@item -no-warn-illegal (*)
+Warn when ILLEGAL pointers are generated. These patches, provided by
+@w{Don Lewis} <gdonl@@gv.ssi1.com>, help to track down ILLEGAL pointer
+errors when they happen.
+@item -warn-unaligned (*)
+@item -no-warn-unaligned
+Warn when a pointer is used in an unaligned manner, for instance reading
+integer data as chars. This warning is turned on by default, but may be
+disabled, since some programs do this quite harmlessly. These patches were
+suggested by @w{Stuart Kemp} and @w{Eberhard Mattes}.
+@item -warn-all
+Turn on all of the warnings above.
+@item -array-index-check (*)
+@item -no-array-index-check
+Check 2D array indices correctly. This is turned on by default. This will
+only check arrays with size > 1. This is done to avoid problems with
+structure hack definintions.
+@xref{Checking 2D array indices}
+@item -never-fatal
+Normally the library will call abort() after it detects the first bounds
+error. If this flag is given, the library attempts to proceed. The first
+error may generate more errors itself afterwards, so only the first error
+is guaranteed to be correct.
+@item -print-calls
+@item -no-print-calls (*)
+Print calls to the checking library. This option is only useful if you
+want to debug bounds checking GCC itself.
+@item -print-heap
+@item -no-print-heap (*)
+Print the contents of the heap at program end. This is usesful to find 
+memory leaks in your program.
+@end table
+
+Items marked with a `(*)' are the default.
+
+@node Managing the heap
+@subsection Managing the heap
+
+The bounds checking library includes a customized version of the GNU
+@code{malloc} library. Calls to @code{malloc}, @code{free}, @code{realloc},
+@code{calloc}, @code{cfree}, @code{valloc} and @code{memalign} are
+checked. You will get a bounds error if you try to:
+
+@itemize @bullet
+@item
+Free a pointer that has not been allocated in the proper way, or free a pointer
+twice.
+
+@item
+Reallocate a pointer that has not been allocated, or has been freed.
+
+@item
+Use a pointer to freed memory, or to memory that has been moved by
+@code{realloc}.
+
+@item
+Free or reallocate static memory.
+
+@end itemize
+
+There are several strategies for tracking stale memory pointers. Ideally,
+we would like to never reuse VM after the programmer has freed it, so that
+we will always be able to detect a stale pointer, no matter how long the
+program runs before using it. If you wish this behaviour, then pass
+the @code{-no-reuse-heap} option in `GCC_BOUNDS_OPTS'
+@xref{Environment at runtime}.@footnote{In a future version of bounds
+checking GCC, we will be able to unmap this memory. Thus the operating
+system will be able to reuse physical memory, whilest virtual memory
+addresses remain unused.}
+
+In practice, we found this technique to be wasteful, so the default is to
+reuse heap memory immediately. However, in order to provide some
+protection against stale pointers, you may pass the @code{-reuse-age=<age>}
+option to the library. This will add freed blocks to a queue of pending
+blocks. You must call @code{free} @code{<age>} times before the block
+is actually reused.
+
+Notice that the most common error is:
+
+@example
+free_list (list *p)
+@{
+  for (; p != NULL; p = p->next)
+    free (p);
+@}
+@end example
+
+The default flags, @code{-reuse-heap -reuse-age=0}, will catch this error.
+
+@node Unchecked objects
+@subsection Unchecked objects
+
+Variables declared in files that are not compiled with @code{-fbounds-checking}
+are not normally known about by the checking library. Pointers that
+point to these variables are not checked, even where the operations
+on these pointers happen within checked code. To be sure that your
+program is running without any errors, you should turn on warnings about
+unchecked operations by giving the @code{-warn-unchecked-statics} and/or
+@code{-warn-unchecked-stack} flags at runtime. @xref{Environment at
+runtime}.
+
+To avoid these warnings, and check all operations, you should take steps
+to add these objects to the tree used by the checking library. There are
+three approaches:
+
+@itemize @bullet
+@item
+Declare the object as @code{extern} somewhere in checked code. Make sure that
+the size of the object appears in the expression, ie. @code{extern int a[10];},
+not @code{extern int a[];}.
+
+@item
+Add the object by hand by calling @code{__bounds_note_constructed_object}.
+This function is declared:
+@example
+void __bounds_note_constructed_object (ptr, size, align, filename, line, name);
+  void *ptr;      /* Pointer to the object. */
+  size_t size;    /* Size of the object (bytes). */
+  size_t align;   /* Pass 1 here. */
+  char *filename; /* Filename where declared (for debugging). */
+  int line;       /* Line number. */
+  char *name;     /* Name of the object. */
+@end example
+
+@item
+Add all the objects from a single object file, or a library automagically,
+using the @code{grab-statics} tool in @file{bounds/tools}. There is a README
+file in that directory that will tell you more.
+
+@end itemize
+
+@node Miscellaneous features
+@subsection Miscellaneous features
+
+@itemize @bullet
+@item Detecting when a source file is being compiled with bounds checking.
+
+When GCC compiles a file with the @code{-fbounds-checking} flag, it
+defines @code{__BOUNDS_CHECKING_ON} in the preprocessor. In addition, the
+variable @code{__bounds_checking_on} is set to 1 when bounds checking is
+on in the program as a whole, and set to 0 when it is not. The variable
+is actually located in @code{libgcc.a}, so it is always present (unless
+you aren't using GCC).
+
+Notice the subtle difference between these two methods. Say a program
+consists of source files @file{file1.c} and @file{file2.c}. If the
+program is compiled with
+
+@example
+gcc -fbounds-checking -c file1.c
+gcc -c file2.c
+gcc -fbounds-checking file1.o file2.o -o program
+@end example
+
+@noindent
+then @file{file1.c} will be compiled with @code{__BOUNDS_CHECKING_ON}
+defined. In @file{file2.c} this will not be defined. Both files will
+be able to declare @code{extern int __bounds_checking_on;} and the
+variable will be read as @code{1} by both.
+
+If the same files are compiled without bounds checking, then
+@code{__BOUNDS_CHECKING_ON} will not be defined. Both files will be
+able to declare @code{extern int __bounds_checking_on;} and will read
+the variable as @code{0}.
+
+If the same files are compiled with another C compiler, then variable
+@code{__bounds_checking_on} will not exist. So all references to this
+variable should be defended by @code{#ifdef __GNUC__} @dots{}
+@code{#endif}.
+
+@end itemize
+
+@node Checking 2D array indices
+@subsection Checking 2D array indices
+
+2D arrays (and, indeed, n-D arrays with n >= 2) are checked as you might
+expect. We consider such arrays to be flattened before checking. For instance
+a mathematical 3x3-matrix @code{A} might be defined as:
+
+@example
+double A[3][3];
+@end example
+
+When @code{-no-array-index-check} is active we consider such a array as
+flattened.
+Bounds checking will then consider this to be a flat array with 9 elements.
+So, it is perfectly sound to write @code{A[1][4]}, since @code{1*3+4} @equiv{}
+@code{7}, and 0 <= 7 < 9. Similarly, @code{A[0][8]} and @code{A[2][-1]}
+will not generate bounds errors. (Interestingly, though, errors in the
+first index @emph{will} be caught --- this is to do with a subtlety in the
+way bounds checking works).
+
+When @code{-array-index-check} is present every dimension of the array is
+checked separatly. This is the default.
+This flag is only used for arrays with size > 1. For arrays with size of 1
+or 0 the flattened model is used. This allows the following code to work
+correctly.
+
+@example
+struct _string_t
+@{
+  int len;
+  char str[1];
+@};
+@end example
+
+@node What errors are caught
+@subsection What errors are caught
+
+A lot of people tell me that they have Purify, and bounds checking GCC seems
+unnecessary, since it seems to duplicate Purify but more slowly. Well,
+there are important reasons why bounds checking GCC is better than Purify,
+and if you rely on Purify alone, you will certainly miss bugs in your
+program.
+
+@noindent
+This is what bounds checking GCC will find, which Purify won't:
+
+@itemize @bullet
+@item Bounds of stack and static variables
+
+Try compiling:
+@example
+main ()
+@{
+  int a[10], b[100], i;
+
+  for (i = 0; i < 100; ++i)
+    a[i] = 0;
+@}
+@end example
+Purify will only detect these sorts of errors reliably if @code{a} is allocated
+with @code{malloc}.
+
+@item Large offsets from memory allocated with @code{malloc}
+
+Bugs such as the following one will not be found reliably by Purify, since
+it only puts a certain amount of blank padding between @code{malloc}'d
+memory.
+@example
+struct large_type @{
+  int data[5000];
+@};
+
+main ()
+@{
+  char *m1;
+  struct large_type *m2;
+  int i;
+
+  m1 = (char *) malloc (20000);
+  m2 = (struct large_type *) malloc (sizeof (struct large_type) * 5);
+
+  for (i = 4; i >= -2; --i) /* note: error when i == -1 */
+    m2[i].data[0] = 0;
+@}
+@end example
+
+@end itemize
+
+@noindent
+This is what Purify will find, which bounds checking GCC won't:
+
+@itemize @bullet
+@item Using a variable or memory before it is initialized
+
+Bounds checking GCC can't currently check this, but it may well be added
+in a future version. GCC itself will pick up simple instances of this
+if you pass the @code{-Winitialized} flag (without @code{-fbounds-checking}),
+but cannot check use of @code{malloc}'d memory.
+
+@end itemize
+
+There is a freeware program which emulates Purify available from Tristan
+Gingold <gingold@@amoco.saclay.cea.fr>. It only runs under Linux. Purify
+only works on Sun SPARCstations and HP-PA machines, and, of course, costs
+lots of cash.
+
+@node Performance
+@subsection Performance
+
+This page is under construction.
+
+@node Stubborn bugs
+@subsection Stubborn bugs
+
+The very latest list of bugs can be found in @file{bounds/BUGS}. This is a
+list of some of the most stubborn bugs, some of which have been around since
+the first version. Please send bug reports and (even better) bug fixes to
+`rjones@@orchestream.com' or `Haj.Ten.Brugge@@net.HCC.nl'.
+
+@itemize @bullet
+@ignore
+@item Incorrect initialization of arrays and structures.
+
+Bounds checking relies on being able to rewrite initializers for stack
+variables with side effect calls, so we can detect when a variable comes
+into scope. For instance, the code:
+
+@example
+f ()
+@{
+  @{
+    int a;
+    /* ... */
+  @}
+  @{
+    int b;
+    /* ... */
+  @}
+@}
+@end example
+
+@noindent
+may be rewritten as:
+
+@example
+f ()
+@{
+  @{
+    int a = (__bounds_add_stack_object (&a, 4, 1, ...), 0);
+    /* ... */
+  @}
+  @{
+    int b = (__bounds_add_stack_object (&b, 4, 1, ...), 0);
+    /* ... */
+  @}
+@}
+@end example
+
+The code that rewrites variable initializers is
+@w{@code{c-bounds.c:bounds_frig_decl_initial}}. The function works for
+simple things like basic types, strings, arrays of strings; but it chokes
+on some more complicated types. It usually throws the error
+
+@example
+empty initializer cannot be bounds checked
+@end example
+
+@noindent
+when it meets one of these usages. The following uses are known to throw
+up this error (all occurring as auto variables inside functions):
+
+@example
+char nodes[][20] = @{"foo", "bar"@};
+--- reported by Stuart Kemp <skemp@@bmc.com>
+
+struct @{ unsigned char c[6]; @} e = @{ 1, 2, 3, 4, 5, 6 @};
+
+struct @{ int foo, bar; @} var = *othervar;
+--- reported by Frank Cringle <fdc@@cliwe.ping.de>
+@end example
+
+I don't fully understand the TREE generated by GCC for constructors. Can
+someone else solve this?
+@end ignore
+
+@item Padding missed out between aggregates and 32-bit objects on the stack.
+
+Bounds checking GCC usually inserts bytes of padding between adjacent
+stack objects. This dead area between objects helps the checking library
+to detect the difference between a pointer to the last byte + 1 of one
+object and a pointer to the first byte of the next object. For some
+reason, this padding is omitted occasionally when a 32-bit object (eg. int,
+pointer) follows an aggregate (eg. array). But not always.
+
+The bug used to happen under Linux, but at some point in the past it seems
+to have fixed itself. The bug still appears under Solaris. You can demonstrate
+the bug by compiling Tcl/Tk on Solaris. The checking library will report
+at run time that a reference has been made to the byte following the end
+of the first object. When you look at the code, you will see that it is in fact
+referring to the next object (ie. the 32-bit integer).
+
+Update (16/10/95): I fixed some stuff in @w{assign_stack_local} and
+@w{assign_outer_stack_local} (thanks to @w{Don Lewis} @w{<gdonl@@gv.ssi1.com>})
+but I haven't been able to verify that this bug has gone for sure.
+
+@end itemize
+
+@node Using G77 with bounds checking
+@subsection Using G77 with bounds checking
+
+Bounds checking patches break the current G77 patches. You can get round this
+very easily. Copy @code{cp/bounds.c} into the @code{f/} subdirectory. Alter
+@code{f/Makefile.in} so that it compiles @code{bounds.c} along with
+the other G77 object files.
+
+Notice that this doesn't add bounds checking to FORTRAN @w{(:-<)}. Just lets
+you compile it.
 
 @node Return Address
 @section Getting the Return or Frame Address of a Function
diff -rup gcc-2.8.1.org/flags.h gcc-2.8.1/flags.h
--- gcc-2.8.1.org/flags.h	Wed Dec 31 13:02:33 1997
+++ gcc-2.8.1/flags.h	Sat Jun 13 12:22:35 1998
@@ -397,6 +397,10 @@ extern int current_function_has_nonlocal
 
 extern int current_function_has_nonlocal_goto;
 
+/* Flag indicating bounds checking in the C front-end. (RWMJ). */
+
+extern int bounds_checking_enabled;
+
 /* Nonzero if GCC must add code to check memory access (used by Checker).  */
 
 extern int flag_check_memory_usage;
diff -rup gcc-2.8.1.org/fold-const.c gcc-2.8.1/fold-const.c
--- gcc-2.8.1.org/fold-const.c	Sat Feb 28 20:58:15 1998
+++ gcc-2.8.1/fold-const.c	Sat Jun 13 12:22:35 1998
@@ -2257,6 +2257,16 @@ invert_truthvalue (arg)
       return build1 (CLEANUP_POINT_EXPR, type,
 		     invert_truthvalue (TREE_OPERAND (arg, 0)));
 
+      /* (RWMJ, 5/3/95)
+         Bounds checking often builds call expressions returning an integer
+         in place of equality and inequality operations, so we must catch
+         this case specially here. Otherwise, we abort after this switch
+         statement, since the return type cannot be `BOOLEAN' in C. */
+    case CALL_EXPR:
+      if (bounds_checking_enabled && TREE_CODE (type) == INTEGER_TYPE)
+	return build1 (TRUTH_NOT_EXPR, type, arg);
+      break;
+
     default:
       break;
     }
diff -rup gcc-2.8.1.org/function.c gcc-2.8.1/function.c
--- gcc-2.8.1.org/function.c	Sat Feb 28 20:58:16 1998
+++ gcc-2.8.1/function.c	Sat Jun 13 12:22:35 1998
@@ -717,6 +717,9 @@ assign_stack_local (mode, size, align)
   if (BYTES_BIG_ENDIAN && mode != BLKmode)
     bigend_correction = size - GET_MODE_SIZE (mode);
 
+  if (bounds_checking_enabled)	/* RWMJ */
+    size += BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+
 #ifdef FRAME_GROWS_DOWNWARD
   frame_offset -= size;
 #endif
@@ -788,6 +791,9 @@ assign_outer_stack_local (mode, size, al
   if (BYTES_BIG_ENDIAN && mode != BLKmode)
     bigend_correction = size - GET_MODE_SIZE (mode);
 
+  if (bounds_checking_enabled) /* RWMJ */
+    size += BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+
 #ifdef FRAME_GROWS_DOWNWARD
   function->frame_offset -= size;
 #endif
@@ -2792,7 +2798,7 @@ purge_addressof_1 (loc, insn, force)
       if (GET_CODE (sub) == MEM)
 	sub = gen_rtx (MEM, GET_MODE (x), copy_rtx (XEXP (sub, 0)));
 
-      if (GET_CODE (sub) == REG && MEM_VOLATILE_P (x))
+      if (GET_CODE (sub) == REG /* && MEM_VOLATILE_P (x) */)
 	{
 	  put_addressof_into_stack (XEXP (x, 0));
 	  return;
diff -rup gcc-2.8.1.org/gcc.c gcc-2.8.1/gcc.c
--- gcc-2.8.1.org/gcc.c	Sat Feb 28 20:58:17 1998
+++ gcc-2.8.1/gcc.c	Sat Jun 13 12:22:36 1998
@@ -580,6 +580,7 @@ static struct compiler *compilers;
 static int n_compilers;
 
 /* The default list of file name suffixes and their compilation specs.  */
+/* Bounds-checking flags added by RWMJ. */
 
 static struct compiler default_compilers[] =
 {
@@ -600,6 +601,7 @@ static struct compiler default_compilers
 	%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
         -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
 	%{ansi:-trigraphs -D__STRICT_ANSI__}\
+	%{fbounds-checking:-D__BOUNDS_CHECKING_ON}\
 	%{!undef:%{!ansi:%p} %P} %{trigraphs} \
         %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
@@ -718,6 +720,7 @@ static char *link_command_spec = "\
 			%{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
 			%{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
 			%{static:} %{L*} %o\
+			%{fbounds-checking:libcheck.a%s} \
 			%{!nostdlib:%{!nodefaultlibs:%G %L %G}}\
 			%{!A:%{!nostdlib:%{!nostartfiles:%E}}}\
 			%{T*}\
@@ -730,6 +733,7 @@ static char *link_command_spec = "\
 			%{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
 			%{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
 			%{static:} %{L*} %D %o\
+			%{fbounds-checking:libcheck.a%s} \
 			%{!nostdlib:%{!nodefaultlibs:%G %L %G}}\
 			%{!A:%{!nostdlib:%{!nostartfiles:%E}}}\
 			%{T*}\
diff -rup gcc-2.8.1.org/ginclude/stdarg.h gcc-2.8.1/ginclude/stdarg.h
--- gcc-2.8.1.org/ginclude/stdarg.h	Sat Oct 18 18:26:07 1997
+++ gcc-2.8.1/ginclude/stdarg.h	Sat Jun 13 12:22:36 1998
@@ -98,12 +98,12 @@ void va_end (__gnuc_va_list);		/* Define
 
 #if (defined (__arm__) && ! defined (__ARMEB__)) || defined (__i386__) || defined (__i860__) || defined (__ns32000__) || defined (__vax__)
 /* This is for little-endian machines; small args are padded upward.  */
-#define va_arg(AP, TYPE)						\
+#define __std_va_arg(AP, TYPE)						\
  (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
   *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE))))
 #else /* big-endian */
 /* This is for big-endian machines; small args are padded downward.  */
-#define va_arg(AP, TYPE)						\
+#define __std_va_arg(AP, TYPE)						\
  (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
   *((TYPE *) (void *) ((char *) (AP)					\
 		       - ((sizeof (TYPE) < __va_rounded_size (char)	\
@@ -131,6 +131,27 @@ void va_end (__gnuc_va_list);		/* Define
 #endif /* not i860 */
 #endif /* not m88k */
 #endif /* not clipper */
+
+/* Define va_arg in terms of __std_va_arg as appropriate for bounds
+   checking.
+   - RWMJ (16/1/96). */
+#ifndef __BOUNDS_CHECKING_ON
+
+#define va_arg(AP,TYPE) __std_va_arg(AP,TYPE)
+
+#else /* __BOUNDS_CHECKING_ON */
+
+extern int __bounds_debug_no_checking;
+
+#define va_arg(AP,TYPE) \
+  ({int __t = __bounds_debug_no_checking; \
+  TYPE __r; \
+  __bounds_debug_no_checking = 1; \
+  __r = __std_va_arg(AP,TYPE); \
+  __bounds_debug_no_checking = __t; \
+  __r;})
+
+#endif /* __BOUNDS_CHECKING_ON */
 
 #ifdef _STDARG_H
 /* Define va_list, if desired, from __gnuc_va_list. */
diff -rup gcc-2.8.1.org/ginclude/va-alpha.h gcc-2.8.1/ginclude/va-alpha.h
--- gcc-2.8.1.org/ginclude/va-alpha.h	Sun Mar  2 22:36:56 1997
+++ gcc-2.8.1/ginclude/va-alpha.h	Sat Jun 13 12:22:36 1998
@@ -110,13 +110,13 @@ enum {
     / __extension__ sizeof (long long)) * __extension__ sizeof (long long))
 
 #ifdef __VMS__
-#define va_arg(__va, __type)						\
+#define __std_va_arg(__va, __type)					\
 (*(((__va) += __va_tsize (__type)),					\
    (__type *)(void *)((__va) - __va_tsize (__type))))
 
 #else
 
-#define va_arg(__va, __type)						\
+#define __std_va_arg(__va, __type)						\
 (*(((__va).__offset += __va_tsize (__type)),				\
    (__type *)(void *)((__va).__base + (__va).__offset			\
 	      - (((__builtin_classify_type (* (__type *) 0)		\
diff -rup gcc-2.8.1.org/ginclude/va-arc.h gcc-2.8.1/ginclude/va-arc.h
--- gcc-2.8.1.org/ginclude/va-arc.h	Tue Sep  9 23:20:32 1997
+++ gcc-2.8.1/ginclude/va-arc.h	Sat Jun 13 12:22:36 1998
@@ -83,7 +83,7 @@ enum __va_type_classes {
   (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
 
 #ifdef __big_endian__
-#define va_arg(AP,TYPE) \
+#define __std_va_arg(AP,TYPE) \
 __extension__							\
 (*({((__builtin_classify_type (*(TYPE*) 0) >= __record_type_class \
       || __va_rounded_size (TYPE) > 8)				\
@@ -95,7 +95,7 @@ __extension__							\
 			 : (int) AP)				\
 			 + __va_rounded_size (TYPE))) - 1));}))
 #else
-#define va_arg(AP,TYPE) \
+#define __std_va_arg(AP,TYPE) \
 __extension__							\
 (*({((__builtin_classify_type (*(TYPE*) 0) >= __record_type_class \
       || __va_rounded_size (TYPE) > 8)				\
diff -rup gcc-2.8.1.org/ginclude/va-clipper.h gcc-2.8.1/ginclude/va-clipper.h
--- gcc-2.8.1.org/ginclude/va-clipper.h	Sun Mar  2 22:36:58 1997
+++ gcc-2.8.1/ginclude/va-clipper.h	Sat Jun 13 12:22:36 1998
@@ -45,7 +45,7 @@ typedef struct
    ~(__alignof__ (TYPE) - 1),					\
   ((AP).__va_ap = ((AP).__va_ap + sizeof (int) - 1) & ~(sizeof (int) - 1)))
 
-#define va_arg(AP, TYPE) \
+#define __std_va_arg(AP, TYPE) \
   (*((AP).__va_num < 2 && __builtin_classify_type (* (TYPE *)0) < 12	\
    ? (__builtin_classify_type (* (TYPE *)0) == 8			\
       ? ((TYPE *)(AP).__va_reg[2 * (AP).__va_num++ + 1])		\
diff -rup gcc-2.8.1.org/ginclude/va-h8300.h gcc-2.8.1/ginclude/va-h8300.h
--- gcc-2.8.1.org/ginclude/va-h8300.h	Sun Mar  2 22:36:59 1997
+++ gcc-2.8.1/ginclude/va-h8300.h	Sat Jun 13 12:22:36 1998
@@ -42,7 +42,7 @@ typedef void *__gnuc_va_list;
 
 #endif /* _VARARGS_H */
 
-#define va_arg(AP, TYPE)						\
+#define __std_va_arg(AP, TYPE)						\
  (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
   *((TYPE *) (void *) ((char *) (AP)					\
 		       - ((sizeof (TYPE) < __va_rounded_size (int)	\
diff -rup gcc-2.8.1.org/ginclude/va-i860.h gcc-2.8.1/ginclude/va-i860.h
--- gcc-2.8.1.org/ginclude/va-i860.h	Sun Mar  2 22:37:02 1997
+++ gcc-2.8.1/ginclude/va-i860.h	Sat Jun 13 12:22:36 1998
@@ -121,7 +121,7 @@ void va_end (__gnuc_va_list);		/* Define
 #define __extension__
 #endif
 
-#define va_arg(__va, __type)						\
+#define __std_va_arg(__va, __type)						\
 __extension__								\
 (* (__type *)								\
 ({									\
diff -rup gcc-2.8.1.org/ginclude/va-i960.h gcc-2.8.1/ginclude/va-i960.h
--- gcc-2.8.1.org/ginclude/va-i960.h	Sun Mar  2 22:37:04 1997
+++ gcc-2.8.1/ginclude/va-i960.h	Sat Jun 13 12:22:36 1998
@@ -56,7 +56,7 @@ __extension__						\
 
 /* We cast to void * and then to TYPE * because this avoids
    a warning about increasing the alignment requirement.  */
-#define	va_arg(AP, T)							\
+#define	__std_va_arg(AP, T)							\
 (									\
   (									\
     ((AP)[1] <= 48 && (__vpad ((AP)[1], T) > 48 || __vsiz (T) > 16))	\
diff -rup gcc-2.8.1.org/ginclude/va-m32r.h gcc-2.8.1/ginclude/va-m32r.h
--- gcc-2.8.1.org/ginclude/va-m32r.h	Mon Mar 24 19:52:26 1997
+++ gcc-2.8.1/ginclude/va-m32r.h	Sat Jun 13 12:22:36 1998
@@ -62,7 +62,7 @@ enum __type_class
 /* Return whether a type is passed by reference.  */
 #define __va_by_reference_p(TYPE) (sizeof (TYPE) > 8)
 
-#define va_arg(AP,TYPE)							\
+#define __std_va_arg(AP,TYPE)						\
 __extension__ (*({							\
   register TYPE *__ptr;							\
 									\
diff -rup gcc-2.8.1.org/ginclude/va-m88k.h gcc-2.8.1/ginclude/va-m88k.h
--- gcc-2.8.1.org/ginclude/va-m88k.h	Sun Mar  2 22:37:06 1997
+++ gcc-2.8.1/ginclude/va-m88k.h	Sat Jun 13 12:22:36 1998
@@ -70,7 +70,7 @@ typedef struct
 
 /* We cast to void * and then to TYPE * because this avoids
    a warning about increasing the alignment requirement.  */
-#define va_arg(AP,TYPE)							   \
+#define __std_va_arg(AP,TYPE)							   \
   ( (AP).__va_arg = (((AP).__va_arg + (1 << (__alignof__(TYPE) >> 3)) - 1) \
 		     & ~((1 << (__alignof__(TYPE) >> 3)) - 1))		   \
     + __va_size(TYPE),							   \
diff -rup gcc-2.8.1.org/ginclude/va-mips.h gcc-2.8.1/ginclude/va-mips.h
--- gcc-2.8.1.org/ginclude/va-mips.h	Mon Sep  8 08:55:47 1997
+++ gcc-2.8.1/ginclude/va-mips.h	Sat Jun 13 12:22:36 1998
@@ -210,7 +210,7 @@ void va_end (__gnuc_va_list);		/* Define
 #endif /* ! (! defined (__mips_soft_float) && ! defined (__mips_single_float)) */
 
 #ifdef __MIPSEB__
-#define va_arg(__AP, __type)						\
+#define __std_va_arg(__AP, __type)					\
   ((__va_rounded_size (__type) <= __va_reg_size)			\
    ? *(__type *) (void *) (__va_next_addr (__AP, __type)		\
 			   + __va_reg_size				\
@@ -221,7 +221,7 @@ void va_end (__gnuc_va_list);		/* Define
 				- sizeof (char *))			\
       : *(__type *) (void *) __va_next_addr (__AP, __type)))
 #else
-#define va_arg(__AP, __type)						\
+#define __std_va_arg(__AP, __type)					\
   ((__va_rounded_size (__type) <= __va_reg_size)			\
    ? *(__type *) (void *) __va_next_addr (__AP, __type)		\
    : (__builtin_classify_type (* (__type *) 0) >= __record_type_class	\
@@ -239,11 +239,11 @@ void va_end (__gnuc_va_list);		/* Define
    right aligned).  */
 #ifdef __mips64
 #ifdef __MIPSEB__
-#define va_arg(__AP, __type)                                    \
+#define __std_va_arg(__AP, __type)                                    \
   ((__type *) (void *) (__AP = (char *) ((((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8) \
 					 + __va_rounded_size (__type))))[-1]
 #else
-#define va_arg(__AP, __type)                                    \
+#define __std_va_arg(__AP, __type)                                    \
   ((__AP = (char *) ((((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8)	\
 		     + __va_rounded_size (__type))),		\
    *(__type *) (void *) (__AP - __va_rounded_size (__type)))
@@ -253,7 +253,7 @@ void va_end (__gnuc_va_list);		/* Define
 
 #ifdef __MIPSEB__
 /* For big-endian machines.  */
-#define va_arg(__AP, __type)					\
+#define __std_va_arg(__AP, __type)					\
   ((__AP = (char *) ((__alignof__ (__type) > 4			\
 		      ? ((int)__AP + 8 - 1) & -8		\
 		      : ((int)__AP + 4 - 1) & -4)		\
@@ -261,7 +261,7 @@ void va_end (__gnuc_va_list);		/* Define
    *(__type *) (void *) (__AP - __va_rounded_size (__type)))
 #else
 /* For little-endian machines.  */
-#define va_arg(__AP, __type)						    \
+#define __std_va_arg(__AP, __type)						    \
   ((__type *) (void *) (__AP = (char *) ((__alignof__(__type) > 4	    \
 					  ? ((int)__AP + 8 - 1) & -8	    \
 					  : ((int)__AP + 4 - 1) & -4)	    \
diff -rup gcc-2.8.1.org/ginclude/va-mn10200.h gcc-2.8.1/ginclude/va-mn10200.h
--- gcc-2.8.1.org/ginclude/va-mn10200.h	Mon Jun 23 18:28:13 1997
+++ gcc-2.8.1/ginclude/va-mn10200.h	Sat Jun 13 12:22:36 1998
@@ -27,7 +27,7 @@ typedef void *__gnuc_va_list;
 #undef va_end
 void va_end (__gnuc_va_list);
 #define va_end(AP) ((void)0)
-#define va_arg(AP, TYPE)						\
+#define __std_va_arg(AP, TYPE)						\
  (sizeof (TYPE) > 8							\
   ? (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (char *)),\
     **((TYPE **) (void *) ((char *) (AP) - __va_rounded_size (char *))))\
diff -rup gcc-2.8.1.org/ginclude/va-mn10300.h gcc-2.8.1/ginclude/va-mn10300.h
--- gcc-2.8.1.org/ginclude/va-mn10300.h	Wed Apr  2 02:18:01 1997
+++ gcc-2.8.1/ginclude/va-mn10300.h	Sat Jun 13 12:22:36 1998
@@ -26,7 +26,7 @@ typedef void *__gnuc_va_list;
 #undef va_end
 void va_end (__gnuc_va_list);
 #define va_end(AP) ((void)0)
-#define va_arg(AP, TYPE)						\
+#define __std_va_arg(AP, TYPE)						\
  (sizeof (TYPE) > 8							\
   ? (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (char *)),\
     **((TYPE **) (void *) ((char *) (AP) - __va_rounded_size (char *))))\
diff -rup gcc-2.8.1.org/ginclude/va-pa.h gcc-2.8.1/ginclude/va-pa.h
--- gcc-2.8.1.org/ginclude/va-pa.h	Sun Mar  2 22:37:11 1997
+++ gcc-2.8.1/ginclude/va-pa.h	Sat Jun 13 12:22:36 1998
@@ -32,7 +32,7 @@ typedef void *__gnuc_va_list;
 #define va_start(AP) __gnuc_va_start (AP)
 #endif
 
-#define va_arg(AP,TYPE)						\
+#define __std_va_arg(AP,TYPE)						\
   (*(sizeof(TYPE) > 8 ?						\
    ((AP = (__gnuc_va_list) ((char *)AP - sizeof (int))),	\
     (((TYPE *) (void *) (*((int *) (AP))))))			\
diff -rup gcc-2.8.1.org/ginclude/va-ppc.h gcc-2.8.1/ginclude/va-ppc.h
--- gcc-2.8.1.org/ginclude/va-ppc.h	Sun Mar  2 22:37:13 1997
+++ gcc-2.8.1/ginclude/va-ppc.h	Sat Jun 13 12:22:36 1998
@@ -115,7 +115,7 @@ __extension__ ({							\
 #define __va_aggregate_p(TYPE)	(__builtin_classify_type(*(TYPE *)0) >= 12)
 #define __va_size(TYPE)		((sizeof(TYPE) + sizeof (long) - 1) / sizeof (long))
 
-#define va_arg(AP,TYPE)							\
+#define __std_va_arg(AP,TYPE)							\
 __extension__ (*({							\
   register TYPE *__ptr;							\
 									\
@@ -219,7 +219,7 @@ typedef char *__gnuc_va_list;
      ((((unsigned long)(AP)) + ((sizeof (TYPE) >= 8) ? 7 : 3))		\
       & ~((sizeof (TYPE) >= 8) ? 7 : 3))
 
-#define va_arg(AP,TYPE)							\
+#define __std_va_arg(AP,TYPE)						\
 ( *(TYPE *)((AP = (char *) (__va_align(AP, TYPE)			\
 			    + __va_rounded_size(TYPE)))			\
 	    - __va_rounded_size(TYPE)))
diff -rup gcc-2.8.1.org/ginclude/va-pyr.h gcc-2.8.1/ginclude/va-pyr.h
--- gcc-2.8.1.org/ginclude/va-pyr.h	Sat Apr 15 00:43:07 1995
+++ gcc-2.8.1/ginclude/va-pyr.h	Sat Jun 13 12:22:36 1998
@@ -109,7 +109,7 @@ typedef __va_buf __gnuc_va_list;
 
 /* We cast to void * and then to TYPE * because this avoids
    a warning about increasing the alignment requirement.  */
-#define va_arg(_AP, _MODE)	\
+#define __std_va_arg(_AP, _MODE)	\
 __extension__								\
 (*({__voidptr *__ap = (__voidptr*)&_AP;					\
   register int __size = sizeof (_MODE);					\
diff -rup gcc-2.8.1.org/ginclude/va-sh.h gcc-2.8.1/ginclude/va-sh.h
--- gcc-2.8.1.org/ginclude/va-sh.h	Thu Oct 30 17:11:17 1997
+++ gcc-2.8.1/ginclude/va-sh.h	Sat Jun 13 12:22:36 1998
@@ -159,7 +159,7 @@ __extension__								\
 #define __PASS_AS_FLOAT(TYPE_CLASS,SIZE) \
   (TYPE_CLASS == __real_type_class && SIZE == 4)
 
-#define va_arg(pvar,TYPE)					\
+#define __std_va_arg(pvar,TYPE)					\
 __extension__							\
 ({int __type = __builtin_classify_type (* (TYPE *) 0);		\
   void * __result_p;						\
@@ -189,7 +189,7 @@ __extension__							\
 
 #else /* ! SH3E */
 
-#define va_arg(AP, TYPE) __va_arg_sh1((AP), TYPE)
+#define __std_va_arg(AP, TYPE) __va_arg_sh1((AP), TYPE)
 
 #endif /* SH3E */
 
diff -rup gcc-2.8.1.org/ginclude/va-sparc.h gcc-2.8.1/ginclude/va-sparc.h
--- gcc-2.8.1.org/ginclude/va-sparc.h	Sat Oct 18 00:32:20 1997
+++ gcc-2.8.1/ginclude/va-sparc.h	Sat Jun 13 12:22:36 1998
@@ -93,7 +93,7 @@ typedef unsigned int __ptrint __attribut
 
 /* ??? TODO: little endian support */
 
-#define va_arg(pvar, TYPE) \
+#define __std_va_arg(pvar, TYPE) \
 __extension__							\
 (*({int __type = __builtin_classify_type (* (TYPE *) 0);	\
   char * __result;						\
@@ -141,7 +141,7 @@ __extension__							\
 /* We cast to void * and then to TYPE * because this avoids
    a warning about increasing the alignment requirement.
    The casts to char * avoid warnings about invalid pointer arithmetic.  */
-#define va_arg(pvar,TYPE)					\
+#define __std_va_arg(pvar,TYPE)					\
 __extension__							\
 (*({((__builtin_classify_type (*(TYPE*) 0) >= __record_type_class \
       || (__builtin_classify_type (*(TYPE*) 0) == __real_type_class \
diff -rup gcc-2.8.1.org/ginclude/va-spur.h gcc-2.8.1/ginclude/va-spur.h
--- gcc-2.8.1.org/ginclude/va-spur.h	Sun Mar  2 22:37:19 1997
+++ gcc-2.8.1/ginclude/va-spur.h	Sat Jun 13 12:22:36 1998
@@ -36,7 +36,7 @@ typedef struct {
 #define __extension__
 #endif
 
-#define va_arg(pvar,type)  \
+#define __va_arg(pvar,type)  \
 __extension__ \
     (*({  type *__va_result; \
         if ((pvar).__pnt >= 20) { \
diff -rup gcc-2.8.1.org/ginclude/va-v850.h gcc-2.8.1/ginclude/va-v850.h
--- gcc-2.8.1.org/ginclude/va-v850.h	Fri Sep  5 18:43:48 1997
+++ gcc-2.8.1/ginclude/va-v850.h	Sat Jun 13 12:22:36 1998
@@ -25,7 +25,7 @@ typedef void *__gnuc_va_list;
 #undef va_end
 void va_end (__gnuc_va_list);
 #define va_end(AP) ((void)0)
-#define va_arg(AP, TYPE)						\
+#define __std_va_arg(AP, TYPE)						\
  (sizeof (TYPE) > 8							\
   ? (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (char *)),\
     **((TYPE **) (void *) ((char *) (AP) - __va_rounded_size (char *))))\
diff -rup gcc-2.8.1.org/ginclude/varargs.h gcc-2.8.1/ginclude/varargs.h
--- gcc-2.8.1.org/ginclude/varargs.h	Sat Oct 18 18:26:07 1997
+++ gcc-2.8.1/ginclude/varargs.h	Sat Jun 13 12:22:36 1998
@@ -117,12 +117,12 @@ typedef void *__gnuc_va_list;
 
 #if (defined (__arm__) && ! defined (__ARMEB__)) || defined (__i386__) || defined (__i860__) || defined (__ns32000__) || defined (__vax__)
 /* This is for little-endian machines; small args are padded upward.  */
-#define va_arg(AP, TYPE)						\
+#define __std_va_arg(AP, TYPE)						\
  (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
   *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE))))
 #else /* big-endian */
 /* This is for big-endian machines; small args are padded downward.  */
-#define va_arg(AP, TYPE)						\
+#define __std_va_arg(AP, TYPE)						\
  (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
   *((TYPE *) (void *) ((char *) (AP)					\
 		       - ((sizeof (TYPE) < __va_rounded_size (char)	\
@@ -150,6 +150,27 @@ typedef void *__gnuc_va_list;
 #endif /* not mips */
 #endif /* not spur */
 #endif /* not sparc */
+
+/* Define va_arg in terms of __std_va_arg as appropriate for bounds
+   checking. - RWMJ (16/1/96). */
+#ifndef __BOUNDS_CHECKING_ON
+
+#define va_arg(AP,TYPE) __std_va_arg(AP,TYPE)
+
+#else /* __BOUNDS_CHECKING_ON */
+
+extern int __bounds_debug_no_checking;
+
+#define va_arg(AP,TYPE) \
+  ({int __t = __bounds_debug_no_checking; \
+  TYPE __r; \
+  __bounds_debug_no_checking = 1; \
+  __r = __std_va_arg(AP,TYPE); \
+  __bounds_debug_no_checking = __t; \
+  __r;})
+
+#endif /* __BOUNDS_CHECKING_ON */
+
 #endif /* not _VARARGS_H */
 
 /* Define va_list from __gnuc_va_list.  */
diff -rup gcc-2.8.1.org/invoke.texi gcc-2.8.1/invoke.texi
--- gcc-2.8.1.org/invoke.texi	Tue Feb 17 18:54:05 1998
+++ gcc-2.8.1/invoke.texi	Sat Jun 13 12:22:36 1998
@@ -137,6 +137,7 @@ in the following sections.
 -ggdb  -gstabs  -gstabs+  -gxcoff  -gxcoff+
 -p  -pg  -print-file-name=@var{library}  -print-libgcc-file-name
 -print-prog-name=@var{program}  -print-search-dirs  -save-temps
+-fbounds-checking
 @end smallexample
 
 @item Optimization Options
@@ -1767,6 +1768,11 @@ to append to the text file @file{bb.out}
 This data could be analyzed by a program like @code{tcov}.  Note,
 however, that the format of the data is not what @code{tcov} expects.
 Eventually GNU @code{gprof} should be extended to process this data.
+
+@cindex @code{-fbounds-checking}
+@item -fbounds-checking
+Add extra code to check array bounds and pointers at run time. See
+@xref{Bounds Checking}. This option only works with C.
 
 @item -ax
 Generate extra code to profile basic blocks.  Your executable will
diff -rup gcc-2.8.1.org/libgcc2.c gcc-2.8.1/libgcc2.c
--- gcc-2.8.1.org/libgcc2.c	Fri Feb  6 20:50:59 1998
+++ gcc-2.8.1/libgcc2.c	Sat Jun 13 12:22:36 1998
@@ -2965,6 +2965,11 @@ cacheflush (char *beg, int size, int fla
 #define HAS_INIT_SECTION
 #endif
 
+/* RWMJ:
+   If there are any bounds-checked modules in this program at all, then
+   __bounds_initialize_library will be called, which sets the following flag. */
+int __bounds_checking_on = 0;
+
 #if !defined (HAS_INIT_SECTION) || !defined (OBJECT_FORMAT_ELF)
 /* Run all the global destructors on exit from the program.  */
 
diff -rup gcc-2.8.1.org/objc/objc-parse.y gcc-2.8.1/objc/objc-parse.y
--- gcc-2.8.1.org/objc/objc-parse.y	Sun Mar  1 11:38:26 1998
+++ gcc-2.8.1/objc/objc-parse.y	Sat Jun 13 12:22:36 1998
@@ -43,6 +43,9 @@ Boston, MA 02111-1307, USA.  */
 #include "c-tree.h"
 #include "flags.h"
 
+extern int bounds_checking_enabled, bounds_in_static_decl;
+tree bounds_build_component_indirect_ref PROTO((tree, tree));
+
 #ifdef MULTIBYTE_CHARS
 #include <stdlib.h>
 #include <locale.h>
@@ -802,17 +805,25 @@ primary:
 		}
 	| primary POINTSAT identifier
 		{
-                  tree expr = build_indirect_ref ($1, "->");
+		  if (bounds_checking_enabled &&
+		      !bounds_in_static_decl)
+		    {
+		      $$ = bounds_build_component_indirect_ref ($1, $3);
+		    }
+		  else
+		    {
+		      tree expr = build_indirect_ref ($1, "->");
 
-                  if (doing_objc_thang)
-                    {
-		      if (is_public (expr, $3))
-			$$ = build_component_ref (expr, $3);
+                      if (doing_objc_thang)
+			{
+			  if (is_public (expr, $3))
+			    $$ = build_component_ref (expr, $3);
+			  else
+			    $$ = error_mark_node;
+			}
 		      else
-			$$ = error_mark_node;
+                        $$ = build_component_ref (expr, $3);
 		    }
-                  else
-                    $$ = build_component_ref (expr, $3);
 		}
 	| primary PLUSPLUS
 		{ $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); }
diff -rup gcc-2.8.1.org/optabs.c gcc-2.8.1/optabs.c
--- gcc-2.8.1.org/optabs.c	Sat Feb 14 11:41:17 1998
+++ gcc-2.8.1/optabs.c	Sat Jun 13 12:22:36 1998
@@ -4286,12 +4286,27 @@ init_optabs ()
   truncxfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__truncxfdf2");
   trunctfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__trunctfdf2");
 
-  memcpy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcpy");
-  bcopy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bcopy");
-  memcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcmp");
-  bcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gcc_bcmp");
-  memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memset");
-  bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero");
+  /* In bounds checking mode, we need to call the unchecked versions of some
+     of these functions. The '__bounds_...' functions are supplied by libcheck.
+     (RWMJ, 25/4/95). */
+  if (!bounds_checking_enabled)
+    {
+      memcpy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcpy");
+      bcopy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bcopy");
+      memcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcmp");
+      bcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gcc_bcmp");
+      memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memset");
+      bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero");
+    }
+  else
+    {
+      memcpy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__bounds_memcpy");
+      bcopy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bcopy");
+      memcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__bounds_memcmp");
+      bcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gcc_bcmp");
+      memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__bounds_memset");
+      bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero");
+    }
 
   throw_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__throw");
   sjthrow_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__sjthrow");
diff -rup gcc-2.8.1.org/print-tree.c gcc-2.8.1/print-tree.c
--- gcc-2.8.1.org/print-tree.c	Thu Aug  7 11:54:37 1997
+++ gcc-2.8.1/print-tree.c	Sat Jun 13 12:22:36 1998
@@ -413,7 +413,10 @@ print_node (file, prefix, node, indent)
 
       print_node (file, "arguments", DECL_ARGUMENTS (node), indent + 4);
       print_node (file, "result", DECL_RESULT (node), indent + 4);
-      print_node_brief (file, "initial", DECL_INITIAL (node), indent + 4);
+
+      /* Want full printing of the initial node here. (RWMJ) */
+/*      print_node_brief (file, "initial", DECL_INITIAL (node), indent + 4); */
+      print_node (file, "initial", DECL_INITIAL (node), indent + 4);
 
       print_lang_decl (file, node, indent);
 
diff -rup gcc-2.8.1.org/stmt.c gcc-2.8.1/stmt.c
--- gcc-2.8.1.org/stmt.c	Sun Mar  1 02:00:00 1998
+++ gcc-2.8.1/stmt.c	Sat Jun 13 12:22:36 1998
@@ -1281,7 +1281,8 @@ fixup_gotos (thisblock, stack_level, cle
 		f->before_jump
 		  = emit_insns_after (cleanup_insns, f->before_jump);
 
-	      f->cleanup_list_list = TREE_CHAIN (lists);
+	      if (!bounds_checking_enabled)
+	        f->cleanup_list_list = TREE_CHAIN (lists);
 	    }
 
 	if (stack_level)
@@ -3548,7 +3549,13 @@ bc_expand_end_bindings (vars, mark_ends,
 }
 
 /* Generate RTL for the automatic variable declaration DECL.
-   (Other kinds of declarations are simply ignored if seen here.)  */
+   (Other kinds of declarations are simply ignored if seen here.)
+
+   In bounds checking mode (for C only at present) we insert an extra byte
+   after automatic variables. This lets us validly generate pointers to
+   the end of the object + 1. Notice that in bounds checking mode, no
+   real automatic variables make it into registers.
+   (RWMJ) */
 
 void
 expand_decl (decl)
@@ -3603,7 +3610,9 @@ expand_decl (decl)
 	   /* if -fcheck-memory-usage, check all variables.  */
 	   && ! flag_check_memory_usage)
     {
-      /* Automatic variable that can go in a register.  */
+      /* Automatic variable that can go in a register.
+         In bounds checking mode, no automatic variables make it into regs,
+         since we take the address of all of them. */
       int unsignedp = TREE_UNSIGNED (type);
       enum machine_mode reg_mode
 	= promote_mode (type, DECL_MODE (decl), &unsignedp, 0);
@@ -3626,6 +3635,7 @@ expand_decl (decl)
       /* Variable of fixed size that goes on the stack.  */
       rtx oldaddr = 0;
       rtx addr;
+      int size;
 
       /* If we previously made RTL for this decl, it must be an array
 	 whose size was determined by the initializer.
@@ -3639,12 +3649,16 @@ expand_decl (decl)
 	  oldaddr = XEXP (DECL_RTL (decl), 0);
 	}
 
+      size = ((TREE_INT_CST_LOW (DECL_SIZE (decl))
+	       + BITS_PER_UNIT - 1)
+	      / BITS_PER_UNIT);
+      /* Add a byte of padding between bounds checked variables. (RWMJ). */
+      if (bounds_checking_enabled)
+	size += BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+
       DECL_RTL (decl)
-	= assign_stack_temp (DECL_MODE (decl),
-			     ((TREE_INT_CST_LOW (DECL_SIZE (decl))
-			       + BITS_PER_UNIT - 1)
-			      / BITS_PER_UNIT),
-			     1);
+	= assign_stack_temp (DECL_MODE (decl), size, 1);
+
       MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (TREE_TYPE (decl));
 
       /* Set alignment we actually gave this decl.  */
@@ -3686,10 +3700,20 @@ expand_decl (decl)
 	}
 
       /* Compute the variable's size, in bytes.  */
-      size = expand_expr (size_binop (CEIL_DIV_EXPR,
-				      DECL_SIZE (decl),
-				      size_int (BITS_PER_UNIT)),
-			  NULL_RTX, VOIDmode, 0);
+      /* In bounds checking mode, make the size one byte larger. (RWMJ) */
+      if (!bounds_checking_enabled)
+	size = expand_expr (size_binop (CEIL_DIV_EXPR,
+					DECL_SIZE (decl),
+					size_int (BITS_PER_UNIT)),
+			    NULL_RTX, VOIDmode, 0);
+      else
+	size = expand_expr (size_binop (CEIL_DIV_EXPR,
+					size_binop (PLUS_EXPR,
+						    DECL_SIZE (decl),
+						    size_int (BIGGEST_ALIGNMENT/
+							      BITS_PER_UNIT)),
+					size_int (BITS_PER_UNIT)),
+			    NULL_RTX, VOIDmode, 0);
       free_temp_slots ();
 
       /* Allocate space on the stack for the variable.  Note that
diff -rup gcc-2.8.1.org/toplev.c gcc-2.8.1/toplev.c
--- gcc-2.8.1.org/toplev.c	Thu Feb 26 02:04:46 1998
+++ gcc-2.8.1/toplev.c	Sat Jun 13 12:22:36 1998
@@ -634,6 +634,12 @@ int flag_check_memory_usage = 0;
    -fcheck-memory-usage.  */
 int flag_prefix_function_name = 0;
 
+/* Flag indicating that bounds checking has been enabled in the C
+   front end. There are some changes in `varasm.c' that depend upon
+   the state of this flag. (RWMJ) */
+
+int bounds_checking_enabled = 0;
+
 /* Table of language-independent -f options.
    STRING is the option name.  VARIABLE is the address of the variable.
    ON_VALUE is the value to store in VARIABLE
@@ -786,6 +792,9 @@ char *lang_options[] =
   "-Wno-undef",
   "-Wwrite-strings",
   "-Wno-write-strings",
+
+  /* This is for bounds checking code. (RWMJ). */
+  "-fbounds-checking",			/* Switches default options on. */
 
   /* these are for obj c */
   "-lang-objc",
diff -rup gcc-2.8.1.org/varasm.c gcc-2.8.1/varasm.c
--- gcc-2.8.1.org/varasm.c	Sun Mar  1 12:04:05 1998
+++ gcc-2.8.1/varasm.c	Sat Jun 13 12:22:36 1998
@@ -165,6 +165,18 @@ static int output_addressed_constants	PR
 static void output_after_function_constants PROTO((void));
 static void bc_assemble_integer		PROTO((tree, int));
 static void output_constructor		PROTO((tree, int));
+
+/* In bounds checking mode, we build a list of private statics allocated
+   in the output file. At the end, we build the list into an array, so we
+   can find all these strings and things. */
+static struct private_statics_elem {
+  struct private_statics_elem *next;
+  char *name;				/* Name for this object. */
+  int name_label;			/* (Private: label for this name). */
+  char *label;				/* Assembler label. */
+  int size;				/* Size of the declaration. */
+} *private_statics_list = NULL;
+
 
 static enum in_section { no_section, in_text, in_data, in_named
 #ifdef BSS_SECTION_ASM_OP
@@ -797,6 +809,83 @@ make_decl_rtl (decl, asmspec, top_level)
 	      ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
 	      name = obstack_copy0 (saveable_obstack, label, strlen (label));
 	      var_labelno++;
+
+	      /* In bounds checked mode, we want to remember this assembler
+	         label till the end of the file. (RWMJ). */
+	      if (bounds_checking_enabled
+		  /* Don't check __FUNCTION__ and __PRETTY_FUNCTION__. */
+		  && !DECL_IN_SYSTEM_HEADER (decl))
+		{
+		  struct private_statics_elem *private_static;
+		  int size;
+		  tree size_tree;
+
+		  /* Work out the size. If it's not constant, then we will
+		     be in trouble. */
+		  if (TREE_CODE (decl) != VAR_DECL
+		      || !DECL_INITIAL (decl)
+		      || TREE_CODE (DECL_INITIAL (decl)) != STRING_CST)
+		    {
+		      if (DECL_SIZE (decl) == 0)
+			layout_decl (decl, 0);
+		      if (DECL_SIZE (decl) != 0)
+			size_tree = size_binop (CEIL_DIV_EXPR,
+						DECL_SIZE (decl),
+						size_int (BITS_PER_UNIT));
+		      if (DECL_SIZE (decl) == 0 ||
+			  TREE_CODE (size_tree) != INTEGER_CST)
+			{
+			  warning ("size of static variable in function must be fixed for bounds checking");
+			  goto no_check;
+			}
+		    }
+		  else
+		    {
+		      /* This is for string declarations like `static char
+		         p [] = "...";' where we can get the size (reliably?)
+		         from the type. */
+		      size_tree = TYPE_SIZE (TREE_TYPE (DECL_INITIAL (decl)));
+		      if (size_tree)
+			size_tree = size_binop (CEIL_DIV_EXPR,
+						size_tree,
+						size_int (BITS_PER_UNIT));
+		      if (!size_tree ||
+			  TREE_CODE (size_tree) != INTEGER_CST)
+			{
+			  warning ("size of static string variable in function must be fixed for bounds checking");
+			  goto no_check;
+			}
+		    }
+		  size = TREE_INT_CST_LOW (size_tree);
+		  if (TREE_INT_CST_HIGH (size_tree) != 0)
+		    {
+		      warning ("static variable in function is too large to bounds check");
+		      goto no_check;
+		    }
+		  if (size == 0)
+		    {
+		      /* Couldn't determine the size. Declarations like
+		         'static int i[] = {0,1,2};' are like this. To do
+		         this, look at 'output_constructor():total_bytes'
+		         which walks over such a constructor, finding its
+		         size. */
+		      warning ("static variable with no size cannot be bounds checked");
+		      goto no_check;
+		    }
+		  private_static
+		    = (struct private_statics_elem *)
+		    xmalloc (sizeof (struct private_statics_elem));
+		  private_static->name =
+		    obstack_copy0 (&permanent_obstack, name, strlen (name));
+		  private_static->label =
+	            obstack_copy0 (&permanent_obstack, label, strlen (label));
+		  private_static->size = size;
+		  private_static->next = private_statics_list;
+		  private_statics_list = private_static;
+
+		  no_check:
+		  ;
+		}
 	    }
 
 	  if (name == 0)
@@ -1378,6 +1467,12 @@ assemble_variable (decl, top_level, at_e
       /* Don't allocate zero bytes of common,
 	 since that means "undefined external" in the linker.  */
       if (size == 0) rounded = 1;
+      /* In bounds checking mode, pad with 1 byte afterwards. (RWMJ) */
+      if (bounds_checking_enabled) {
+	/* We will fix this in a moment ... */
+	size += BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+	rounded += BIGGEST_ALIGNMENT;
+      }
       /* Round size up to multiple of BIGGEST_ALIGNMENT bits
 	 so that each uninitialized object starts on such a boundary.  */
       rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
@@ -1490,6 +1585,11 @@ assemble_variable (decl, top_level, at_e
 #endif
 	      }
 	}
+
+      /* In bounds checking mode, we `fixed' size by adding 1 for padding,
+         earlier so subtract 1 again. (RWMJ) */
+      if (bounds_checking_enabled) size -= BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+
       goto finish;
     }
 
@@ -1615,7 +1715,20 @@ assemble_variable (decl, top_level, at_e
     {
 #ifdef ASM_DECLARE_OBJECT_NAME
       last_assemble_variable_decl = decl;
-      ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
+      if (bounds_checking_enabled
+          && TREE_TYPE(decl) != error_mark_node
+          && TYPE_SIZE (TYPE_MAIN_VARIANT (TREE_TYPE (decl))))
+        {
+          tree save_size = TYPE_SIZE (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
+          TYPE_SIZE (TYPE_MAIN_VARIANT (TREE_TYPE(decl))) =
+	    size_binop (PLUS_EXPR,
+		        TYPE_SIZE (TYPE_MAIN_VARIANT (TREE_TYPE (decl))),
+		        size_int(BIGGEST_ALIGNMENT));
+          ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
+          TYPE_SIZE (TYPE_MAIN_VARIANT (TREE_TYPE (decl))) = save_size;
+        }
+      else
+          ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
 #else
       /* Standard thing is just output label for the object.  */
       ASM_OUTPUT_LABEL (asm_out_file, name);
@@ -1630,6 +1743,11 @@ assemble_variable (decl, top_level, at_e
       else
 	/* Leave space for it.  */
 	assemble_zeros (TREE_INT_CST_LOW (size_tree));
+
+      /* In bounds checking mode, add a single byte of padding after the
+         variable. */
+      if (bounds_checking_enabled)
+	assemble_zeros (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
     }
 
  finish:
@@ -1693,6 +1811,87 @@ contains_pointers_p (type)
     }
 }
 
+/* In bounds checking mode, build a table at the end of the file containing
+   pointers and sizes of all private static data in the file. (RWMJ) */
+
+void
+assemble_private_statics_table ()
+{
+  struct private_statics_elem *p, *p_next;
+  rtx ptr_rtx, size_rtx, name_rtx;
+  int align, this_label_no = 0;
+  char label[256];
+
+  /* This table used to go in readonly_data_section, but unfortunately
+     this broke AIX on RS/6000 machines. The error message was `data adcons
+     in readonly sections' where (I presume) an `adcon' is an addressable
+     constant. Anyway, I've put this in the ordinary data section for
+     now. A correct solution probably involves looking at the `SELECT_
+     SECTION' macro. */
+/*  readonly_data_section (); */
+  data_section ();
+
+  /* Align it to the default alignment for integers. Take care not to align
+     bigger than the maximum the object file format will allow. Increase
+     alignment on machines that can benefit. */
+  align = BIGGEST_ALIGNMENT;
+#ifdef DATA_ALIGNMENT
+  align = DATA_ALIGNMENT (integer_type_node, align);
+#endif
+  if (align > BITS_PER_UNIT)
+    ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+
+  /* Write out the label for this object. */
+  ASM_OUTPUT_LABEL (asm_out_file, "__bounds_private_statics");
+
+  /* Write out the elements in the array, ie. a list of (label_pointer,
+     size, name_pointer). */
+  for (p = private_statics_list; p; p = p->next) {
+    /* Write a pointer to the object.  */
+    ptr_rtx = gen_rtx (SYMBOL_REF, Pmode, p->label);
+    assemble_integer ( ptr_rtx, POINTER_SIZE/BITS_PER_UNIT, 0);
+
+    /* Write the size of the object.  */
+    size_rtx = GEN_INT (p->size);
+    assemble_integer ( size_rtx, POINTER_SIZE/BITS_PER_UNIT, 0);
+
+    /* Write out a pointer to the object's name. We write the names out
+       afterwards. */
+    if (p->name != NULL)
+      {
+	p->name_label = this_label_no ++;
+	ASM_GENERATE_INTERNAL_LABEL (label, "LPS", p->name_label);
+	name_rtx = gen_rtx (SYMBOL_REF, Pmode, label);
+        assemble_integer ( name_rtx, POINTER_SIZE/BITS_PER_UNIT, 0);
+      }
+    else
+      {
+	assemble_integer ( const0_rtx, POINTER_SIZE/BITS_PER_UNIT, 0);
+      }	
+  }
+
+  /* NULL-terminate the array. */
+  assemble_integer ( const0_rtx, POINTER_SIZE/BITS_PER_UNIT, 0);
+  assemble_integer ( const0_rtx, POINTER_SIZE/BITS_PER_UNIT, 0);
+  assemble_integer ( const0_rtx, POINTER_SIZE/BITS_PER_UNIT, 0);
+
+  /* Write out the object names that we referred to in the above table. */
+  for (p = private_statics_list; p; p = p->next)
+    if (p->name != NULL)
+      {
+	ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPS", p->name_label);
+	assemble_string (p->name, strlen (p->name) + 1);
+      }
+
+  /* For completeness, free up this list. */
+  for (p = private_statics_list; p; p = p_next)
+    {
+      p_next = p->next;
+      free (p);
+    }
+  private_statics_list = NULL;
+}
+
 /* Output text storage for constructor CONSTR.  */
 
 void
@@ -3215,7 +3414,7 @@ output_constant_def_contents (exp, reloc
      int reloc;
      int labelno;
 {
-  int align;
+  int align, size;
 
   if (IN_NAMED_SECTION (exp))
     named_section (exp, NULL, reloc);
@@ -3255,11 +3454,73 @@ output_constant_def_contents (exp, reloc
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno);
 
   /* Output the value of EXP.  */
-  output_constant (exp,
-		   (TREE_CODE (exp) == STRING_CST
-		    ? TREE_STRING_LENGTH (exp)
-		    : int_size_in_bytes (TREE_TYPE (exp))));
+  size = TREE_CODE (exp) == STRING_CST		/* Calculate size in bytes. */
+    ? TREE_STRING_LENGTH (exp)
+    : int_size_in_bytes (TREE_TYPE (exp));
+  output_constant (exp, size);
+
+  /* In bounds checked mode, put a byte of padding after addressed
+     constants. Then add the assembler label and the (real) byte size to
+     a list. We will output this list as a private array at the end, so
+     we can pick up these static constants for checking. (RWMJ). */
+  if (bounds_checking_enabled)
+    {
+      struct private_statics_elem *private_static;
+      char label [256];
+
+      assemble_zeros (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
+      if (size != 0)
+	{
+	  private_static
+	    = (struct private_statics_elem *)
+	    xmalloc (sizeof (struct private_statics_elem));
+	  ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
+	  private_static->name = NULL;		/* Object has no name. */
+	  private_static->label =
+	    obstack_copy0 (&permanent_obstack, label, strlen (label));
+	  private_static->size = size;
+	  private_static->next = private_statics_list;
+	  private_statics_list = private_static;
+	}
+      else
+	warning ("cannot generate bounds checking code for zero sized static object");
+    }
+}
+
+/* Add external data definitions to the private_static list. Use a
+   negative size to flag this is an external data definition. */
+void
+bounds_external_declaration ( decl, len )
+    tree decl;
+    int len;
+{
+#if 1
+  int i;
+
+  for (i = 0 ; i < len ; i++, decl = TREE_CHAIN (decl)) {
 
+    if (TREE_CODE(decl) == VAR_DECL
+        && DECL_EXTERNAL (decl)
+        && TREE_USED(decl))
+      {
+        int size = int_size_in_bytes (TREE_TYPE (decl));
+
+        if (size > 0) {
+          struct private_statics_elem *private_static;
+          char *label = IDENTIFIER_POINTER (DECL_NAME (decl)) ;
+
+	  label = obstack_copy0 (&permanent_obstack, label, strlen (label));
+          private_static = (struct private_statics_elem *)
+			    xmalloc (sizeof (struct private_statics_elem));
+          private_static->name = label;
+          private_static->label = label;
+          private_static->size = -size;
+          private_static->next = private_statics_list;
+          private_statics_list = private_static;
+        }
+      }
+  }
+#endif
 }
 
 /* Similar hash facility for making memory-constants
@@ -4253,6 +4514,7 @@ bc_assemble_integer (exp, size)
     else
       abort ();		/* FIXME: there may be more cases.  */
 }
+
 
 /* Subroutine of output_constant, used for CONSTRUCTORs
    (aggregate constants).
