This service will be undergoing maintenance at 00:00 UTC, 2016-09-28. It is expected to last about 1 hours
Bug 177706 - Constant argument of a function with variable length args is pushed as a 4-byte value instead of 8-byte
Constant argument of a function with variable length args is pushed as a 4-by...
Status: CLOSED NOTABUG
Product: Red Hat Enterprise Linux 3
Classification: Red Hat
Component: gcc (Show other bugs)
3.0
ia64 Linux
medium Severity medium
: ---
: ---
Assigned To: Jakub Jelinek
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2006-01-12 21:29 EST by Lego Haryanto
Modified: 2007-11-30 17:07 EST (History)
0 users

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2006-01-13 02:33:03 EST
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:


Attachments (Terms of Use)
C test code (508 bytes, text/plain)
2006-01-12 21:29 EST, Lego Haryanto
no flags Details
Assembly output of the same test.c (3.05 KB, text/plain)
2006-01-12 21:31 EST, Lego Haryanto
no flags Details

  None (edit)
Description Lego Haryanto 2006-01-12 21:29:42 EST
Description of problem:
The problem happens when dealing with a variable-arguments function, e.g.: int 
foo(int numArgs, ...);

When I call this foo function like the following (please note that we pass 
constants on all arguments):

foo(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);

On the later arguments (e.g.: 12 and 13), the constants are pushed as a 4-byte 
integer.  Since the elements in the stack are of 8-bytes, then there will be 4-
bytes with unknown value for those arguments.

When the callee (in this case, foo) treats the argument as a size_t (which is 
an 8-byte data type) via something like:

size_t value;

value = va_arg(args, size_t);

We'll see the problem that the value we got is possibly different with the one 
pushed to the stack earlier.

I'm attaching the test code (test.c) and the assembly output.


Version-Release number of selected component (if applicable):
gcc-3.2.3-42

How reproducible:
Everytime.

Steps to Reproduce:
1. Compile the attached code (I called it test.c) with: "gcc test.c" to 
produce a.out
2. Run "./a.out" and observe the output

  
Actual results:
sizeof size_t = 8
sizeof long = 8
col: 0 -> arg: 1
col: 1 -> arg: 2
col: 2 -> arg: 3
col: 3 -> arg: 4
col: 4 -> arg: 5
col: 5 -> arg: 6
col: 6 -> arg: 7
col: 7 -> arg: 8
col: 8 -> arg: 9
col: 9 -> arg: a
col: 10 -> arg: b
col: 11 -> arg: 200000000000000c
col: 12 -> arg: 200000000000000d

(please note that the extra 200000000000000 on 11 and 12 doesn't necessarily 
have to be the same value).


Expected results:
sizeof size_t = 8
sizeof long = 8
col: 0 -> arg: 1
col: 1 -> arg: 2
col: 2 -> arg: 3
col: 3 -> arg: 4
col: 4 -> arg: 5
col: 5 -> arg: 6
col: 6 -> arg: 7
col: 7 -> arg: 8
col: 8 -> arg: 9
col: 9 -> arg: a
col: 10 -> arg: b
col: 11 -> arg: c
col: 12 -> arg: d


Additional info:
One can argue that the behavior is expected, but if we look closely at the 
assembly output, it's obvious that the compiler sometimes treats it as a 4-
byte push, and other times it treats it as an 8-byte (via general purpose 
registers).
Please also take a look at the produce assembly output.
Comment 1 Lego Haryanto 2006-01-12 21:29:42 EST
Created attachment 123147 [details]
C test code
Comment 2 Lego Haryanto 2006-01-12 21:31:04 EST
Created attachment 123148 [details]
Assembly output of the same test.c
Comment 3 Jakub Jelinek 2006-01-13 02:33:03 EST
GCC behavior matches the IA-64 ABI, your testcase is buggy.
The constants you are passing to the function have int type, not size_t
or long, so if you use va_arg (ap, size_t), the behaviour is undefined.
If you want to read the values as size_t arguments, you need to make sure they
are passed with those types, i.e. either
foo (2, (size_t) 1, (size_t) 34);
or e.g.
foo (2, 1L, 34L);
(the former is portable, the latter will work on IA-64 where you know
size_t and long are the same size, and will work e.g. on all ILP32 and LP64
Linux targets, but there might be some weirdo targets where sizeof (size_t) !=
sizeof (long); still, sizeof (size_t) == sizeof (long) is pretty common, while
sizeof (size_t) != sizeof (int) is true on many targets).

Note You need to log in before you can comment on or make changes to this bug.