Hello everyone,
I encountered a curious behavior regarding va_arg
using x86_64-w64-mingw32.shared-gcc
with the following configuration (built from within a Docker MXE container) :
root@68e497122072:/work/BUILD.win64# /usr/src/mxe/usr/bin/x86_64-w64-mingw32.shared-gcc -v Reading specs from /usr/src/mxe/usr/lib/gcc/x86_64-w64-mingw32.shared/7.5.0/specs COLLECT_GCC=/usr/src/mxe/usr/bin/x86_64-w64-mingw32.shared-gcc COLLECT_LTO_WRAPPER=/usr/src/mxe/usr/libexec/gcc/x86_64-w64-mingw32.shared/7.5.0/lto-wrapper Target: x86_64-w64-mingw32.shared Configured with: /usr/src/mxe/tmp-gcc-x86_64-w64-mingw32.shared/gcc-7.5.0/configure ac_cv_prog_HAVE_DOXYGEN=false --enable-doc=no --enable-gtk-doc=no --enable-gtk-doc-html=no --enable-gtk-doc-pdf=no --docdir=/usr/src/mxe/tmp-gcc-x86_64-w64-mingw32.shared/gcc-7.5.0.build_.sink --infodir=/usr/src/mxe/tmp-gcc-x86_64-w64-mingw32.shared/gcc-7.5.0.build_.sink --mandir=/usr/src/mxe/tmp-gcc-x86_64-w64-mingw32.shared/gcc-7.5.0.build_.sink --with-html-dir=/usr/src/mxe/tmp-gcc-x86_64-w64-mingw32.shared/gcc-7.5.0.build_.sink --disable-doxygen --target=x86_64-w64-mingw32.shared --build=x86_64-pc-linux-gnu --prefix=/usr/src/mxe/usr --libdir=/usr/src/mxe/usr/lib --with-sysroot=/usr/src/mxe/usr/x86_64-w64-mingw32.shared --enable-languages=c,c++,objc,fortran --enable-version-specific-runtime-libs --with-gcc --with-gnu-ld --with-gnu-as --disable-nls --disable-multilib --without-x --disable-win32-registry --enable-threads=posix --enable-default-ssp --enable-libgomp --with-gmp=/usr/src/mxe/usr/x86_64-pc-linux-gnu --with-isl=/usr/src/mxe/usr/x86_64-pc-linux-gnu --with-mpc=/usr/src/mxe/usr/x86_64-pc-linux-gnu --with-mpfr=/usr/src/mxe/usr/x86_64-pc-linux-gnu --with-as=/usr/src/mxe/usr/bin/x86_64-w64-mingw32.shared-as --with-ld=/usr/src/mxe/usr/bin/x86_64-w64-mingw32.shared-ld --with-nm=/usr/src/mxe/usr/bin/x86_64-w64-mingw32.shared-nm Thread model: posix gcc version 7.5.0 (GCC)
The problem appears to be that a va_arg
argument gets messed up when passing through embedded/inner function calls. Here is a sample code to illustrate the issue:
#include <stdarg.h> #include <stdio.h> /* foo(12) -> 24 */ int foo(va_list va) { int value_int = va_arg(va, int); return value_int * 2; } /* bar(12, 64) -> 24+128 -> 152 */ int bar(va_list va) { int value_int = 0; int value_foo = foo(va); value_int = va_arg(va, int); return value_foo + value_int * 2; } /* foobar(<whatever>, 12, 64) -> 152 */ int foobar(int unused, ...) { va_list va; int value = 0; va_start(va, unused); value = bar(va); va_end(va); return value; } int main(void) { int value = foobar(0, 12, 64); #define RESULT (12*2 + 64*2) printf("foobar=%d (%s)\n", value, value == RESULT ? "ok" : "ko"); return value != RESULT; }
From my tests with "native" gcc on my distribution (Arch) I get the right result everytime (I don't have any gcc 7 currently available for installation):
$ gcc sample-va_list.c -o sample-va_list-v10 ./sample-va_list-v10 foobar=152 (ok) $ gcc-9 sample-va_list.c -o sample-va_list-v9 ./sample-va_list-v9 foobar=152 (ok) $ gcc-8 sample-va_list.c -o sample-va_list-v8 $ ./sample-va_list-v8 foobar=152 (ok)
While with mingw:
root@68e497122072:/work/BUILD.win64# /usr/src/mxe/usr/bin/x86_64-w64-mingw32.shared-gcc sample-va_list.c -o sample-va_list.exe $ wine ./sample-va_list.exe foobar=48 (ko)
Did anyone ever cross this case ? I don't see any mention of this kind of usage in the manual page, so I assumed it is a legit use.
What do you think ?
Regards
Hello,
Sorry for telling you, but your assumptions about passing va_list as
argument, and how it behalfs is plain wrong. So your test-code is
invalid. Why you assume that a local variable va is modified under
the hood by a different function? As long as you don't pass reference
to it, you are not able to modify its contents for an outer function.
int foo(va_list argp)
{
return va_arg(argp, int);
}
void zoo(const char *fmt, ...)
{
va_list argp;
argp=va_start(argp, fmt);
fprintf(stderr, fmt, foo(argp), foo(argp));
}
int main()
{
zoo("%d", 12, 64);
return 0;
}
will of course display 24, and not - as you were assuming - 76. Btw
it is absolutely irrelevant how many subs you are putting here
inbetween of zoo and foo ...
Cheers,
Kai
Am Mo., 28. Sept. 2020 um 01:56 Uhr schrieb zaghp zaghp@users.sourceforge.net:
Related
Bugs: #856
Hi
Thank you for the reply.
That's interresting, as soon as I read that line I was like "what an idiot".
But then, I realized that the issue here was actually the misleading gcc/libc/... from my distribution because, well it "works" even though I'm passing the va_list as an argument and not as a reference (I mean, the example using gcc-8 and others were "real"). I assume the pointer/reference is handled under the hood in that particular case while I should not assume that but that's what lead me to believe what I was doing was right, my bad.
Indeed, only if the fprintf line is
fprintf(stderr, fmt, foo(argp) + foo(argp));
(with a '+' instead of the last comma -- I felt kind of lost the first time I read it). But now, I understand your point.Thank you for your support.
PS : this ticket may be closed, but I don't see any option for that, so I let you do it.
Last edit: zaghp 2020-09-28