Red Hat Bugzilla – Bug 177706
Constant argument of a function with variable length args is pushed as a 4-byte value instead of 8-byte
Last modified: 2007-11-30 17:07:09 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.
Created attachment 123147 [details] C test code
Created attachment 123148 [details] Assembly output of the same test.c
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).