Bug 19491 - va_start incorrect, Number of floating point and integer registers counted incorrectly
Summary: va_start incorrect, Number of floating point and integer registers counted in...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 3.3.4
: P3 minor
Target Milestone: 4.0.0
Assignee: David Edelsohn
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2005-01-17 21:13 UTC by Suriya Narayanan M S
Modified: 2005-01-22 03:24 UTC (History)
1 user (show)

See Also:
Host: powerpc-gnu-linux
Target: powerpc-gnu-linux
Build:
Known to work:
Known to fail: 3.3.3 3.4.3 4.0.0
Last reconfirmed: 2005-01-21 22:38:22


Attachments
Test case, should return success (1.31 KB, text/plain)
2005-01-20 18:05 UTC, Suriya Narayanan M S
Details
rs6000_va_start patch (534 bytes, patch)
2005-01-21 22:39 UTC, David Edelsohn
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Suriya Narayanan M S 2005-01-17 21:13:53 UTC
I couldn't find a description of Host, Target and Build Triplet inside
gcc.gnu.org.

Here is my gcc version

$ gcc -v
Reading specs from /usr/lib/gcc-lib/powerpc-linux/3.3.4/specs
Configured with: ../src/configure -v
--enable-languages=c,c++,java,f77,pascal,objc,ada --prefix=/usr
--mandir=/usr/share/man --infodir=/usr/share/info
--with-gxx-include-dir=/usr/include/c++/3.3 --enable-shared --with-system-zlib
--enable-nls --without-included-gettext --enable-__cxa_atexit
--enable-clocale=gnu --enable-debug --enable-java-gc=boehm
--enable-java-awt=xlib --enable-objc-gc --disable-multilib powerpc-linux
Thread model: posix
gcc version 3.3.4 (Debian 1:3.3.4-2)

The function rs6000_va_start() in gcc/gcc/config/rs6000/rs6000.c incorrectly
sets va_list.gpr (and fpr). gpr should have a maximum value equal to the number
of integer registers available for parameter passing. If gpr takes greater
number of values, this results in a wraparound, as in the example below, where
256 integer parameters are passed.

I don't know if I looking at the correct function corresponding to the target,
but the bug exists. Using gdb and inspecting the va_list after the va_start
function shows that va_list.gpr wraps around.

The preprocessed file is (also) available at
http://www.cs.utexas.edu/users/suriya/va_list.i

# 1 "va_list.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "va_list.c"
# 1 "/usr/lib/gcc-lib/powerpc-linux/3.3.4/include/stdarg.h" 1 3 4
# 43 "/usr/lib/gcc-lib/powerpc-linux/3.3.4/include/stdarg.h" 3 4
typedef __builtin_va_list __gnuc_va_list;
# 105 "/usr/lib/gcc-lib/powerpc-linux/3.3.4/include/stdarg.h" 3 4
typedef __gnuc_va_list va_list;
# 2 "va_list.c" 2

int foo(
        int a0x00, int a0x01, int a0x02, int a0x03, int a0x04, int a0x05, int
a0x06, int a0x07,
        int a0x08, int a0x09, int a0x0a, int a0x0b, int a0x0c, int a0x0d, int
a0x0e, int a0x0f,
        int a0x10, int a0x11, int a0x12, int a0x13, int a0x14, int a0x15, int
a0x16, int a0x17,
        int a0x18, int a0x19, int a0x1a, int a0x1b, int a0x1c, int a0x1d, int
a0x1e, int a0x1f,
        int a0x20, int a0x21, int a0x22, int a0x23, int a0x24, int a0x25, int
a0x26, int a0x27,
        int a0x28, int a0x29, int a0x2a, int a0x2b, int a0x2c, int a0x2d, int
a0x2e, int a0x2f,
        int a0x30, int a0x31, int a0x32, int a0x33, int a0x34, int a0x35, int
a0x36, int a0x37,
        int a0x38, int a0x39, int a0x3a, int a0x3b, int a0x3c, int a0x3d, int
a0x3e, int a0x3f,
        int a0x40, int a0x41, int a0x42, int a0x43, int a0x44, int a0x45, int
a0x46, int a0x47,
        int a0x48, int a0x49, int a0x4a, int a0x4b, int a0x4c, int a0x4d, int
a0x4e, int a0x4f,
        int a0x50, int a0x51, int a0x52, int a0x53, int a0x54, int a0x55, int
a0x56, int a0x57,
        int a0x58, int a0x59, int a0x5a, int a0x5b, int a0x5c, int a0x5d, int
a0x5e, int a0x5f,
        int a0x60, int a0x61, int a0x62, int a0x63, int a0x64, int a0x65, int
a0x66, int a0x67,
        int a0x68, int a0x69, int a0x6a, int a0x6b, int a0x6c, int a0x6d, int
a0x6e, int a0x6f,
        int a0x70, int a0x71, int a0x72, int a0x73, int a0x74, int a0x75, int
a0x76, int a0x77,
        int a0x78, int a0x79, int a0x7a, int a0x7b, int a0x7c, int a0x7d, int
a0x7e, int a0x7f,
        int a0x80, int a0x81, int a0x82, int a0x83, int a0x84, int a0x85, int
a0x86, int a0x87,
        int a0x88, int a0x89, int a0x8a, int a0x8b, int a0x8c, int a0x8d, int
a0x8e, int a0x8f,
        int a0x90, int a0x91, int a0x92, int a0x93, int a0x94, int a0x95, int
a0x96, int a0x97,
        int a0x98, int a0x99, int a0x9a, int a0x9b, int a0x9c, int a0x9d, int
a0x9e, int a0x9f,
        int a0xa0, int a0xa1, int a0xa2, int a0xa3, int a0xa4, int a0xa5, int
a0xa6, int a0xa7,
        int a0xa8, int a0xa9, int a0xaa, int a0xab, int a0xac, int a0xad, int
a0xae, int a0xaf,
        int a0xb0, int a0xb1, int a0xb2, int a0xb3, int a0xb4, int a0xb5, int
a0xb6, int a0xb7,
        int a0xb8, int a0xb9, int a0xba, int a0xbb, int a0xbc, int a0xbd, int
a0xbe, int a0xbf,
        int a0xc0, int a0xc1, int a0xc2, int a0xc3, int a0xc4, int a0xc5, int
a0xc6, int a0xc7,
        int a0xc8, int a0xc9, int a0xca, int a0xcb, int a0xcc, int a0xcd, int
a0xce, int a0xcf,
        int a0xd0, int a0xd1, int a0xd2, int a0xd3, int a0xd4, int a0xd5, int
a0xd6, int a0xd7,
        int a0xd8, int a0xd9, int a0xda, int a0xdb, int a0xdc, int a0xdd, int
a0xde, int a0xdf,
        int a0xe0, int a0xe1, int a0xe2, int a0xe3, int a0xe4, int a0xe5, int
a0xe6, int a0xe7,
        int a0xe8, int a0xe9, int a0xea, int a0xeb, int a0xec, int a0xed, int
a0xee, int a0xef,
        int a0xf0, int a0xf1, int a0xf2, int a0xf3, int a0xf4, int a0xf5, int
a0xf6, int a0xf7,
        int a0xf8, int a0xf9, int a0xfa, int a0xfb, int a0xfc, int a0xfd, int
a0xfe, int a0xff,
        ...)
{
    va_list list;
    int i;
    __builtin_va_start(list,a0xff);
    i = __builtin_va_arg(list,int);
    return i;
}

int main()
{
    return foo(
        689 + 0x00, 689 + 0x01, 689 + 0x02, 689 + 0x03, 689 + 0x04, 689 + 0x05,
689 + 0x06, 689 + 0x07,
        689 + 0x08, 689 + 0x09, 689 + 0x0a, 689 + 0x0b, 689 + 0x0c, 689 + 0x0d,
689 + 0x0e, 689 + 0x0f,
        689 + 0x10, 689 + 0x11, 689 + 0x12, 689 + 0x13, 689 + 0x14, 689 + 0x15,
689 + 0x16, 689 + 0x17,
        689 + 0x18, 689 + 0x19, 689 + 0x1a, 689 + 0x1b, 689 + 0x1c, 689 + 0x1d,
689 + 0x1e, 689 + 0x1f,
        689 + 0x20, 689 + 0x21, 689 + 0x22, 689 + 0x23, 689 + 0x24, 689 + 0x25,
689 + 0x26, 689 + 0x27,
        689 + 0x28, 689 + 0x29, 689 + 0x2a, 689 + 0x2b, 689 + 0x2c, 689 + 0x2d,
689 + 0x2e, 689 + 0x2f,
        689 + 0x30, 689 + 0x31, 689 + 0x32, 689 + 0x33, 689 + 0x34, 689 + 0x35,
689 + 0x36, 689 + 0x37,
        689 + 0x38, 689 + 0x39, 689 + 0x3a, 689 + 0x3b, 689 + 0x3c, 689 + 0x3d,
689 + 0x3e, 689 + 0x3f,
        689 + 0x40, 689 + 0x41, 689 + 0x42, 689 + 0x43, 689 + 0x44, 689 + 0x45,
689 + 0x46, 689 + 0x47,
        689 + 0x48, 689 + 0x49, 689 + 0x4a, 689 + 0x4b, 689 + 0x4c, 689 + 0x4d,
689 + 0x4e, 689 + 0x4f,
        689 + 0x50, 689 + 0x51, 689 + 0x52, 689 + 0x53, 689 + 0x54, 689 + 0x55,
689 + 0x56, 689 + 0x57,
        689 + 0x58, 689 + 0x59, 689 + 0x5a, 689 + 0x5b, 689 + 0x5c, 689 + 0x5d,
689 + 0x5e, 689 + 0x5f,
        689 + 0x60, 689 + 0x61, 689 + 0x62, 689 + 0x63, 689 + 0x64, 689 + 0x65,
689 + 0x66, 689 + 0x67,
        689 + 0x68, 689 + 0x69, 689 + 0x6a, 689 + 0x6b, 689 + 0x6c, 689 + 0x6d,
689 + 0x6e, 689 + 0x6f,
        689 + 0x70, 689 + 0x71, 689 + 0x72, 689 + 0x73, 689 + 0x74, 689 + 0x75,
689 + 0x76, 689 + 0x77,
        689 + 0x78, 689 + 0x79, 689 + 0x7a, 689 + 0x7b, 689 + 0x7c, 689 + 0x7d,
689 + 0x7e, 689 + 0x7f,
        689 + 0x80, 689 + 0x81, 689 + 0x82, 689 + 0x83, 689 + 0x84, 689 + 0x85,
689 + 0x86, 689 + 0x87,
        689 + 0x88, 689 + 0x89, 689 + 0x8a, 689 + 0x8b, 689 + 0x8c, 689 + 0x8d,
689 + 0x8e, 689 + 0x8f,
        689 + 0x90, 689 + 0x91, 689 + 0x92, 689 + 0x93, 689 + 0x94, 689 + 0x95,
689 + 0x96, 689 + 0x97,
        689 + 0x98, 689 + 0x99, 689 + 0x9a, 689 + 0x9b, 689 + 0x9c, 689 + 0x9d,
689 + 0x9e, 689 + 0x9f,
        689 + 0xa0, 689 + 0xa1, 689 + 0xa2, 689 + 0xa3, 689 + 0xa4, 689 + 0xa5,
689 + 0xa6, 689 + 0xa7,
        689 + 0xa8, 689 + 0xa9, 689 + 0xaa, 689 + 0xab, 689 + 0xac, 689 + 0xad,
689 + 0xae, 689 + 0xaf,
        689 + 0xb0, 689 + 0xb1, 689 + 0xb2, 689 + 0xb3, 689 + 0xb4, 689 + 0xb5,
689 + 0xb6, 689 + 0xb7,
        689 + 0xb8, 689 + 0xb9, 689 + 0xba, 689 + 0xbb, 689 + 0xbc, 689 + 0xbd,
689 + 0xbe, 689 + 0xbf,
        689 + 0xc0, 689 + 0xc1, 689 + 0xc2, 689 + 0xc3, 689 + 0xc4, 689 + 0xc5,
689 + 0xc6, 689 + 0xc7,
        689 + 0xc8, 689 + 0xc9, 689 + 0xca, 689 + 0xcb, 689 + 0xcc, 689 + 0xcd,
689 + 0xce, 689 + 0xcf,
        689 + 0xd0, 689 + 0xd1, 689 + 0xd2, 689 + 0xd3, 689 + 0xd4, 689 + 0xd5,
689 + 0xd6, 689 + 0xd7,
        689 + 0xd8, 689 + 0xd9, 689 + 0xda, 689 + 0xdb, 689 + 0xdc, 689 + 0xdd,
689 + 0xde, 689 + 0xdf,
        689 + 0xe0, 689 + 0xe1, 689 + 0xe2, 689 + 0xe3, 689 + 0xe4, 689 + 0xe5,
689 + 0xe6, 689 + 0xe7,
        689 + 0xe8, 689 + 0xe9, 689 + 0xea, 689 + 0xeb, 689 + 0xec, 689 + 0xed,
689 + 0xee, 689 + 0xef,
        689 + 0xf0, 689 + 0xf1, 689 + 0xf2, 689 + 0xf3, 689 + 0xf4, 689 + 0xf5,
689 + 0xf6, 689 + 0xf7,
        689 + 0xf8, 689 + 0xf9, 689 + 0xfa, 689 + 0xfb, 689 + 0xfc, 689 + 0xfd,
689 + 0xfe, 689 + 0xff,
            5555) - 5555;
}
Comment 1 David Edelsohn 2005-01-20 16:07:29 UTC
GCC 3.3 used the magic number of 1000 when initializing the number of 
arguments.  This bug report does not state the exact failure mode of the 
example, but the slightly greater than 1000 words (256 arguments) might 
interact incorrectly with the magic value 1000.  The use of "1000" was removed 
in GCC 3.4, so I would recommend retesting with that GCC release.  The lack of 
description about the failure makes it difficult for anyone else to confirm 
the report or test if the problem already is corrected.
Comment 2 Suriya Narayanan M S 2005-01-20 18:05:38 UTC
Created attachment 8022 [details]
Test case, should return success
Comment 3 Suriya Narayanan M S 2005-01-20 18:07:36 UTC
(In reply to comment #1)
> GCC 3.3 used the magic number of 1000 when initializing the number of 
> arguments.  This bug report does not state the exact failure mode of the 
> example, but the slightly greater than 1000 words (256 arguments) might 
> interact incorrectly with the magic value 1000.  The use of "1000" was removed 
> in GCC 3.4, so I would recommend retesting with that GCC release.  The lack of 
> description about the failure makes it difficult for anyone else to confirm 
> the report or test if the problem already is corrected.


The same problem exists with GCC 3.4.

Let me restate the problem. va_start(va_list, param) sets fields { gpr, fpr,
overflow_arg_area, reg_save_area } in the va_list structure. `gpr' is an index
into the reg_save_area. Parameters are passed into integer registers r3 through
r10. So, the index into the integer portion of reg_save_area (where the 8
integer registers, followed by the floating point registers are saved) should be
between 0 and 7 (both inclusive) to be meaningful. Any value greater than 7
indicates that the next parameter is not in the integer save area but in
overflow_arg_area.

For example, if the function was int foo(int a0, int a1, ...), then gpr would be
2, to indicate that the next integer parameter (afdter a1) is in offset 2 (the
parameter was passed in r5) of the reg_save_area.

For example, if the function was int foo(int a0, int a1, int a2, int a3, int a4,
int a5, int a6, int a7, ...), then gpr would be 8. This means that this is an
offset greater than 7 and as a result the next integer parameter (passed after
a7) is inthe overflow_arg_area.

For example, if the function was foo(int a0, int a1, int a2, int a3, int a4, int
a5, int a6, int a7, int a8, ...), then gprturns out to be be 9 (confirmed using
 gdb). This is again a value greater than 7 indicating that the next integer
parameter (passed after a8) is in the overflow_arg_area.

va_arg which gets the next argument, compares gpr to 8 to decide from which area
the load the parameter from.

In the above examples, gpr is not bound to a maximum value of 8, but instead
increments for each additional argument. gpr is of type char. As a result, if
there are 256 parameters before the ellipsis '...', gpr takes a value 0 (due to
overflow). This, incorrectly indicates (because va_arg compares gpr to 8, and 0
< 8) that the parameter is in the reg_save_area, though in reality, the
parameter is in the overflow_arg_area.

The test program I sent, had 256 parameters followed by the ellipsis.
va_arg(list, int) should give the value of the 257th parameter (counting from
one), which is 5555 (in the example, the last argument passed by main). The
program should return success, however it doesn't, because of incorrect setting
of gpr in va_start.
Comment 4 David Edelsohn 2005-01-21 02:52:30 UTC
PowerPC SVR4 va_arg bug.
Comment 5 David Edelsohn 2005-01-21 22:39:33 UTC
Created attachment 8035 [details]
rs6000_va_start patch
Comment 6 GCC Commits 2005-01-22 03:09:48 UTC
Subject: Bug 19491

CVSROOT:	/cvs/gcc
Module name:	gcc
Changes by:	dje@gcc.gnu.org	2005-01-22 03:09:31

Modified files:
	gcc            : ChangeLog 
	gcc/config/rs6000: rs6000.c 

Log message:
	2005-01-20  David Edelsohn  <edelsohn@gnu.org>
	Andrew Pinski  <pinskia@physics.uc.edu>
	
	PR target/19491
	* config/rs6000/rs6000.c (rs6000_va_start): Saturate n_gpr at
	maximum number of GPRs.  Saturate n_fpr at maximum number of FPRs.

Patches:
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&r1=2.7225&r2=2.7226
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/config/rs6000/rs6000.c.diff?cvsroot=gcc&r1=1.780&r2=1.781

Comment 7 David Edelsohn 2005-01-22 03:24:11 UTC
Patch committed.
This is not a regression, so it will not be fixed on earlier branches.