Why does this variable function crash the 4th parameter in Windows x64?

Below is the code that includes the variational function and calls the variational function. I would expect it to output each sequence of numbers appropriately. This happens when compiling as a 32-bit executable, but not when compiling as a 64-bit executable.

#include <stdarg.h>
#include <stdio.h>

#ifdef _WIN32
#define SIZE_T_FMT "%Iu"
#else
#define SIZE_T_FMT "%zu"
#endif


static void dumpargs(size_t count, ...) {

    size_t i;
    va_list args;

    printf("dumpargs: argument count: " SIZE_T_FMT "\n", count);

    va_start(args, count);

    for (i = 0; i < count; i++) {

        size_t val = va_arg(args, size_t);
        printf("Value=" SIZE_T_FMT "\n", val);
    }
    va_end(args);
}

int main(int argc, char** argv) {

    (void)argc;
    (void)argv;

    dumpargs(1, 10);
    dumpargs(2, 10, 20);
    dumpargs(3, 10, 20, 30);
    dumpargs(4, 10, 20, 30, 40);
    dumpargs(5, 10, 20, 30, 40, 50);

    return 0;
}

Here is the result when compiled for 64 bit:

dumpargs: argument count: 1
Value=10
dumpargs: argument count: 2
Value=10
Value=20
dumpargs: argument count: 3
Value=10
Value=20
Value=30
dumpargs: argument count: 4
Value=10
Value=20
Value=30
Value=14757395255531667496
dumpargs: argument count: 5
Value=10
Value=20
Value=30
Value=14757395255531667496
Value=14757395255531667506

Edit:

Note that the reason a variable function pulls out size_tis because in the real world it is used for a variational function that takes a list of pointers and lengths. Naturally, the argument of length should be size_t. And in some cases, the caller may convey something known:

void myfunc(size_t pairs, ...) {
    va_list args;
    va_start(args, count);

    for (i = 0; i < pairs; i++) {
        const void* ptr = va_arg(args, const void*);
        size_t len = va_arg(args, size_t);
        process(ptr, len);
    }
    va_end(args);
}

void user(void) {
    myfunc(2, ptr1, ptr1_len, ptr2, 4);
}

, 4, myfunc, , . , , sizeof strlen 4 size_t -. , ( ).

- , . , , .

+3
5

, , , ( , , , , ).

, 4-, , x86-64. , ++, gcc , .

, ( , va_ * ).

x86 C - .

+6

, size_t . , 32- Win64.

Size_t , 32 64 - (, ). int __int32, .

, Win32, , size_t - , platfrom. 32- 32 , 64- - 64 . 32- .

+4

, size_t 32- 32- Windows 64- 64- Windows. 4- , . 4 5 :

Value=0xcccccccc00000028
Value=0xcccccccc00000032

, :

dumpargs(5, (size_t)10, (size_t)20, (size_t)30, (size_t)40, (size_t)50);

; :

  • 4- ? , 3 ?
  • ?
  • 64- , 64- (, size_t 32- 64- )?
  • 32- , , 64- ?
  • ?

Edit:

, , , . , .

comp.lang.c FAQ, , , , . , , . .

, C printf ( , gcc printf style), , , , , undefined . "", , 0, "" - 64- 32- , undefined.

+2

. , , , .

size_t 32- Win32 64- Win64. , . , , , size_t, , , .

10 int. , size_t. , , , (size_z)10 .

, - , Win64. , , - . .

. Undefined Behavior, "undefined" "undefined": . .

, , , , , , .

, , . , gcc , printf() . .

+2

, , , / .

, C (. ), . , , UL ULL.

Most health checks of the passed values ​​will be application specific or not portable (for example, pointer validity). You can use hacks, such as indicating that a predefined sender value has also been sent, but this is not infallible in all cases.

The best practice would be documentation to a large extent, doing code reviews and / or writing unit tests to account for this error.

+1
source

Source: https://habr.com/ru/post/1706077/


All Articles