Fixture 84

compound literals

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

One lane has a function that returns a different result after decompilation: clang-O0 (1/3).

C99 compound literals: an unnamed object with automatic storage inside a block. Its address is valid for the enclosing block only, and the object is a fresh one on every evaluation.

tests/decompiler_fixtures/src/84_compound_literals.c source
#include <stdint.h>

/* C99 compound literals: an unnamed object with automatic storage inside a
 * block. Its address is valid for the enclosing block only, and the object is
 * a fresh one on every evaluation. */

struct Pair {
    int32_t first;
    int32_t second;
};

static int32_t pair_span(const struct Pair *pair) {
    return pair->first - pair->second;
}

__attribute__((noinline)) int32_t
compound_literal_argument(int32_t left, int32_t right) {
    /* The literal lives until the end of this block. */
    return pair_span(&(struct Pair){left, right});
}

__attribute__((noinline)) int32_t
compound_literal_array(int32_t index) {
    if (index < 0 || index > 5) {
        return -1;
    }
    return (int32_t[]){2, 3, 5, 7, 11, 13}[index];
}

__attribute__((noinline)) int32_t
compound_literal_in_loop(int32_t count) {
    int32_t total = 0;
    int32_t step;
    if (count < 0 || count > 16) {
        return -1;
    }
    for (step = 0; step < count; ++step) {
        /* A distinct object each iteration. */
        struct Pair local = (struct Pair){step, count - step};
        total += pair_span(&local);
    }
    return total;
}

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
compound_literal_argument fail 11 lines
// glaurung: compound_literal_argument @ 0x1100
__attribute__((no_stack_protector)) int32_t compound_literal_argument(int32_t arg0, int32_t arg1) {
    extern int pair_span(char *);
    unsigned char local_10[4];
    int ret;
    // x86-64 prologue: save rbp, frame 16 bytes
    *(int *)(&local_10[0]) = arg0;
    ret = pair_span((char *)(&local_10[0]));
    // x86-64 epilogue: restore rbp
    return ret;
}
compound_literal_array fail 27 lines
// glaurung: compound_literal_array @ 0x1150
static unsigned char glaurung_global_4020[16] __attribute__((aligned(16)));
static unsigned char glaurung_global_4028[16] __attribute__((aligned(16)));
static unsigned char glaurung_global_4030[16] __attribute__((aligned(16)));
__attribute__((no_stack_protector)) int32_t compound_literal_array(int32_t arg0) {
    extern unsigned char glaurung_global_4020[16];
    extern unsigned char glaurung_global_4028[16];
    extern unsigned char glaurung_global_4030[16];
    unsigned char local_20[32];
    // x86-64 prologue: save rbp
    if (((long)(arg0) < 0)) {
        *(int *)((&local_20[0] + 28)) = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(*(int *)((&local_20[0] + 28)));
    }
    if (((((unsigned long)((unsigned int)(arg0)) == 5) | ((long)(arg0) < 5)) == 0)) {
        *(int *)((&local_20[0] + 28)) = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(*(int *)((&local_20[0] + 28)));
    }
    *(long *)(&local_20[0]) = *(long *)(&glaurung_global_4020[0]);
    *(long *)((&local_20[0] + 8)) = *(long *)(&glaurung_global_4028[0]);
    *(long *)((&local_20[0] + 16)) = *(long *)(&glaurung_global_4030[0]);
    *(int *)((&local_20[0] + 28)) = *(int *)((&local_20[0] + ((long)(arg0) * 4)));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(*(int *)((&local_20[0] + 28)));
}
compound_literal_in_loop pass 30 lines
// glaurung: compound_literal_in_loop @ 0x11b0
__attribute__((no_stack_protector)) int32_t compound_literal_in_loop(int32_t arg0) {
    extern int pair_span(char *);
    int total;
    int step;
    unsigned char local_18[8];
    int local_4;
    int var5;
    // x86-64 prologue: save rbp, frame 32 bytes
    total = 0;
    if (((long)(arg0) < 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((((unsigned long)((unsigned int)(arg0)) == 16) | ((long)(arg0) < 16)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    for (step = 0; (step < arg0); step++) {
        *(int *)(&local_18[0]) = step;
        *(int *)((&local_18[0] + 4)) = ((unsigned long)((unsigned int)(arg0)) - step);
        var5 = pair_span((char *)(&local_18[0]));
        total = (var5 + total);
    }
    local_4 = total;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}

clang -O2

3/3
compound_literal_argument pass 4 lines
// glaurung: compound_literal_argument @ 0x1100
int32_t compound_literal_argument(int32_t arg0, int32_t arg1) {
    return (unsigned int)(((unsigned long)((unsigned int)(arg0)) - arg1));
}
compound_literal_array pass 9 lines
// glaurung: compound_literal_array @ 0x1110
int32_t compound_literal_array(int32_t arg0) {
    long ret;
    ret = 0xffffffff;
    if (((unsigned long)((unsigned long)((unsigned int)(arg0))) <= (unsigned long)(5))) {
        ret = (unsigned long)((unsigned int)((((unsigned long)((unsigned int)(arg0)) == 0) ? 2 : (((unsigned long)((unsigned int)(arg0)) == 1) ? 3 : (((unsigned long)((unsigned int)(arg0)) == 2) ? 5 : (((unsigned long)((unsigned int)(arg0)) == 3) ? 7 : (((unsigned long)((unsigned int)(arg0)) == 4) ? 11 : (((unsigned long)((unsigned int)(arg0)) == 5) ? 13 : *(int *)((0x2000 + ((unsigned long)((unsigned int)(arg0)) * 4)))))))))));
    }
    return ret;
}
compound_literal_in_loop pass 16 lines
// glaurung: compound_literal_in_loop @ 0x1130
int32_t compound_literal_in_loop(int32_t arg0) {
    int step;
    int total;
    long ret;
    long var1;
    ret = 0xffffffff;
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
        return ret;
    }
    if (((unsigned long)((unsigned int)(arg0)) == 0)) {
        return 0;
    }
    var1 = (unsigned long)((unsigned int)((arg0 - 1)));
    return (unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)((arg0 - 2))) * var1))) & -2))) + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)((2 - arg0))) * var1)))))) - arg0));
}

gcc -O0

3/3
compound_literal_argument pass 19 lines
// glaurung: compound_literal_argument @ 0x1138
int32_t compound_literal_argument(int32_t arg0, int32_t arg1) {
    extern __attribute__((noreturn)) void __stack_chk_fail(void);
    extern int pair_span(char *);
    unsigned char local_10[16];
    long ret;
    int var6;
    // x86-64 prologue: save rbp, frame 32 bytes
    *(long *)((&local_10[0] + 8)) = (long)((long)(0x28));
    *(int *)(&local_10[0]) = arg0;
    *(int *)((&local_10[0] + 4)) = arg1;
    var6 = pair_span((char *)(&local_10[0]));
    ret = (unsigned long)((unsigned int)(var6));
    if ((*(long *)((&local_10[0] + 8)) != 0x28)) {
        __stack_chk_fail();
    }
    // x86-64 epilogue: restore rbp
    return ret;
}
compound_literal_array pass 24 lines
// glaurung: compound_literal_array @ 0x1187
int32_t compound_literal_array(int32_t arg0) {
    extern __attribute__((noreturn)) void __stack_chk_fail(void);
    unsigned char local_20[32];
    long ret;
    // x86-64 prologue: save rbp, frame 48 bytes
    *(long *)((&local_20[0] + 24)) = (long)((long)(0x28));
    if ((((long)(arg0) < 0) || (((unsigned long)((unsigned int)(arg0)) != 5) && (5 <= (long)(arg0))))) {
        ret = 0xffffffff;
    } else {
        *(int *)(&local_20[0]) = 2;
        *(int *)((&local_20[0] + 4)) = 3;
        *(int *)((&local_20[0] + 8)) = 5;
        *(int *)((&local_20[0] + 12)) = 7;
        *(int *)((&local_20[0] + 16)) = 11;
        *(int *)((&local_20[0] + 20)) = 13;
        ret = (unsigned long)((unsigned int)(*(int *)((&local_20[0] + ((long)(arg0) * 4)))));
    }
    if ((*(long *)((&local_20[0] + 24)) != 0x28)) {
        __stack_chk_fail();
    }
    // x86-64 epilogue: restore rbp
    return ret;
}
compound_literal_in_loop pass 30 lines
// glaurung: compound_literal_in_loop @ 0x1201
int32_t compound_literal_in_loop(int32_t arg0) {
    extern __attribute__((noreturn)) void __stack_chk_fail(void);
    extern int pair_span(char *);
    int total;
    int step;
    unsigned char local_10[8];
    long local_8;
    long ret;
    int var9;
    // x86-64 prologue: save rbp, frame 48 bytes
    local_8 = (long)(0x28);
    total = 0;
    if ((((long)(arg0) < 0) || (((unsigned long)((unsigned int)(arg0)) != 16) && (16 <= (long)(arg0))))) {
        ret = 0xffffffff;
    } else {
        for (step = 0; (step < arg0); step++) {
            *(int *)(&local_10[0]) = step;
            *(int *)((&local_10[0] + 4)) = ((unsigned long)((unsigned int)(arg0)) - step);
            var9 = pair_span((char *)(&local_10[0]));
            total = (total + var9);
        }
        ret = (unsigned long)((unsigned int)(total));
    }
    if ((local_8 != 0x28)) {
        __stack_chk_fail();
    }
    // x86-64 epilogue: restore rbp
    return ret;
}

gcc -O2

3/3
compound_literal_argument pass 4 lines
// glaurung: compound_literal_argument @ 0x1120
int32_t compound_literal_argument(int32_t arg0, int32_t arg1) {
    return (unsigned int)(((unsigned long)((unsigned int)(arg0)) - arg1));
}
compound_literal_array pass 19 lines
// glaurung: compound_literal_array @ 0x1130
int32_t compound_literal_array(int32_t arg0) {
    extern __attribute__((noreturn)) void __stack_chk_fail(void);
    unsigned char local_28[40];
    long ret;
    *(long *)((&local_28[0] + 24)) = (long)((long)(0x28));
    if (((unsigned long)(5) < (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
        ret = 0xffffffff;
    } else {
        *(long *)(&local_28[0]) = 0x300000002;
        *(long *)((&local_28[0] + 8)) = 0x700000005;
        *(long *)((&local_28[0] + 16)) = 0xd0000000b;
        ret = (unsigned long)((unsigned int)(*(int *)((&local_28[0] + ((long)(arg0) * 4)))));
    }
    if ((*(long *)((&local_28[0] + 24)) != 0x28)) {
        __stack_chk_fail();
    }
    return ret;
}
compound_literal_in_loop pass 31 lines
// glaurung: compound_literal_in_loop @ 0x11b0
int32_t compound_literal_in_loop(int32_t arg0) {
    int total;
    int step;
    long var3;
    long var4;
    int var6;
    long var7;
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
        goto L_11e7;
    }
    if (((unsigned long)((unsigned int)(arg0)) == 0)) {
        goto L_11e0;
    }
    var3 = (-(unsigned long)((unsigned int)(arg0)));
    var4 = 0;
    do {
        total = (var4 + var3);
        var4 = (unsigned long)((unsigned int)(total));
        var6 = (var3 + 2);
        var3 = (unsigned long)((unsigned int)(var6));
        var7 = (unsigned long)((unsigned int)(total));
    } while (((unsigned int)(arg0) != (unsigned int)(var6)));
    L_11d2: ;
    return (unsigned int)(var7);
    L_11e0: ;
    return 0;
    L_11e7: ;
    var7 = 0xffffffff;
    goto L_11d2;
}

← 213 fixtures