Fixture 108

multidimensional arrays

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 true 2D array is one object with a compound stride; an array of pointers is two loads. The functions below are deliberately confusable at the source level and completely different in the binary.

tests/decompiler_fixtures/src/108_multidimensional_arrays.c source
#include <stdint.h>

/* A true 2D array is one object with a compound stride; an array of pointers is
 * two loads. The functions below are deliberately confusable at the source
 * level and completely different in the binary. */

#define GRID_ROWS 4
#define GRID_COLUMNS 4

__attribute__((noinline)) int32_t
sum_true_2d(const int32_t grid[GRID_ROWS][GRID_COLUMNS], int32_t rows) {
    int32_t total = 0;
    int32_t row;
    int32_t column;
    if (grid == 0 || rows < 0 || rows > GRID_ROWS) {
        return -1;
    }
    for (row = 0; row < rows; ++row) {
        for (column = 0; column < GRID_COLUMNS; ++column) {
            total += grid[row][column];
        }
    }
    return total;
}

__attribute__((noinline)) int32_t
sum_flat_with_stride(const int32_t *flat, int32_t rows, int32_t columns) {
    int32_t total = 0;
    int32_t row;
    int32_t column;
    if (flat == 0 || rows < 0 || rows > GRID_ROWS || columns < 0 ||
        columns > GRID_COLUMNS) {
        return -1;
    }
    for (row = 0; row < rows; ++row) {
        for (column = 0; column < columns; ++column) {
            total += flat[row * columns + column];
        }
    }
    return total;
}

__attribute__((noinline)) int32_t
row_decay_span(const int32_t grid[GRID_ROWS][GRID_COLUMNS], int32_t row) {
    const int32_t *decayed;
    if (grid == 0 || row < 0 || row >= GRID_ROWS) {
        return -1;
    }
    decayed = grid[row]; /* a row decays to int32_t*, not int32_t(*)[4] */
    return decayed[0] + decayed[GRID_COLUMNS - 1];
}

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
row_decay_span structural 25 lines
// glaurung: row_decay_span @ 0x1270
int32_t row_decay_span(char * arg0, int32_t arg1) {
    int * decayed;
    int local_4;
    // x86-64 prologue: save rbp
    if ((arg0 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((long)(arg1) < 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if ((4 <= (long)(arg1))) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    decayed = (int *)(((long)arg0 + ((long)(arg1) << 4)));
    local_4 = ((unsigned int)(*(int *)(decayed)) + *(int *)((decayed + 0xc)));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
sum_flat_with_stride pass 44 lines
// glaurung: sum_flat_with_stride @ 0x11b0
int32_t sum_flat_with_stride(const int32_t * arg0, int32_t arg1, int32_t arg2) {
    int total;
    int row;
    int column;
    int local_4;
    // x86-64 prologue: save rbp
    total = 0;
    if ((arg0 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((long)(arg1) < 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((((unsigned long)((unsigned int)(arg1)) == 4) | ((long)(arg1) < 4)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((long)(arg2) < 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((((unsigned long)((unsigned int)(arg2)) == 4) | ((long)(arg2) < 4)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    row = 0;
    while ((row < arg1)) {
        for (column = 0; (column < arg2); column++) {
            total = ((unsigned int)(arg0[(long)((int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(row)) * arg2))) + column)))]) + total);
        }
        row = ((unsigned int)(row) + 1);
    }
    local_4 = total;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
sum_true_2d structural 34 lines
// glaurung: sum_true_2d @ 0x1100
int32_t sum_true_2d(char * arg0, int32_t arg1) {
    int total;
    int row;
    int column;
    int local_4;
    // x86-64 prologue: save rbp
    total = 0;
    if ((arg0 == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((long)(arg1) < 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    if (((((unsigned long)((unsigned int)(arg1)) == 4) | ((long)(arg1) < 4)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    row = 0;
    while ((row < arg1)) {
        for (column = 0; ((long)(column) < 4); column++) {
            total = ((unsigned int)(*(int *)((((long)arg0 + ((long)(row) << 4)) + ((long)(column) * 4)))) + total);
        }
        row = ((unsigned int)(row) + 1);
    }
    local_4 = total;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}

clang -O2

1/3
row_decay_span structural 13 lines
// glaurung: row_decay_span @ 0x1290
int32_t row_decay_span(char * arg0, int32_t arg1) {
    long ret;
    long var1;
    ret = 0xffffffff;
    if ((arg0 != 0)) {
        if (((unsigned long)((unsigned long)((unsigned int)(arg1))) <= (unsigned long)(3))) {
            var1 = ((unsigned long)((unsigned int)(arg1)) << 4);
            ret = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(*(int *)(((long)arg0 + var1 + 0xc)))) + *(int *)(((long)arg0 + var1)))));
        }
    }
    return ret;
}
sum_flat_with_stride pass 110 lines
// glaurung: sum_flat_with_stride @ 0x11b0
int32_t sum_flat_with_stride(const int32_t * arg0, int32_t arg1, int32_t arg2) {
    int total;
    int column;
    int row;
    long ret;
    long var10;
    long var17;
    long var23;
    int var24;
    int var26;
    int var28;
    long var29;
    int var4;
    long var5;
    int var6;
    long var7;
    ret = 0xffffffff;
    if (((unsigned long)((unsigned long)((unsigned int)(arg2))) <= (unsigned long)(4))) {
        ret = 0xffffffff;
        if ((arg0 == 0)) {
            return ret;
        }
        ret = 0xffffffff;
        if (((unsigned long)(4) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
            return ret;
        }
        if (((unsigned long)((unsigned int)(arg1)) == 0)) {
            return 0;
        }
        if (((unsigned long)((unsigned int)(arg2)) == 0)) {
            ret = 0;
        } else {
            ret = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
            if (((unsigned long)((unsigned int)(arg2)) != 1)) {
                var4 = (ret + *(int *)(((long)arg0 + 0x4)));
                var5 = (unsigned long)((unsigned int)(var4));
                ret = (unsigned long)((unsigned int)(var4));
                if (((unsigned long)((unsigned int)(arg2)) != 2)) {
                    var6 = (var5 + *(int *)(((long)arg0 + 0x8)));
                    var7 = (unsigned long)((unsigned int)(var6));
                    ret = (unsigned long)((unsigned int)(var6));
                    if (((unsigned long)((unsigned int)(arg2)) != 3)) {
                        ret = (unsigned long)((unsigned int)((var7 + *(int *)(((long)arg0 + 0xc)))));
                    }
                }
            }
        }
        if (((unsigned long)((unsigned int)(arg1)) == 1)) {
            return ret;
        }
        var10 = (unsigned long)((unsigned int)(arg2));
        total = ret;
        if (((unsigned long)((unsigned int)(arg2)) != 0)) {
            total = (unsigned long)((unsigned int)((ret + *(int *)(((long)arg0 + var10 * 4)))));
            if (((unsigned long)((unsigned int)(arg2)) != 1)) {
                total = (unsigned long)((unsigned int)((total + *(int *)(((long)arg0 + var10 * 4 + 0x4)))));
                if (((unsigned long)((unsigned int)(arg2)) != 2)) {
                    total = (unsigned long)((unsigned int)((total + *(int *)(((long)arg0 + var10 * 4 + 0x8)))));
                    if (((unsigned long)((unsigned int)(arg2)) != 3)) {
                        total = (unsigned long)((unsigned int)((total + *(int *)(((long)arg0 + var10 * 4 + 0xc)))));
                    }
                }
            }
        }
        ret = (unsigned long)((unsigned int)(total));
        if (((unsigned long)((unsigned int)(arg1)) == 2)) {
            return ret;
        }
        if (((unsigned long)((unsigned int)(arg2)) != 0)) {
            total = (unsigned long)((unsigned int)((total + *(int *)(((long)arg0 + var10 * 8)))));
            if (((unsigned long)((unsigned int)(arg2)) != 1)) {
                var17 = (var10 + var10);
                total = (unsigned long)((unsigned int)((total + *(int *)(((long)arg0 + ((var17 * 4) | 4))))));
                if (((unsigned long)((unsigned int)(arg2)) != 2)) {
                    total = (unsigned long)((unsigned int)((total + *(int *)(((long)arg0 + var17 * 4 + 0x8)))));
                    if (((unsigned long)((unsigned int)(arg2)) != 3)) {
                        total = (unsigned long)((unsigned int)((total + *(int *)(((long)arg0 + var17 * 4 + 0xc)))));
                    }
                }
            }
        }
        ret = (unsigned long)((unsigned int)(total));
        if (((unsigned long)((unsigned int)(arg1)) == 3)) {
            return ret;
        }
        ret = (unsigned long)((unsigned int)(total));
        if (((unsigned long)((unsigned int)(arg2)) == 0)) {
            return ret;
        }
        var23 = (var10 + (var10 * 2));
        var24 = (total + *(int *)(((long)arg0 + var23 * 4)));
        ret = (unsigned long)((unsigned int)(var24));
        if (((unsigned long)((unsigned int)(arg2)) == 1)) {
            return ret;
        }
        var26 = ((unsigned int)(var24) + *(int *)(((long)arg0 + var23 * 4 + 0x4)));
        ret = (unsigned long)((unsigned int)(var26));
        if (((unsigned long)((unsigned int)(arg2)) == 2)) {
            return ret;
        }
        var28 = ((unsigned int)(var26) + *(int *)(((long)arg0 + var23 * 4 + 0x8)));
        var29 = (unsigned long)((unsigned int)(var28));
        ret = (unsigned long)((unsigned int)(var28));
        if (((unsigned long)((unsigned int)(arg2)) != 3)) {
            ret = (unsigned long)((unsigned int)((var29 + *(int *)(((long)arg0 + var23 * 4 + 0xc)))));
        }
    }
    return ret;
}
sum_true_2d structural 42 lines
// glaurung: sum_true_2d @ 0x1100
int32_t sum_true_2d(char * arg0, int32_t arg1) {
    int column;
    int row;
    int total;
    long ret;
    int var31;
    int var38;
    int var53;
    int var60;
    int var75;
    int var82;
    ret = 0xffffffff;
    if ((arg0 != 0)) {
        ret = 0xffffffff;
        if (((unsigned long)(4) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
            return ret;
        }
        if (((unsigned long)((unsigned int)(arg1)) == 0)) {
            return 0;
        }
        ret = (unsigned long)((unsigned int)(((*(int *)(((long)arg0 + 0xc)) + *(int *)(((long)arg0 + 0x4))) + (*(int *)(((long)arg0 + 0x8)) + *(int *)(((long)arg0))))));
        if (((unsigned long)((unsigned int)(arg1)) == 1)) {
            return ret;
        }
        var31 = (*(int *)(((long)arg0 + 0x1c)) + *(int *)(((long)arg0 + 0x14)));
        var38 = (var31 + (*(int *)(((long)arg0 + 0x18)) + *(int *)(((long)arg0 + 0x10))));
        ret = (unsigned long)((unsigned int)((((var31 + var31) | var38) + (unsigned long)((unsigned int)(var38)))));
        if (((unsigned long)((unsigned int)(arg1)) == 2)) {
            return ret;
        }
        var53 = (*(int *)(((long)arg0 + 0x2c)) + *(int *)(((long)arg0 + 0x24)));
        var60 = (var53 + (*(int *)(((long)arg0 + 0x28)) + *(int *)(((long)arg0 + 0x20))));
        ret = (unsigned long)((unsigned int)((((var53 + var53) | var60) + (unsigned long)((unsigned int)(var60)))));
        if (((unsigned long)((unsigned int)(arg1)) != 3)) {
            var75 = (*(int *)(((long)arg0 + 0x3c)) + *(int *)(((long)arg0 + 0x34)));
            var82 = (var75 + (*(int *)(((long)arg0 + 0x38)) + *(int *)(((long)arg0 + 0x30))));
            ret = (unsigned long)((unsigned int)((((var75 + var75) | var82) + (unsigned long)((unsigned int)(var82)))));
        }
    }
    return ret;
}

gcc -O0

1/3
row_decay_span structural 20 lines
// glaurung: row_decay_span @ 0x1206
int32_t row_decay_span(char * arg0, int32_t arg1) {
    int * decayed;
    // x86-64 prologue: save rbp
    if ((arg0 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((long)(arg1) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((((unsigned long)((unsigned int)(arg1)) == 3) | ((long)(arg1) < 3)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    decayed = (int *)(((long)arg0 + ((long)(arg1) << 4)));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(*(int *)((decayed + 3)))) + (unsigned long)((unsigned int)(*(int *)(decayed)))));
}
sum_flat_with_stride pass 37 lines
// glaurung: sum_flat_with_stride @ 0x1174
int32_t sum_flat_with_stride(const int32_t * arg0, int32_t arg1, int32_t arg2) {
    int total;
    int row;
    int column;
    // x86-64 prologue: save rbp
    total = 0;
    if ((arg0 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((long)(arg1) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((((unsigned long)((unsigned int)(arg1)) == 4) | ((long)(arg1) < 4)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((long)(arg2) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((((unsigned long)((unsigned int)(arg2)) == 4) | ((long)(arg2) < 4)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    row = 0;
    while ((row < arg1)) {
        for (column = 0; (column < arg2); column++) {
            total = (total + (unsigned int)(arg0[(long)((int)(((unsigned long)((unsigned int)(column)) + (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(row)) * arg2))))))]));
        }
        row = (row + 1);
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(total);
}
sum_true_2d structural 29 lines
// glaurung: sum_true_2d @ 0x10f9
int32_t sum_true_2d(char * arg0, int32_t arg1) {
    int total;
    int row;
    int column;
    // x86-64 prologue: save rbp
    total = 0;
    if ((arg0 == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((long)(arg1) < 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    if (((((unsigned long)((unsigned int)(arg1)) == 4) | ((long)(arg1) < 4)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    row = 0;
    while ((row < arg1)) {
        for (column = 0; ((((unsigned long)((unsigned int)(column)) == 3) | ((long)(column) < 3)) != 0); column++) {
            total = (total + (unsigned int)(*(int *)(((((long)(row) << 4) + (long)arg0) + ((long)(column) * 4)))));
        }
        row = (row + 1);
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(total);
}

gcc -O2

1/3
row_decay_span structural 11 lines
// glaurung: row_decay_span @ 0x11c0
int32_t row_decay_span(char * arg0, int32_t arg1) {
    long var2;
    if ((arg0 != 0)) {
        if (((unsigned long)((unsigned long)((unsigned int)(arg1))) <= (unsigned long)(3))) {
            var2 = (long)(((long)arg0 + ((long)(arg1) << 4)));
            return (unsigned int)(((unsigned long)((unsigned int)(*(int *)((var2 + 0xc)))) + *(int *)((var2))));
        }
    }
    return 0xffffffff;
}
sum_flat_with_stride pass 60 lines
// glaurung: sum_flat_with_stride @ 0x1150
int32_t sum_flat_with_stride(const int32_t * arg0, int32_t arg1, int32_t arg2) {
    int total;
    int column;
    int row;
    long var0;
    long var10;
    long var11;
    long var12;
    long var13;
    long var15;
    long var17;
    long var18;
    long var2;
    int var20;
    long var4;
    long var9;
    if ((arg0 == 0)) {
        var0 = 0xffffffff;
        return 0xffffffff;
    }
    if (((unsigned long)(4) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        var0 = 0xffffffff;
        return 0xffffffff;
    }
    if (((unsigned long)(4) < (unsigned long)((unsigned long)((unsigned int)(arg2))))) {
        var0 = 0xffffffff;
        return 0xffffffff;
    }
    var0 = 0;
    if (((unsigned long)((unsigned int)(arg1)) == 0)) {
        return (unsigned int)(var0);
    }
    var2 = (long)arg0;
    var4 = 0;
    var9 = (unsigned long)((unsigned int)((arg2 - 1)));
    var10 = (long)((arg0 + 1));
    var11 = 0;
    var12 = 0;
    do {
        var13 = var11;
        if (((unsigned long)((unsigned int)(arg2)) != 0)) {
            var15 = (var2 + ((long)((int)(var4)) * 4));
            var17 = (var10 + (((long)((int)(var4)) + var9) * 4));
            var18 = var11;
            do {
                total = (var18 + *(int *)((var15)));
                var18 = (unsigned long)((unsigned int)(total));
                var15 = (var15 + 4);
                var13 = (unsigned long)((unsigned int)(total));
            } while ((var15 != var17));
        }
        var20 = (var12 + 1);
        var4 = (unsigned long)((unsigned int)((var4 + arg2)));
        var11 = var13;
        var12 = (unsigned long)((unsigned int)(var20));
    } while (((unsigned int)(arg1) != (unsigned int)(var20)));
    // x86-64 epilogue: tear down frame
    return (unsigned int)(var13);
}
sum_true_2d structural 32 lines
// glaurung: sum_true_2d @ 0x1100
int32_t sum_true_2d(char * arg0, int32_t arg1) {
    int column;
    int row;
    int total;
    long ret;
    int var14;
    long var3;
    long var6;
    long var7;
    int var8;
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    if (((unsigned long)(4) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        return 0xffffffff;
    }
    if (((unsigned long)((unsigned int)(arg1)) == 0)) {
        return 0;
    }
    var3 = (long)((((long)arg0 + ((unsigned long)((unsigned int)((arg1 - 1))) << 4)) + 16));
    var6 = 0;
    var7 = (long)arg0;
    do {
        var8 = (var6 + *(int *)((var7)));
        var7 = (var7 + 16);
        var14 = ((unsigned int)(((unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var8)) + *(int *)((var7 - 0xc))))) + *(int *)((var7 - 0x8)))) + *(int *)((var7 - 0x4)));
        ret = (unsigned long)((unsigned int)(var14));
        var6 = (unsigned long)((unsigned int)(var14));
    } while ((var7 != var3));
    return ret;
}

← 213 fixtures