Fixture 105

goto ladder

C · 1 functions · 4 lanes · 4 of 4 function-lanes behave identically

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

The kernel-style cleanup ladder: forward gotos into a reversed unwind chain where later labels fall through earlier ones. Structuring must recover the partial-cleanup order, not just the fact that a jump exists.

tests/decompiler_fixtures/src/105_goto_ladder.c source
#include <stdint.h>

/* The kernel-style cleanup ladder: forward gotos into a reversed unwind chain
 * where later labels fall through earlier ones. Structuring must recover the
 * partial-cleanup order, not just the fact that a jump exists. */

__attribute__((noinline)) int32_t
acquire_and_release(int32_t stages, int32_t *log, int32_t capacity) {
    int32_t released = 0;
    int32_t status = 0;
    if (log == 0 || capacity < 4 || stages < 0 || stages > 4) {
        return -1;
    }
    log[0] = 0;
    log[1] = 0;
    log[2] = 0;
    log[3] = 0;

    if (stages < 1) {
        status = -2;
        goto done;
    }
    log[0] = 1;
    if (stages < 2) {
        status = -3;
        goto release_first;
    }
    log[1] = 1;
    if (stages < 3) {
        status = -4;
        goto release_second;
    }
    log[2] = 1;
    if (stages < 4) {
        status = -5;
        goto release_third;
    }
    log[3] = 1;
    status = stages;

    released += 1;
release_third:
    released += 1;
release_second:
    released += 1;
release_first:
    released += 1;
done:
    return status * 10 + released;
}

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/1
acquire_and_release pass 61 lines
// glaurung: acquire_and_release @ 0x1100
int32_t acquire_and_release(int32_t arg0, int32_t * arg1, int32_t arg2) {
    int released;
    int status;
    int local_4;
    // x86-64 prologue: save rbp
    released = 0;
    status = 0;
    if ((arg1 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((long)(arg2) < 4)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((long)(arg0) < 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((((unsigned long)((unsigned int)(arg0)) == 4) | ((long)(arg0) < 4)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    *(int *)((long)arg1) = 0;
    *(int *)(((long)arg1 + 0x4)) = 0;
    *(int *)(((long)arg1 + 0x8)) = 0;
    *(int *)(((long)arg1 + 0xc)) = 0;
    if ((1 <= (long)(arg0))) {
        *(int *)((long)arg1) = 1;
        if ((2 <= (long)(arg0))) {
            *(int *)(((long)arg1 + 0x4)) = 1;
            if ((3 <= (long)(arg0))) {
                *(int *)(((long)arg1 + 0x8)) = 1;
                if ((4 <= (long)(arg0))) {
                    *(int *)(((long)arg1 + 0xc)) = 1;
                    status = arg0;
                    released = ((unsigned int)(released) + 1);
                } else {
                    status = -5;
                }
                released = ((unsigned int)(released) + 1);
            } else {
                status = -4;
            }
            released = ((unsigned int)(released) + 1);
        } else {
            status = -3;
        }
        released = ((unsigned int)(released) + 1);
    } else {
        status = -2;
    }
    local_4 = ((status * 10) + released);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}

clang -O2

1/1
acquire_and_release pass 55 lines
// glaurung: acquire_and_release @ 0x1100
int32_t acquire_and_release(int32_t arg0, int32_t * arg1, int32_t arg2) {
    int released;
    int status;
    long ret;
    int var8;
    long var9;
    long zf_6;
    ret = 0xffffffff;
    if (((unsigned long)(4) < (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
        return ret;
    }
    ret = 0xffffffff;
    if ((arg1 == 0)) {
        return ret;
    }
    ret = 0xffffffff;
    if (((long)(arg2) < 4)) {
        return ret;
    }
    *(int *)(((long)arg1)) = 0;
    *(int *)(((long)arg1 + 0x4)) = 0;
    *(int *)(((long)arg1 + 0x8)) = 0;
    *(int *)(((long)arg1 + 0xc)) = 0;
    if (((unsigned long)((unsigned int)(arg0)) == 0)) {
        var8 = 0xffffffec;
        var9 = 0;
    } else {
        *(int *)(((long)arg1)) = 1;
        if (((unsigned long)((unsigned int)(arg0)) != 1)) {
            *(int *)(((long)arg1 + 0x4)) = 1;
            zf_6 = ((unsigned long)((unsigned int)(arg0)) == 3);
            if (((unsigned long)(3) <= (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
                *(int *)(((long)arg1 + 0x8)) = 1;
                if ((zf_6 == 0)) {
                    *(int *)(((long)arg1 + 0xc)) = 1;
                    var8 = 40;
                    var9 = 4;
                } else {
                    var8 = 0xffffffce;
                    var9 = 3;
                }
            } else {
                var8 = 0xffffffd8;
                var9 = 2;
            }
        } else {
            var8 = 0xffffffe2;
            var9 = 1;
        }
    }
    released = (var9 + var8);
    ret = (unsigned long)((unsigned int)(released));
    return (unsigned int)(released);
}

gcc -O0

1/1
acquire_and_release pass 57 lines
// glaurung: acquire_and_release @ 0x10f9
int32_t acquire_and_release(int32_t arg0, int32_t * arg1, int32_t arg2) {
    int released;
    int status;
    int var19;
    // x86-64 prologue: save rbp
    released = 0;
    status = 0;
    if ((arg1 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if ((((unsigned long)((unsigned int)(arg2)) == 3) | ((long)(arg2) < 3))) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((long)(arg0) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((((unsigned long)((unsigned int)(arg0)) == 4) | ((long)(arg0) < 4)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    *(int *)((long)arg1) = 0;
    *(int *)((arg1 + 1)) = 0;
    *(int *)((arg1 + 2)) = 0;
    *(int *)((arg1 + 3)) = 0;
    if (((((unsigned long)((unsigned int)(arg0)) == 0) | ((long)(arg0) < 0)) == 0)) {
        *(int *)((long)arg1) = 1;
        if (((((unsigned long)((unsigned int)(arg0)) == 1) | ((long)(arg0) < 1)) == 0)) {
            *(int *)((arg1 + 1)) = 1;
            if (((((unsigned long)((unsigned int)(arg0)) == 2) | ((long)(arg0) < 2)) == 0)) {
                *(int *)((arg1 + 2)) = 1;
                if (((((unsigned long)((unsigned int)(arg0)) == 3) | ((long)(arg0) < 3)) == 0)) {
                    *(int *)((arg1 + 3)) = 1;
                    status = arg0;
                    released = (released + 1);
                } else {
                    status = -5;
                }
                released = (released + 1);
            } else {
                status = -4;
            }
            released = (released + 1);
        } else {
            status = -3;
        }
        released = (released + 1);
    } else {
        status = -2;
    }
    var19 = ((unsigned int)(((unsigned long)((unsigned int)(status)) << 2)) + (unsigned int)(status));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(released)) + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var19)) + (unsigned long)((unsigned int)(var19)))))));
}

gcc -O2

1/1
acquire_and_release pass 34 lines
// glaurung: acquire_and_release @ 0x1100
int32_t acquire_and_release(int32_t arg0, int32_t * arg1, int32_t arg2) {
    int released;
    int status;
    long ret;
    if ((arg1 == 0)) {
        return 0xffffffff;
    }
    if ((((unsigned long)((unsigned int)(arg2)) == 3) | ((long)(arg2) < 3))) {
        return 0xffffffff;
    }
    if (((unsigned long)(4) < (unsigned long)((unsigned long)((unsigned int)(arg0))))) {
        return 0xffffffff;
    }
    *(long *)(((long)arg1)) = 0;
    ret = 0xffffffec;
    *(long *)(((long)arg1 + 0x8)) = 0;
    if (((unsigned long)((unsigned int)(arg0)) != 0)) {
        *(int *)(((long)arg1)) = 1;
        ret = 0xffffffe3;
        if (((unsigned long)((unsigned int)(arg0)) == 1)) {
            return ret;
        }
        *(int *)(((long)arg1 + 0x4)) = 1;
        ret = 0xffffffda;
        if (((unsigned long)((unsigned int)(arg0)) != 2)) {
            *(int *)(((long)arg1 + 0x8)) = 1;
            ret = (((unsigned long)((unsigned int)(arg0)) == 3) ? 0xffffffd1 : 44);
            *(int *)(((long)arg1 + 0xc)) = ((unsigned long)((unsigned int)(arg0)) != 3);
            return ret;
        }
    }
    return ret;
}

← 213 fixtures