Fixture 113

varargs

C · 3 functions · 4 lanes · 4 of 12 function-lanes behave identically

4 of 4 lanes have a function that returns a different result after decompilation: clang-O0 (1/3), clang-O2 (1/3), gcc-O0 (1/3), gcc-O2 (1/3).

A variadic callee: arguments past the prototype are passed by the register save area / overflow area rules, and the callee walks them with va_arg. Default argument promotion means a narrow value arrives as int.

tests/decompiler_fixtures/src/113_varargs.c source
#include <stdint.h>
#include <stdarg.h>

/* A variadic callee: arguments past the prototype are passed by the register
 * save area / overflow area rules, and the callee walks them with va_arg.
 * Default argument promotion means a narrow value arrives as int. */

static int32_t sum_variadic(int32_t count, ...) {
    va_list arguments;
    int32_t total = 0;
    int32_t index;
    if (count < 0 || count > 8) {
        return -1;
    }
    va_start(arguments, count);
    for (index = 0; index < count; ++index) {
        total += va_arg(arguments, int32_t);
    }
    va_end(arguments);
    return total;
}

static int32_t weighted_variadic(int32_t count, ...) {
    va_list arguments;
    int32_t total = 0;
    int32_t index;
    if (count < 0 || count > 8) {
        return -1;
    }
    va_start(arguments, count);
    for (index = 0; index < count; ++index) {
        total += va_arg(arguments, int32_t) * (index + 1);
    }
    va_end(arguments);
    return total;
}

__attribute__((noinline)) int32_t
variadic_three(int32_t a, int32_t b, int32_t c) {
    return sum_variadic(3, a, b, c);
}

__attribute__((noinline)) int32_t
variadic_weighted_four(int32_t a, int32_t b, int32_t c, int32_t d) {
    return weighted_variadic(4, a, b, c, d);
}

__attribute__((noinline)) int32_t variadic_none(void) {
    return sum_variadic(0);
}

Recovered C

Generated by glaurung decompile --style decbench at b47f6b43. baseline.json records the result after recompiling the C and calling it beside the original with seeded inputs.

clang -O0

1/3
variadic_none pass 9 lines
// glaurung: variadic_none @ 0x1430
int32_t variadic_none(void) {
    extern int sum_variadic(int);
    int ret;
    // x86-64 prologue: save rbp
    ret = sum_variadic(0);
    // x86-64 epilogue: restore rbp
    return ret;
}
variadic_three fail 9 lines
// glaurung: variadic_three @ 0x1100
int32_t variadic_three(int32_t arg0, int32_t arg1, int32_t arg2) {
    extern int sum_variadic(int);
    int ret;
    // x86-64 prologue: save rbp, frame 16 bytes
    ret = sum_variadic(3);
    // x86-64 epilogue: restore rbp
    return ret;
}
variadic_weighted_four fail 9 lines
// glaurung: variadic_weighted_four @ 0x1290
int32_t variadic_weighted_four(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern int weighted_variadic(int);
    int ret;
    // x86-64 prologue: save rbp, frame 16 bytes
    ret = weighted_variadic(4);
    // x86-64 epilogue: restore rbp
    return ret;
}

clang -O2

1/3
variadic_none pass 7 lines
// glaurung: variadic_none @ 0x1360
int32_t variadic_none(void) {
    extern int sum_variadic(int);
    int ret;
    ret = sum_variadic(0);
    return ret;
}
variadic_three fail 7 lines
// glaurung: variadic_three @ 0x1100
int32_t variadic_three(int32_t arg0, int32_t arg1, int32_t arg2) {
    extern int sum_variadic(int, long, long, long);
    int ret;
    ret = sum_variadic(3, (unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)));
    return ret;
}
variadic_weighted_four fail 7 lines
// glaurung: variadic_weighted_four @ 0x1240
int32_t variadic_weighted_four(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern int weighted_variadic(int, long, long, long, long);
    int ret;
    ret = weighted_variadic(arg0, (unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(arg3)));
    return ret;
}

gcc -O0

1/3
variadic_none pass 9 lines
// glaurung: variadic_none @ 0x1422
int32_t variadic_none(void) {
    extern int sum_variadic(int);
    int ret;
    // x86-64 prologue: save rbp
    ret = sum_variadic(0);
    // x86-64 epilogue: restore rbp
    return ret;
}
variadic_three fail 9 lines
// glaurung: variadic_three @ 0x13b7
int32_t variadic_three(int32_t arg0, int32_t arg1, int32_t arg2) {
    extern int sum_variadic(int);
    int ret;
    // x86-64 prologue: save rbp, frame 16 bytes
    ret = sum_variadic(3);
    // x86-64 epilogue: restore rbp
    return ret;
}
variadic_weighted_four fail 9 lines
// glaurung: variadic_weighted_four @ 0x13e8
int32_t variadic_weighted_four(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern int weighted_variadic(int);
    int ret;
    // x86-64 prologue: save rbp, frame 16 bytes
    ret = weighted_variadic(4);
    // x86-64 epilogue: restore rbp
    return ret;
}

gcc -O2

1/3
variadic_none pass 7 lines
// glaurung: variadic_none @ 0x1290
int32_t variadic_none(void) {
    extern int sum_variadic(int);
    int ret;
    ret = sum_variadic(0);
    return ret;
}
variadic_three fail 7 lines
// glaurung: variadic_three @ 0x1250
int32_t variadic_three(int32_t arg0, int32_t arg1, int32_t arg2) {
    extern int sum_variadic(int, long, long, long);
    int ret;
    ret = sum_variadic(3, (unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)));
    return ret;
}
variadic_weighted_four fail 7 lines
// glaurung: variadic_weighted_four @ 0x1270
int32_t variadic_weighted_four(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern int weighted_variadic_constprop_0(int, long, long, long, long);
    int ret;
    ret = weighted_variadic_constprop_0(4, (unsigned long)((unsigned int)(arg0)), (unsigned long)((unsigned int)(arg1)), (unsigned long)((unsigned int)(arg2)), (unsigned long)((unsigned int)(arg3)));
    return ret;
}

← 213 fixtures