Fixture 111

self referential struct

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

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

A struct containing a pointer to its own type. The nodes live in a caller-owned array and are linked by real addresses, so traversal is a chain of dependent loads that must terminate on the recovered null test.

tests/decompiler_fixtures/src/111_self_referential_struct.c source
#include <stdint.h>

/* A struct containing a pointer to its own type. The nodes live in a
 * caller-owned array and are linked by real addresses, so traversal is a chain
 * of dependent loads that must terminate on the recovered null test. */

struct Node {
    int32_t value;
    struct Node *next;
};

#define NODE_MAX 8

__attribute__((noinline)) int32_t
link_and_sum(int32_t *values, int32_t count) {
    struct Node nodes[NODE_MAX];
    struct Node *cursor;
    int32_t index;
    int32_t total = 0;
    int32_t visited = 0;
    if (values == 0 || count < 0 || count > NODE_MAX) {
        return -1;
    }
    for (index = 0; index < count; ++index) {
        nodes[index].value = values[index];
        nodes[index].next = (index + 1 < count) ? &nodes[index + 1] : 0;
    }
    for (cursor = (count > 0) ? &nodes[0] : 0; cursor != 0;
         cursor = cursor->next) {
        total += cursor->value;
        visited += 1;
        if (visited > NODE_MAX) {
            return -2;
        }
    }
    return total * 10 + visited;
}

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 -O2

0/1
link_and_sum fail 153 lines
// glaurung: link_and_sum @ 0x1100
typedef struct Node Node;
int32_t link_and_sum(int32_t * arg0, int32_t arg1) {
    Node * cursor;
    int index;
    int total;
    int visited;
    long local_10;
    int local_18;
    long local_20;
    int local_28;
    long local_30;
    int local_38;
    long local_40;
    int local_48;
    long local_50;
    int local_58;
    long local_60;
    int local_68;
    long local_70;
    int local_78;
    long local_8;
    long local_80;
    int local_88;
    long ret;
    long rsp;
    long var4;
    long var47;
    long var5;
    long var50;
    long var53;
    long var56;
    long var59;
    long var6;
    long var62;
    long var65;
    long var9;
    rsp = (rsp - 8);
    local_8 = ret;
    ret = 0xffffffff;
    if ((arg0 == 0)) {
        // x86-64 epilogue: tear down frame
        return ret;
    }
    if (((unsigned long)(8) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        // x86-64 epilogue: tear down frame
        return ret;
    }
    if (((unsigned long)((unsigned int)(arg1)) == 0)) {
        var4 = 0;
        var5 = 0;
        L_12c4: ;
        var6 = (unsigned long)((unsigned int)((var5 + (var5 * 4))));
        return (unsigned int)((var4 + (var6 * 2)));
    }
    local_88 = *(int *)(((long)arg0));
    var9 = 0;
    local_80 = (((unsigned long)((unsigned long)((unsigned int)(arg1))) < (unsigned long)(2)) ? 0 : (rsp - 112));
    if (((unsigned long)((unsigned int)(arg1)) != 1)) {
        local_78 = *(int *)(((long)arg0 + 0x4));
        local_70 = (((unsigned long)(3) <= (unsigned long)((unsigned long)((unsigned int)(arg1)))) ? (rsp - 96) : 0);
        if (((unsigned long)((unsigned int)(arg1)) != 2)) {
            local_68 = *(int *)(((long)arg0 + 0x8));
            local_60 = (((unsigned long)(4) <= (unsigned long)((unsigned long)((unsigned int)(arg1)))) ? (rsp - 80) : 0);
            if (((unsigned long)((unsigned int)(arg1)) != 3)) {
                local_58 = *(int *)(((long)arg0 + 0xc));
                local_50 = (((unsigned long)(5) <= (unsigned long)((unsigned long)((unsigned int)(arg1)))) ? (rsp - 64) : 0);
                if (((unsigned long)((unsigned int)(arg1)) != 4)) {
                    local_48 = *(int *)(((long)arg0 + 0x10));
                    local_40 = (((unsigned long)(6) <= (unsigned long)((unsigned long)((unsigned int)(arg1)))) ? (rsp - 48) : 0);
                    if (((unsigned long)((unsigned int)(arg1)) != 5)) {
                        local_38 = *(int *)(((long)arg0 + 0x14));
                        local_30 = (((unsigned long)(7) <= (unsigned long)((unsigned long)((unsigned int)(arg1)))) ? (rsp - 32) : 0);
                        if (((unsigned long)((unsigned int)(arg1)) != 6)) {
                            local_28 = *(int *)(((long)arg0 + 0x18));
                            local_20 = (((unsigned long)(8) <= (unsigned long)((unsigned long)((unsigned int)(arg1)))) ? (rsp - 16) : 0);
                            if (((unsigned long)((unsigned int)(arg1)) != 7)) {
                                local_18 = *(int *)(((long)arg0 + 0x1c));
                                local_10 = (((unsigned long)(9) <= (unsigned long)((unsigned long)((unsigned int)(arg1)))) ? rsp : 0);
                            }
                        }
                    }
                }
            }
        }
    }
    var4 = 0;
    var5 = var9;
    if (((unsigned long)((unsigned int)(arg1)) == 0)) {
        var6 = (unsigned long)((unsigned int)((var5 + (var5 * 4))));
        // x86-64 epilogue: tear down frame
        return (unsigned int)((var4 + (var6 * 2)));
    }
    var5 = (unsigned long)((unsigned int)(local_88));
    var47 = local_80;
    if ((local_80 == 0)) {
        var4 = 1;
        goto L_12c4;
    } else {
        var5 = (unsigned long)((unsigned int)((var5 + *(int *)((var47)))));
        var50 = *(long *)((var47 + 0x8));
        if ((var50 == 0)) {
            var4 = 2;
            goto L_12c4;
        } else {
            var5 = (unsigned long)((unsigned int)((var5 + *(int *)((var50)))));
            var53 = *(long *)((var50 + 0x8));
            if ((var53 == 0)) {
                var4 = 3;
                goto L_12c4;
            } else {
                var5 = (unsigned long)((unsigned int)((var5 + *(int *)((var53)))));
                var56 = *(long *)((var53 + 0x8));
                if ((var56 == 0)) {
                    var4 = 4;
                    goto L_12c4;
                } else {
                    var5 = (unsigned long)((unsigned int)((var5 + *(int *)((var56)))));
                    var59 = *(long *)((var56 + 0x8));
                    if ((var59 == 0)) {
                        var4 = 5;
                        goto L_12c4;
                    } else {
                        var5 = (unsigned long)((unsigned int)((var5 + *(int *)((var59)))));
                        var62 = *(long *)((var59 + 0x8));
                        if ((var62 == 0)) {
                            var4 = 6;
                            goto L_12c4;
                        } else {
                            var5 = (unsigned long)((unsigned int)((var5 + *(int *)((var62)))));
                            var65 = *(long *)((var62 + 0x8));
                            if ((var65 == 0)) {
                                var4 = 7;
                                goto L_12c4;
                            } else {
                                ret = 0xfffffffe;
                                if ((*(long *)((var65 + 0x8)) != 0)) {
                                    // x86-64 epilogue: tear down frame
                                    return ret;
                                }
                                var5 = (unsigned long)((unsigned int)((var5 + *(int *)((var65)))));
                                var4 = 8;
                                goto L_12c4;
                            }
                        }
                    }
                }
            }
        }
    }
    // x86-64 epilogue: tear down frame
    return ret;
}

gcc -O0

0/1
link_and_sum fail 81 lines
// glaurung: link_and_sum @ 0x1119
typedef struct Node Node;
int32_t link_and_sum(int32_t * arg0, int32_t arg1) {
    extern __attribute__((noreturn)) void __stack_chk_fail(void);
    int total;
    int visited;
    int index;
    Node * cursor;
    long local_8;
    unsigned char local_90[128];
    long rbp;
    long ret;
    long rsp;
    int var15;
    long var23;
    void * var30;
    int var39;
    rsp = (rsp - 8);
    rbp = rsp;
    rsp = (rsp - 192);
    local_8 = (long)(0x28);
    total = 0;
    visited = 0;
    if ((arg0 != 0)) {
        if ((0 <= (long)(arg1))) {
            if ((((unsigned long)((unsigned int)(arg1)) == 8) | ((long)(arg1) < 8))) {
                goto L_117e;
            }
        }
    }
    ret = 0xffffffff;
    goto L_12a1;
    L_117e: ;
    index = 0;
    goto L_1214;
    L_118d: ;
    *(int *)(((((long)(index) << 4) + rbp) - 144)) = arg0[(long)(index)];
    var15 = ((unsigned int)(index) + 1);
    if (((((unsigned int)(arg1) == (unsigned int)(var15)) | (arg1 < var15)) == 0)) {
        var23 = (long)((((long)((int)(((unsigned long)((unsigned int)(index)) + 1))) << 4) + &local_90[0]));
        goto L_11f3;
    }
    var23 = 0;
    L_11f3: ;
    *(long *)(((((long)(index) << 4) + rbp) - 136)) = var23;
    index = (index + 1);
    L_1214: ;
    if ((index < arg1)) {
        goto L_118d;
    }
    if (((((unsigned long)((unsigned int)(arg1)) == 0) | ((long)(arg1) < 0)) == 0)) {
        var30 = &local_90[0];
        goto L_123d;
    }
    var30 = (void *)(0);
    L_123d: ;
    cursor = var30;
    goto L_127e;
    L_1246: ;
    total = (total + (unsigned int)(*(int *)((long)cursor)));
    visited = (visited + 1);
    if (((((unsigned long)((unsigned int)(visited)) == 8) | ((long)(visited) < 8)) == 0)) {
        ret = 0xfffffffe;
        goto L_12a1;
    }
    cursor = (Node *)(*(long *)(((long)cursor + 0x8)));
    L_127e: ;
    if ((cursor != 0)) {
        goto L_1246;
    }
    var39 = ((unsigned int)(((unsigned long)((unsigned int)(total)) << 2)) + (unsigned int)(total));
    ret = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(visited)) + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var39)) + (unsigned long)((unsigned int)(var39))))))));
    L_12a1: ;
    if ((local_8 == 0x28)) {
        // x86-64 epilogue: restore rbp
        return ret;
    }
    __stack_chk_fail();
    // x86-64 epilogue: restore rbp
    return ret;
}

clang -O0

1/1
link_and_sum pass 69 lines
// glaurung: link_and_sum @ 0x1100
typedef struct Node Node;
__attribute__((no_stack_protector)) int32_t link_and_sum(int32_t * arg0, int32_t arg1) {
    int total;
    int visited;
    int index;
    unsigned char cursor[16];
    int local_4;
    unsigned char local_a0[128];
    long local_c0;
    void * local_c8;
    total = 0;
    visited = 0;
    if ((arg0 != 0)) {
        if ((0 <= (long)(arg1))) {
            if ((((unsigned long)((unsigned int)(arg1)) == 8) | ((long)(arg1) < 8))) {
                goto L_114e;
            }
        }
    }
    local_4 = -1;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
    L_114e: ;
    index = 0;
    L_1158: ;
    if ((arg1 <= index)) {
        goto L_1206;
    }
    *(int *)((&local_a0[0] + ((long)(index) << 4))) = arg0[(long)(index)];
    if (((long)((int)(((unsigned long)((unsigned int)(index)) + 1))) < (long)(arg1))) {
        local_c0 = (long)((&local_a0[0] + ((long)((int)(((unsigned long)((unsigned int)(index)) + 1))) << 4)));
        goto L_11d2;
    }
    local_c0 = 0;
    goto L_11d2;
    L_11d2: ;
    *(long *)(((&local_a0[0] + ((long)(index) << 4)) + 8)) = local_c0;
    index = ((unsigned int)(index) + 1);
    goto L_1158;
    L_1206: ;
    if (((((unsigned long)((unsigned int)(arg1)) == 0) | ((long)(arg1) < 0)) == 0)) {
        local_c8 = &local_a0[0];
        goto L_1231;
    }
    local_c8 = (void *)(0);
    goto L_1231;
    L_1231: ;
    *(long *)(&cursor[0]) = (long)((long)local_c8);
    L_123f: ;
    if ((*(long *)(&cursor[0]) == 0)) {
        goto L_12a6;
    }
    total = ((unsigned int)(*(int *)(*(long *)(&cursor[0]))) + total);
    visited = ((unsigned int)(visited) + 1);
    if (((((unsigned long)((unsigned int)(visited)) == 8) | ((long)(visited) < 8)) == 0)) {
        local_4 = -2;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    goto L_128f;
    L_128f: ;
    *(long *)(&cursor[0]) = *(long *)((*(long *)(&cursor[0]) + 8));
    goto L_123f;
    L_12a6: ;
    local_4 = ((total * 10) + visited);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}

gcc -O2

1/1
link_and_sum pass 73 lines
// glaurung: link_and_sum @ 0x1120
typedef struct Node Node;
int32_t link_and_sum(int32_t * arg0, int32_t arg1) {
    extern __attribute__((noreturn)) void __stack_chk_fail(void);
    Node * cursor;
    int visited;
    int index;
    int total;
    long local_10;
    unsigned char local_98[128];
    long ret;
    long var12;
    long var13;
    long var14;
    long var22;
    int var23;
    long var6;
    long var8;
    long var9;
    local_10 = (long)(0x28);
    if ((arg0 == 0)) {
        L_1204: ;
        ret = 0xffffffff;
    } else {
        if (((unsigned long)(8) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
            goto L_1204;
        } else {
            if (((unsigned long)((unsigned int)(arg1)) == 0)) {
                ret = 0;
            } else {
                var6 = (unsigned long)((unsigned int)((arg1 - 1)));
                var8 = var6;
                var9 = (long)(((long)arg0 + (var6 * 4)));
                var12 = (long)((&local_98[0] + 16));
                *(int *)((var12 - 0x10)) = *(int *)(((long)arg0));
                if (((long)arg0 != var9)) {
                    var13 = (long)arg0;
                    while ((var13 != var9)) {
                        var14 = (unsigned long)((unsigned int)(*(int *)((var13 + 0x4))));
                        var13 = (var13 + 4);
                        *(long *)((var12 - 0x8)) = var12;
                        var12 = (var12 + 16);
                        *(int *)((var12 - 0x10)) = var14;
                    }
                }
                *(long *)((&local_98[0] + (((long)((int)(var8)) << 4) + 8))) = 0;
                cursor = (Node *)&local_98[0];
                visited = 1;
                var22 = (unsigned long)((unsigned int)(*(int *)(&local_98[0])));
                L_11b8: ;
                while (1) {
                    cursor = (Node *)(*(long *)(((long)cursor + 0x8)));
                    if ((cursor == 0)) {
                        break;
                    }
                    var23 = (visited + 1);
                    visited = (unsigned long)((unsigned int)(var23));
                    var22 = (unsigned long)((unsigned int)((var22 + *(int *)(((long)cursor)))));
                    if (((unsigned long)((unsigned int)(var23)) != 9)) {
                        goto L_11b8;
                    } else {
                        ret = 0xfffffffe;
                    }
                    if ((local_10 != 0x28)) {
                        __stack_chk_fail();
                    }
                    return ret;
                }
                ret = (unsigned long)((unsigned int)((visited + ((unsigned long)((unsigned int)((var22 + (var22 * 4)))) * 2))));
            }
        }
    }
}

← 213 fixtures