Prev: VirtualAlloc
Next: Endianness of padded scalar objects
From: lallous on 24 Feb 2010 07:25 Hello I have this code: #include <stdio.h> #include <stdarg.h> bool abc1( unsigned long &v1, unsigned long &v2, unsigned long &v3, ...) { va_list va; va_start(va, v3); printf("<abc1> "); for (int i=0;i<5;i++) { printf("%02x ", va_arg(va, int) & 0xff); } printf("</abc1>\n"); va_end(va); return true; } bool abc2( unsigned long v1, unsigned long v2, unsigned long v3, ...) { va_list va; va_start(va, v3); printf("<abc2> "); for (int i=0;i<5;i++) { printf("%02x ", va_arg(va, int) & 0xff); } printf("</abc2>\n"); va_end(va); return true; } int main() { unsigned long r1=0, r2=0, r3=0; abc1(r1, r2, r3, 0x54,0x01,0x00,0x00,0x00,0x58,0x05,0x00,0x00,0x00,0x28,0x02,0x00,0x00,0x00,0x16,0xff, 0xff,0xff,0xff,0xff); abc2(r1, r2, r3, 0x54,0x01,0x00,0x00,0x00,0x58,0x05,0x00,0x00,0x00,0x28,0x02,0x00,0x00,0x00,0x16,0xff, 0xff,0xff,0xff,0xff); return 0; } The only difference between abc1() and abc2() is that the first three arguments are passed by value or by reference. Now the output is different, when compiled: C:\Temp>cl32 abc.cpp & abc Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. abc.cpp Microsoft (R) Incremental Linker Version 9.00.30729.01 Copyright (C) Microsoft Corporation. All rights reserved. /out:abc.exe abc.obj <abc1> 00 00 88 94 01 </abc1> <abc2> 54 01 00 00 00 </abc2> Please advise. -- Elias
From: Igor Tandetnik on 24 Feb 2010 07:46 lallous wrote: > bool abc1( > unsigned long &v1, > unsigned long &v2, > unsigned long &v3, > ...) Your code exhibits undefined behavior: 18.7p3 ... The parameter parmN is the identifier of the rightmost parameter in the variable parameter list of the function definition (the one just before the ...). If the parameter parmN is declared with a function, array, or reference type, or with a type that is not compatible with the type that results when passing an argument for which there is no parameter, the behavior is undefined. As a practical matter, va_start(va, v3) takes an address of v3 and expects it to point into the stack where abc1's parameter list is. But when you take an address of a reference, you get the address of the referred-to value, not the address of the reference itself. So, instead of starting where v3 is on the stack and walking through the parameter list, abc1 is starting from where r3 is on the stack of main() and walking though whatever data just happens to sit above it on the stack. -- With best wishes, Igor Tandetnik With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925
From: lallous on 24 Feb 2010 08:43 Thanks Igor for the clarification. It seems g++ (GCC) 3.4.4 has no problem with that. -- Elias "Igor Tandetnik" <itandetnik(a)mvps.org> wrote in message news:#DQG19UtKHA.732(a)TK2MSFTNGP06.phx.gbl... > lallous wrote: >> bool abc1( >> unsigned long &v1, >> unsigned long &v2, >> unsigned long &v3, >> ...) > > Your code exhibits undefined behavior: > > 18.7p3 ... The parameter parmN is the identifier of the rightmost > parameter in the variable parameter list of the function definition (the > one just before the ...). If the parameter parmN is declared with a > function, array, or reference type, or with a type that is not compatible > with the type that results when passing an argument for which there is no > parameter, the behavior is undefined. > > As a practical matter, va_start(va, v3) takes an address of v3 and expects > it to point into the stack where abc1's parameter list is. But when you > take an address of a reference, you get the address of the referred-to > value, not the address of the reference itself. So, instead of starting > where v3 is on the stack and walking through the parameter list, abc1 is > starting from where r3 is on the stack of main() and walking though > whatever data just happens to sit above it on the stack. > -- > With best wishes, > Igor Tandetnik > > With sufficient thrust, pigs fly just fine. However, this is not > necessarily a good idea. It is hard to be sure where they are going to > land, and it could be dangerous sitting under them as they fly > overhead. -- RFC 1925
From: Igor Tandetnik on 24 Feb 2010 08:54 lallous wrote: > It seems g++ (GCC) 3.4.4 has no problem with that. "The program appears to work" is included in the range of undefined behavior. It appears GCC provides certain (non-standard) compiler intrinsics to help programs determine where named arguments end and variadic arguments begin: http://www.delorie.com/gnu/docs/gcc/gccint_135.html GCC's implementation of va_start uses these and ignores its second parameter. -- With best wishes, Igor Tandetnik With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925
|
Pages: 1 Prev: VirtualAlloc Next: Endianness of padded scalar objects |