Fixture 92

anonymous members

C · 2 functions · 4 lanes · 8 of 8 function-lanes behave identically

All 4 lanes recompile and return the same results as the original.

C11 anonymous structs and unions: members of an unnamed member are addressed as if they belonged to the enclosing type, so the source names carry no offset information a decompiler can lean on.

tests/decompiler_fixtures/src/92_anonymous_members.c source
#include <stdint.h>

/* C11 anonymous structs and unions: members of an unnamed member are addressed
 * as if they belonged to the enclosing type, so the source names carry no
 * offset information a decompiler can lean on. */

struct Message {
    int32_t kind;
    union {
        struct {
            int32_t x;
            int32_t y;
        };
        struct {
            int32_t code;
            int32_t detail;
        };
        int32_t raw[2];
    };
};

__attribute__((noinline)) int32_t
anonymous_select(int32_t kind, int32_t first, int32_t second, int32_t which) {
    struct Message message;
    message.kind = kind;
    message.x = first;
    message.y = second;
    switch (which & 3) {
    case 0:
        return message.x + message.y;
    case 1:
        return message.code - message.detail;
    case 2:
        return message.raw[0];
    default:
        return message.raw[1];
    }
}

__attribute__((noinline)) int32_t
anonymous_overlap_proof(int32_t value) {
    struct Message message;
    message.kind = 0;
    message.code = value;
    /* `x` and `code` name the same storage. */
    return message.x == value;
}

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

2/2
anonymous_overlap_proof pass 9 lines
// glaurung: anonymous_overlap_proof @ 0x1190
__attribute__((no_stack_protector)) int32_t anonymous_overlap_proof(int32_t arg0) {
    unsigned char local_10[12];
    // x86-64 prologue: save rbp
    *(int *)(&local_10[0]) = 0;
    *(int *)((&local_10[0] + 4)) = arg0;
    // x86-64 epilogue: restore rbp
    return ((unsigned int)(*(int *)((&local_10[0] + 4))) == (unsigned int)(arg0));
}
anonymous_select pass 25 lines
// glaurung: anonymous_select @ 0x1100
__attribute__((no_stack_protector)) int32_t anonymous_select(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    unsigned char local_20[12];
    int local_24;
    int var4;
    // x86-64 prologue: save rbp
    *(int *)(&local_20[0]) = arg0;
    *(int *)((&local_20[0] + 4)) = arg1;
    *(int *)((&local_20[0] + 8)) = arg2;
    var4 = ((unsigned int)(arg3) & 3);
    local_24 = var4;
    if (((unsigned long)((unsigned int)(var4)) == 0)) {
        return (unsigned int)(((unsigned long)((unsigned int)(*(int *)((&local_20[0] + 4)))) + *(int *)((&local_20[0] + 8))));
    } else {
        if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_24)) - 1))) == 0)) {
            return (unsigned int)(((unsigned long)((unsigned int)(*(int *)((&local_20[0] + 4)))) - *(int *)((&local_20[0] + 8))));
        } else {
            if (((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(local_24)) - 2))) == 0)) {
                return (unsigned int)(*(int *)((&local_20[0] + 4)));
            } else {
                return (unsigned int)(*(int *)((&local_20[0] + 8)));
            }
        }
    }
}

clang -O2

2/2
anonymous_overlap_proof pass 4 lines
// glaurung: anonymous_overlap_proof @ 0x1120
int32_t anonymous_overlap_proof(int32_t arg0) {
    return 1;
}
anonymous_select pass 20 lines
// glaurung: anonymous_select @ 0x1100
int32_t anonymous_select(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    long ret;
    long var1;
    long var2;
    var1 = (unsigned long)((unsigned int)((arg3 & 3)));
    var2 = (unsigned long)((unsigned int)(arg1));
    if (((unsigned long)((unsigned int)(var1)) == 2)) {
        return (unsigned int)(var2);
    }
    ret = (unsigned long)((unsigned int)(arg2));
    if (((unsigned long)((unsigned int)(var1)) == 1)) {
        var2 = (unsigned long)((unsigned int)((arg1 - ret)));
        return (unsigned int)(var2);
    }
    if (((unsigned long)((unsigned int)(var1)) != 0)) {
        return ret;
    }
    return (unsigned int)((ret + arg1));
}

gcc -O0

2/2
anonymous_overlap_proof pass 17 lines
// glaurung: anonymous_overlap_proof @ 0x119f
int32_t anonymous_overlap_proof(int32_t arg0) {
    extern __attribute__((noreturn)) void __stack_chk_fail(void);
    unsigned char local_14[12];
    long local_8;
    long ret;
    // x86-64 prologue: save rbp, frame 48 bytes
    local_8 = (long)(0x28);
    *(int *)(&local_14[0]) = 0;
    *(int *)((&local_14[0] + 4)) = arg0;
    ret = ((unsigned int)(arg0) == (unsigned int)(*(int *)((&local_14[0] + 4))));
    if ((local_8 != 0x28)) {
        __stack_chk_fail();
    }
    // x86-64 epilogue: restore rbp
    return ret;
}
anonymous_select pass 37 lines
// glaurung: anonymous_select @ 0x1119
int32_t anonymous_select(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    extern __attribute__((noreturn)) void __stack_chk_fail(void);
    unsigned char local_14[12];
    long local_8;
    long ret;
    long var8;
    // x86-64 prologue: save rbp, frame 48 bytes
    local_8 = (long)(0x28);
    *(int *)(&local_14[0]) = arg0;
    *(int *)((&local_14[0] + 4)) = arg1;
    *(int *)((&local_14[0] + 8)) = arg2;
    var8 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(arg3)) & 3)));
    if (((unsigned long)((unsigned int)(var8)) == 2)) {
        ret = (unsigned long)((unsigned int)(*(int *)((&local_14[0] + 4))));
    } else {
        if (((((unsigned long)((unsigned int)(var8)) == 2) | ((long)((int)(var8)) < 2)) == 0)) {
            L_1186: ;
            ret = (unsigned long)((unsigned int)(*(int *)((&local_14[0] + 8))));
        } else {
            if (((unsigned long)((unsigned int)(var8)) == 0)) {
                ret = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)((&local_14[0] + 8)))) + (unsigned long)((unsigned int)(*(int *)((&local_14[0] + 4)))))));
            } else {
                if (((unsigned long)((unsigned int)(var8)) == 1)) {
                    ret = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)((&local_14[0] + 4)))) - (unsigned long)((unsigned int)(*(int *)((&local_14[0] + 8)))))));
                } else {
                    goto L_1186;
                }
            }
        }
    }
    if ((local_8 != 0x28)) {
        __stack_chk_fail();
    }
    // x86-64 epilogue: restore rbp
    return ret;
}

gcc -O2

2/2
anonymous_overlap_proof pass 4 lines
// glaurung: anonymous_overlap_proof @ 0x1130
int32_t anonymous_overlap_proof(int32_t arg0) {
    return 1;
}
anonymous_select pass 12 lines
// glaurung: anonymous_select @ 0x1100
int32_t anonymous_select(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3) {
    long var1;
    var1 = (unsigned long)((unsigned int)((arg3 & 3)));
    if (((unsigned long)((unsigned int)(var1)) == 1)) {
        return (unsigned int)((arg1 - arg2));
    }
    if (((unsigned long)((unsigned int)(var1)) == 2)) {
        return (unsigned int)(arg1);
    }
    return (((unsigned long)((unsigned int)(var1)) == 0) ? (unsigned long)((unsigned int)((arg1 + arg2))) : (unsigned long)((unsigned int)(arg2)));
}

← 213 fixtures