"[PATCH] cc1/f771 array overrun - x86 Floating Point"

Donn Terry donnte@microsoft.com
Wed Jul 5 16:18:00 GMT 2000


This patch reflects an (at least partly) asymtomatic bug.  An out of
bounds array access is occurring with reasonable regularity.  In my
situation, upon occasion the access causes a SIGSEGV, just due to the
accidents of memory layout.  Otherwise, the access appears to be
benign, in that it seems to have no negative effect that I've detected,
but since I'm not sure what the variable involved is being used for,
I can't say for sure.

However, if the value used from the array access CAN cause problems
occasionally, it could lead to some really nasty, hard to find,
bugs.  Minimally, this at least eliminiates that possibility.

This shows up on the x86; presumably all versions as I don't have
any patches in the code I'm testing that should affect this.
It (see below) appears to be floating point related, although
when I first ran across it, it seemed to be related to templates.
(I suspect that the "template" variation may have been fixed
in the meantime, in that I don't see it where I originally did.)

The array involved is calloc()ed, based upon the current number of
insns.  Most of the uses are before code that can increase the number
of insns, but in one case it's used after the number of insns is
increased.

All the patch below does is range check the access and provide a zero
instead of the random memory that would be used (if SIGSEGV did not
occur).  I have also included a commented-out printf() which will
give those who understand this code better an idea of how often
and where this occurs.

Here's a partial list of places I've observed the problem. 

libgcc/_fixunsdfsi.o (from libgcc2.c)
libgcc/_fixunssfsi.o (from libgcc2.c)
libgcc/_fixdfdi.o (from libgcc2.c)
libgcc/_fixunsdfdi.o (from libgcc2.c) (4x)
libgcc/_fixunssfdi.o (from libgcc2.c) (4x)
libgcc/_fixsfdi.o (from libgcc2.c)
libgcc/_fixxfdi.o (from libgcc2.c)
libgcc/_fixunsxfdi.o (from libgcc2.c) (5x)

libiberty/floatformat.c (3x)

libf2c/libU77/u77-test.f (4x)

whatever gdb/testsuite/gdb.base/call-ar-st.exp causes to be compiled.
whatever gdb/testsuite/gdb.base/call-rt-st.exp causes to be compiled.
whatever gdb/testsuite/gdb.base/callfuncs.exp causes to be compiled. (many
x)
whatever gdb/testsuite/gdb.base/callfwmall.exp causes to be compiled. (many
x)
whatever gdb/testsuite/gdb.base/funcargs.exp causes to be compiled. (many x)
whatever gdb/testsuite/gdb.base/varargs.exp causes to be compiled. (2 x)
whatever gdb/testsuite/gdb.c++/method.exp causes to be compiled.

tcl/generic/tclTest.c (3x)
tcl/generic/tclBasic.c (2x)
tcl/generic/tclBinary.c (2x)
tcl/generic/tclCmdIL.c (2x)
tcl/generic/tclExecute.c (many x)
tcl/generic/tclLink.c
tcl/generic/tclObj.c

tk/generic/tkGet.c
tk/generic/tkPlace.c (4x)
tk/unix/tkUnixColor.c
tk/unix/tkUnixScale.c (many x)
tk/generic/tkLixtBox.c (4 x)
tk/generic/tkScale.c (many x)
tk/generic/tkScrollbar.c (many x)
tk/generic/tkCanvas.c (many x)
tk/generic/tkCanvArc.c (many,many x)
tk/generic/tkCanvBmap.c (many x)
tk/generic/tkCanvImage.c (many x)
tk/generic/tkCanvLine.c (many x)
tk/generic/tkCanvPoly.c (3 x)
tk/generic/tkCanvPs.c 
tk/generic/tkCanvText.c (2 x)
tk/generic/tkCanvUtil.c (many x)
tk/generic/tkCanvWind.c (many x)
tk/generic/tkRectOval.c (many x)
tk/generic/tkTrig.c (many,many x)
tk/generic/tkImgPhoto.c (many x)
tk/generic/tkTextDisp.c (many x)

(Given what I infer that most of the files are doing above, I have
to suspect that this is related to x86 floating point stuff.)

Here's a pretty small testcase that still exhibits the problem
(causes the printf to occur).  This certainly confirms that it's
FP related, although whether it's exclusively FP related remains
to be seen.

    int
    __fixunsdfSI (double a)
    {
      return a > 1234567.0;
    }


Details:
insn_addresses was allocated based on get_max_uid() when shorten_branches
was called by toplev.c.  However, due to the call to reg_to_stack() which
follows the call in toplev.c, additional UIDs have been allocated and access
to insn_addresses off the end of the calloc()d space is made at the point
of the patch.

This appears to be related to a change made in roughly February
to toplev.c where the order of reg_to_stack() and shorten_branches()
was reversed due to problems for the ia32 backend.


This is clearly not the "right" fix, but, since the comment in
toplev.c indicates that that change might be temporary it might be
a good corresponding temporary fix until the final fix (whatever
it is) is made.  (See line 3555 of toplev.c.)

At least it may make some future misbehavior repeatable.

(Properly, this should be an ASSERT, but I suspect that it would
NOT prove a popular choice until the underlying problem is fixed.)


diff -drupP --exclude-from=//M/donn/diffs/exclude.files
//S/CVS/egcs.baseline/gcc/final.c gcc/final.c
--- //S/CVS/egcs.baseline/gcc/final.c	Mon Jan 31 11:29:48 2000
+++ gcc/final.c	Tue Feb  8 14:07:35 2000
@@ -2025,6 +2025,13 @@ final (first, file, optimize, prescan)
   for (insn = NEXT_INSN (first); insn;)
     {
 #ifdef HAVE_ATTR_length
+      if (INSN_UID(insn) >= insn_lengths_max_uid)
+        {
+          /* Caused by move of shorten_branches() in toplev.c */
+          insn_current_address = 0;
+	   /* fprintf(stderr, "Out of range access\n"); */
+        }
+      else
       insn_current_address = insn_addresses[INSN_UID (insn)];
 #endif
       insn = final_scan_insn (insn, file, optimize, prescan, 0);


More information about the Gcc-bugs mailing list