This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC - detect static data overruns


I'd like to get some general comments about whether or not the
following hack seems like something that should be cleaned up and
officially submitted for inclusion in gcc.

An extremely common problem is overrunning allocated memory, both
static and dynamic allocations.  There are tools that help with
dynamically allocated memory, such as Electric Fence, but I've not
seen much for helping to detect overruns in static data.

As it turns out, a very simple patch to gcc to put guard words with
known data patterns after every static allocation catches a lot of
these static data overruns.  Attached is a quickie patch I whipped up
to test this with a mips-elf toolchain, and it immediately found
dozens of overruns in the code base I'm working with.

If there's enough interest, I'll try to clean things up and submit
an official patch.

-Fred

============================================================================

Index: varasm.c
===================================================================
RCS file: /mips/newtools/fsf/gcc/gcc/varasm.c,v
retrieving revision 1.14
diff -c -p -r1.14 varasm.c
*** varasm.c	2003/07/30 06:39:05	1.14
--- varasm.c	2003/08/07 22:22:20
*************** assemble_variable (tree decl, int top_le
*** 1554,1559 ****
--- 1554,1572 ----
  	/* Leave space for it.  */
  	assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));
      }
+ 
+   /* This is a hack that needs to be cleaned up to use the appropriate
+      macros. */
+   if (flag_detect_static_data_overrun)
+     {
+       static int guardnum;
+       char buf[32];
+       sprintf (buf, "__guard%d", guardnum++);
+       ASM_OUTPUT_LABEL (asm_out_file, buf);
+       fputs ("\t.word\t0xdeadbeef\n", asm_out_file);
+       named_section (0, ".guard", 0);
+       fprintf (asm_out_file, "\t.word\t%s\n", buf);
+     }
  }
  
  /* Return 1 if type TYPE contains any pointers.  */
Index: common.opt
===================================================================
RCS file: /mips/newtools/fsf/gcc/gcc/common.opt,v
retrieving revision 1.2
diff -c -p -r1.2 common.opt
*** common.opt	2003/07/31 21:29:52	1.2
--- common.opt	2003/08/07 22:22:11
*************** fbounds-check
*** 227,232 ****
--- 227,236 ----
  Common
  Generate code to check bounds before indexing arrays
  
+ fdetect-static-data-overrun
+ Common
+ Generate guard words after static data allocations
+ 
  fbranch-count-reg
  Common
  Replace add, compare, branch with branch on count register
Index: flags.h
===================================================================
RCS file: /mips/newtools/fsf/gcc/gcc/flags.h,v
retrieving revision 1.13
diff -c -p -r1.13 flags.h
*** flags.h	2003/07/31 21:29:52	1.13
--- flags.h	2003/08/07 22:22:12
*************** extern int flag_guess_branch_prob;
*** 577,582 ****
--- 577,587 ----
     For Fortran: defaults to off.  */
  extern int flag_bounds_check;
  
+ /* -fdetect-static-data-overrun causes gcc to generate guard words
+    after all static data allocations, which can be used at runtime to
+    detect writing past the end of such allocations. */
+ extern int flag_detect_static_data_overrun;
+ 
  /* This will attempt to merge constant section constants, if 1 only
     string constants and constants from constant pool, if 2 also constant
     variables.  */
Index: libgcc-std.ver
===================================================================
RCS file: /mips/newtools/fsf/gcc/gcc/libgcc-std.ver,v
retrieving revision 1.6
diff -c -p -r1.6 libgcc-std.ver
*** libgcc-std.ver	2003/07/30 06:39:04	1.6
--- libgcc-std.ver	2003/08/07 22:22:12
*************** GCC_3.0 {
*** 141,146 ****
--- 141,149 ----
    __floattixf
    __floattitf
  
+   # Used to check guard words
+   __guard_check
+ 
    # Used to deal with trampoline initialization on some platforms
    __clear_cache
  
Index: libgcc2.c
===================================================================
RCS file: /mips/newtools/fsf/gcc/gcc/libgcc2.c,v
retrieving revision 1.5
diff -c -p -r1.5 libgcc2.c
*** libgcc2.c	2003/07/22 01:45:03	1.5
--- libgcc2.c	2003/08/07 22:22:13
*************** __eprintf (const char *string, const cha
*** 1543,1548 ****
--- 1543,1573 ----
  #endif
  
  
+ /* Check all the guard words, if any */
+ /* FIXME: This really belongs somewhere else ... */
+ #ifdef L_guard_check
+ 
+ #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
+ #include <stdio.h>
+ 
+ void
+ __guard_check (void)
+ {
+   extern int *__guards[];
+ 
+   int **guardpp;
+   for (guardpp = __guards; *guardpp; guardpp++)
+     {
+       if ((unsigned int) **guardpp != 0xdeadbeef)
+         {
+           fprintf (stderr, "GUARD ALERT: something overwrote guard%d at address 0x%x with 0x%x\n", guardpp-__guards, (unsigned int) *guardpp, **guardpp);
+ 	  fflush (stderr);
+         }
+     }
+ }
+ 
+ #endif	/* L_guard_check */
+ 
  #ifdef L_clear_cache
  /* Clear part of an instruction cache.  */
  
Index: libgcc2.h
===================================================================
RCS file: /mips/newtools/fsf/gcc/gcc/libgcc2.h,v
retrieving revision 1.4
diff -c -p -r1.4 libgcc2.h
*** libgcc2.h	2003/05/12 05:32:45	1.4
--- libgcc2.h	2003/08/07 22:22:13
*************** Software Foundation, 59 Temple Place - S
*** 31,36 ****
--- 31,37 ----
  #define GCC_LIBGCC2_H
  
  extern int __gcc_bcmp (const unsigned char *, const unsigned char *, size_t);
+ extern void __guard_check (void);
  extern void __clear_cache (char *, char *);
  extern void __eprintf (const char *, const char *, unsigned int, const char *)
    __attribute__ ((__noreturn__));
Index: mklibgcc.in
===================================================================
RCS file: /mips/newtools/fsf/gcc/gcc/mklibgcc.in,v
retrieving revision 1.6
diff -c -p -r1.6 mklibgcc.in
*** mklibgcc.in	2003/06/23 01:31:19	1.6
--- mklibgcc.in	2003/08/07 22:22:13
*************** echo
*** 47,53 ****
  lib2funcs='_muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3
  	_cmpdi2 _ucmpdi2 _floatdidf _floatdisf _fixunsdfsi _fixunssfsi
  	_fixunsdfdi _fixdfdi _fixunssfdi _fixsfdi _fixxfdi _fixunsxfdi
! 	_floatdixf _fixunsxfsi _fixtfdi _fixunstfdi _floatditf _clear_cache
  	_trampoline __main _absvsi2 _absvdi2 _addvsi3 _addvdi3
  	_subvsi3 _subvdi3 _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 _ctors
  	_ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab
--- 47,53 ----
  lib2funcs='_muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3
  	_cmpdi2 _ucmpdi2 _floatdidf _floatdisf _fixunsdfsi _fixunssfsi
  	_fixunsdfdi _fixdfdi _fixunssfdi _fixsfdi _fixxfdi _fixunsxfdi
! 	_floatdixf _fixunsxfsi _fixtfdi _fixunstfdi _floatditf _guard_check _clear_cache
  	_trampoline __main _absvsi2 _absvdi2 _addvsi3 _addvdi3
  	_subvsi3 _subvdi3 _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 _ctors
  	_ffssi2 _ffsdi2 _clz _clzsi2 _clzdi2 _ctzsi2 _ctzdi2 _popcount_tab
Index: opts.c
===================================================================
RCS file: /mips/newtools/fsf/gcc/gcc/opts.c,v
retrieving revision 1.2
diff -c -p -r1.2 opts.c
*** opts.c	2003/07/31 21:29:52	1.2
--- opts.c	2003/08/07 22:22:14
*************** common_handle_option (size_t scode, cons
*** 845,850 ****
--- 845,854 ----
        flag_bounds_check = value;
        break;
  
+     case OPT_fdetect_static_data_overrun:
+       flag_detect_static_data_overrun = value;
+       break;
+ 
      case OPT_fbranch_count_reg:
        flag_branch_on_count_reg = value;
        break;
Index: toplev.c
===================================================================
RCS file: /mips/newtools/fsf/gcc/gcc/toplev.c,v
retrieving revision 1.14
diff -c -p -r1.14 toplev.c
*** toplev.c	2003/07/31 21:29:52	1.14
--- toplev.c	2003/08/07 22:22:17
*************** int flag_guess_branch_prob = 0;
*** 946,951 ****
--- 946,956 ----
     For Fortran: defaults to off.  */
  int flag_bounds_check = 0;
  
+ /* -fdetect-static-data-overrun causes gcc to generate guard words
+    after all static data allocations, which can be used at runtime to
+    detect writing past the end of such allocations. */
+ int flag_detect_static_data_overrun = 0;
+ 
  /* This will attempt to merge constant section constants, if 1 only
     string constants and constants from constant pool, if 2 also constant
     variables.  */
*************** static const lang_independent_options f_
*** 1176,1181 ****
--- 1181,1187 ----
    {"unsafe-math-optimizations", &flag_unsafe_math_optimizations, 1 },
    {"signaling-nans", &flag_signaling_nans, 1 },
    {"bounds-check", &flag_bounds_check, 1 },
+   {"detect-static-data-overrun", &flag_detect_static_data_overrun, 1 },
    {"single-precision-constant", &flag_single_precision_constant, 1 },
    {"time-report", &time_report, 1 },
    {"mem-report", &mem_report, 1 },
Index: config/mips/crti.asm
===================================================================
RCS file: /mips/newtools/fsf/gcc/gcc/config/mips/crti.asm,v
retrieving revision 1.2
diff -c -p -r1.2 crti.asm
*** config/mips/crti.asm	2003/02/18 21:31:52	1.2
--- config/mips/crti.asm	2003/08/07 22:22:22
*************** _fini:
*** 24,26 ****
--- 24,31 ----
  	addu	$sp,$sp,-32
  	sw	$31,20($sp)
  #endif
+ 
+ 	.section .guard,"a",@progbits
+ 	.globl	__guards
+ __guards:
+ 	
Index: config/mips/crtn.asm
===================================================================
RCS file: /mips/newtools/fsf/gcc/gcc/config/mips/crtn.asm,v
retrieving revision 1.2
diff -c -p -r1.2 crtn.asm
*** config/mips/crtn.asm	2003/02/18 21:31:52	1.2
--- config/mips/crtn.asm	2003/08/07 22:22:22
***************
*** 27,29 ****
--- 27,31 ----
  #endif
  	j	RA
  
+ 	.section .guard,"a",@progbits
+ 	.word	0
Index: doc/invoke.texi
===================================================================
RCS file: /mips/newtools/fsf/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.15
diff -c -p -r1.15 invoke.texi
*** doc/invoke.texi	2003/07/31 21:29:52	1.15
--- doc/invoke.texi	2003/08/07 22:22:44
*************** in the following sections.
*** 682,688 ****
  -fargument-alias  -fargument-noalias @gol
  -fargument-noalias-global  -fleading-underscore @gol
  -ftls-model=@var{model} @gol
! -ftrapv  -fwrapv  -fbounds-check}
  @end table
  
  @menu
--- 682,688 ----
  -fargument-alias  -fargument-noalias @gol
  -fargument-noalias-global  -fleading-underscore @gol
  -ftls-model=@var{model} @gol
! -ftrapv  -fwrapv  -fbounds-check  -fdetect-static-data-overrun}
  @end table
  
  @menu
*************** For front-ends that support it, generate
*** 10995,11000 ****
--- 10995,11008 ----
  indices used to access arrays are within the declared range.  This is
  currently only supported by the Java and Fortran 77 front-ends, where
  this option defaults to true and false respectively.
+ 
+ @item -fdetect-static-data-overrun
+ @opindex fdetect-static-data-overrun
+ Add guard words after each initialized data variable, with a known
+ content that can be checked for writes past the end of the static data
+ allocation.  A runtime function, __guard_check, can be called at
+ anytime, either explicitly or through registration with atexit, to
+ check the contents of all guard words.
  
  @item -ftrapv
  @opindex ftrapv


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]