Menu

#856 va_arg is acting weird during inner function calls

v1.0 (example)
open
nobody
None
5
2020-09-28
2020-09-27
zaghp
No

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

1 Attachments

Related

Bugs: #856

Discussion

  • Kai Tietz

    Kai Tietz - 2020-09-28

    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:


    [bugs:#856] va_arg is acting weird during inner function calls

    Status: open
    Group: v1.0 (example)
    Created: Sun Sep 27, 2020 11:56 PM UTC by zaghp
    Last Updated: Sun Sep 27, 2020 11:56 PM UTC
    Owner: nobody
    Attachments:

    sample-va_list.c (662 Bytes; text/x-csrc)

    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></stdarg.h>

    include <stdio.h></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 </whatever>/
    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 (122 + 642)

    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


    Sent from sourceforge.net because you indicated interest in https://sourceforge.net/p/mingw-w64/bugs/856/

    To unsubscribe from further messages, please visit https://sourceforge.net/auth/subscriptions/

     

    Related

    Bugs: #856

  • zaghp

    zaghp - 2020-09-28

    Hi

    Thank you for the reply.

    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.

    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.

    will of course display 24, and not - as you were assuming - 76

    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

Log in to post a comment.