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.
#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/3variadic_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/3variadic_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/3variadic_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/3variadic_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;
}