Fixture 128

qualifier combinations

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

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

The qualifier binds to what precedes the const: const int * is a mutable pointer to constant data, int *const is a constant pointer to mutable data. They generate different code for the same-looking source.

tests/decompiler_fixtures/src/128_qualifier_combinations.c source
#include <stdint.h>

/* The qualifier binds to what precedes the const: `const int *` is a mutable
 * pointer to constant data, `int *const` is a constant pointer to mutable data.
 * They generate different code for the same-looking source. */

__attribute__((noinline)) int32_t
pointer_to_const_walks(const int32_t *values, int32_t count) {
    const int32_t *cursor = values; /* the pointer may move */
    int32_t total = 0;
    int32_t index;
    if (values == 0 || count < 0 || count > 16) {
        return -1;
    }
    for (index = 0; index < count; ++index) {
        total += *cursor;
        cursor += 1;
    }
    return total;
}

__attribute__((noinline)) int32_t
const_pointer_writes(int32_t *const target, int32_t count) {
    int32_t index;
    if (target == 0 || count < 0 || count > 16) {
        return -1;
    }
    /* The pointer cannot move, but the pointee can change. */
    for (index = 0; index < count; ++index) {
        target[index] = index * 2;
    }
    return target[0] + count;
}

__attribute__((noinline)) int32_t
volatile_const_is_readable(int32_t seed) {
    /* A hardware-register idiom: not writable here, but re-read every time. */
    volatile const int32_t cell = seed;
    int32_t total = 0;
    total += cell;
    total += cell;
    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

2/3
const_pointer_writes fail 27 lines
// glaurung: const_pointer_writes @ 0x1190
int32_t const_pointer_writes(const int32_t * arg0, int32_t arg1) {
    int index;
    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 (((((unsigned long)((unsigned int)(arg1)) == 16) | ((long)(arg1) < 16)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    for (index = 0; (index < arg1); index++) {
        arg0[(long)(index)] = ((unsigned long)((unsigned int)(index)) << 1);
    }
    local_4 = ((unsigned int)(*(int *)((long)arg0)) + arg1);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
pointer_to_const_walks pass 32 lines
// glaurung: pointer_to_const_walks @ 0x1100
int32_t pointer_to_const_walks(const int32_t * arg0, int32_t arg1) {
    int * cursor;
    int total;
    int index;
    int local_4;
    // x86-64 prologue: save rbp
    cursor = (int *)arg0;
    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)) == 16) | ((long)(arg1) < 16)) == 0)) {
        local_4 = -1;
        // x86-64 epilogue: restore rbp
        return (unsigned int)(local_4);
    }
    for (index = 0; (index < arg1); index++) {
        total = ((unsigned int)(*(int *)(cursor)) + total);
        cursor = (int *)((cursor + 1));
    }
    local_4 = total;
    // x86-64 epilogue: restore rbp
    return (unsigned int)(local_4);
}
volatile_const_is_readable pass 12 lines
// glaurung: volatile_const_is_readable @ 0x1210
int32_t volatile_const_is_readable(int32_t arg0) {
    int cell;
    int total;
    // x86-64 prologue: save rbp
    cell = arg0;
    total = 0;
    total = ((unsigned int)(cell) + total);
    total = ((unsigned int)(cell) + total);
    // x86-64 epilogue: restore rbp
    return (unsigned int)(total);
}

gcc -O0

2/3
const_pointer_writes fail 22 lines
// glaurung: const_pointer_writes @ 0x1159
int32_t const_pointer_writes(const int32_t * arg0, int32_t arg1) {
    int index;
    // 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)) == 16) | ((long)(arg1) < 16)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    for (index = 0; (index < arg1); index++) {
        arg0[(long)(index)] = ((unsigned long)((unsigned int)(index)) + (unsigned long)((unsigned int)(index)));
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(((unsigned long)((unsigned int)(arg1)) + (unsigned long)((unsigned int)(*(int *)((long)arg0)))));
}
pointer_to_const_walks pass 27 lines
// glaurung: pointer_to_const_walks @ 0x10f9
int32_t pointer_to_const_walks(const int32_t * arg0, int32_t arg1) {
    int * cursor;
    int total;
    int index;
    // x86-64 prologue: save rbp
    cursor = (int *)arg0;
    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)) == 16) | ((long)(arg1) < 16)) == 0)) {
        // x86-64 epilogue: restore rbp
        return 0xffffffff;
    }
    for (index = 0; (index < arg1); index++) {
        total = (total + (unsigned int)(*(int *)(cursor)));
        cursor = (int *)((cursor + 1));
    }
    // x86-64 epilogue: restore rbp
    return (unsigned int)(total);
}
volatile_const_is_readable pass 12 lines
// glaurung: volatile_const_is_readable @ 0x11bf
int32_t volatile_const_is_readable(int32_t arg0) {
    int cell;
    int total;
    // x86-64 prologue: save rbp
    cell = arg0;
    total = 0;
    total = (total + (unsigned int)(cell));
    total = (total + (unsigned int)(cell));
    // x86-64 epilogue: restore rbp
    return (unsigned int)(total);
}

clang -O2

3/3
const_pointer_writes pass 66 lines
// glaurung: const_pointer_writes @ 0x1230
int32_t const_pointer_writes(const int32_t * arg0, int32_t arg1) {
    int index;
    long ret;
    long t2;
    long var0;
    long var20;
    int var21;
    long var23;
    long var3;
    ret = 0xffffffff;
    if ((arg0 == 0)) {
        return ret;
    }
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        return ret;
    }
    if (((unsigned long)((unsigned int)(arg1)) != 0)) {
        var0 = (unsigned long)((unsigned int)(arg1));
        if (((unsigned long)(4) <= (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
            var3 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var0)) & -4)));
            *(int *)(((long)arg0)) = 0;
            *(int *)(((long)arg0 + 0x4)) = 2;
            *(int *)(((long)arg0 + 0x8)) = 4;
            *(int *)(((long)arg0 + 0xc)) = 6;
            if ((var3 != 4)) {
                *(int *)(((long)arg0 + 0x10)) = 8;
                *(int *)(((long)arg0 + 0x14)) = 10;
                *(int *)(((long)arg0 + 0x18)) = 12;
                *(int *)(((long)arg0 + 0x1c)) = 14;
                if (((unsigned long)((unsigned int)(var3)) != 8)) {
                    *(int *)(((long)arg0 + 0x20)) = 16;
                    *(int *)(((long)arg0 + 0x24)) = 18;
                    *(int *)(((long)arg0 + 0x28)) = 20;
                    *(int *)(((long)arg0 + 0x2c)) = 22;
                    if (((unsigned long)((unsigned int)(var3)) != 12)) {
                        *(int *)(((long)arg0 + 0x30)) = 24;
                        *(int *)(((long)arg0 + 0x34)) = 26;
                        *(int *)(((long)arg0 + 0x38)) = 28;
                        *(int *)(((long)arg0 + 0x3c)) = 30;
                    }
                }
            }
            var20 = var3;
            if ((var3 == var0)) {
                t2 = *(int *)(((long)arg0));
                var21 = (arg1 + t2);
                return (unsigned int)(var21);
            }
            L_1293: ;
            var23 = (unsigned long)((unsigned int)((var20 + var20)));
            index = var20;
            do {
                *(int *)(((long)arg0 + index * 4)) = var23;
                index = (index + 1);
                var23 = (unsigned long)((unsigned int)((var23 + 2)));
            } while ((var0 != index));
        } else {
            var20 = 0;
            goto L_1293;
        }
    }
    t2 = *(int *)(((long)arg0));
    var21 = (arg1 + t2);
    return (unsigned int)(var21);
}
pointer_to_const_walks pass 127 lines
// glaurung: pointer_to_const_walks @ 0x1100
int32_t pointer_to_const_walks(const int32_t * arg0, int32_t arg1) {
    int total;
    int index;
    long ret;
    long var10;
    long var117;
    long var119;
    long var120;
    long var122;
    long var124;
    long var125;
    long var129;
    long var13;
    long var14;
    int var16;
    int var17;
    int var18;
    int var19;
    long var2;
    long var21;
    long var4;
    long var5;
    long var7;
    long var82;
    int var83;
    int var84;
    int var85;
    int var86;
    int var89;
    int var90;
    int var91;
    int var92;
    long var93;
    long var95;
    ret = 0xffffffff;
    if ((arg0 == 0)) {
        return ret;
    }
    ret = 0xffffffff;
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        return ret;
    }
    if (((unsigned long)((unsigned int)(arg1)) == 0)) {
        return 0;
    }
    var2 = (unsigned long)((unsigned int)((arg1 - 1)));
    var4 = 0;
    if (((unsigned long)(3) <= (unsigned long)((unsigned long)((unsigned int)(var2))))) {
        var5 = (var2 + 1);
        var4 = (var5 & -4);
        var7 = (var4 - 4);
        var10 = (((unsigned long)(var7) >> 2) + 1);
        var13 = (unsigned long)((unsigned int)(((unsigned long)((unsigned int)(var10)) & 7)));
        if (((unsigned long)(28) <= (unsigned long)(var7))) {
            var14 = (var10 & -8);
            var16 = 0;
            var17 = 0;
            var18 = 0;
            var19 = 0;
            var21 = 0;
            do {
                var16 = ((*(int *)(((long)arg0 + var21 * 4 + 0x70)) + *(int *)(((long)arg0 + var21 * 4 + 0x60))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x50)) + (*(int *)(((long)arg0 + var21 * 4 + 0x40)) + *(int *)(((long)arg0 + var21 * 4 + 0x30)))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x20)) + *(int *)(((long)arg0 + var21 * 4 + 0x10))) + (*(int *)(((long)arg0 + var21 * 4)) + var16))));
                var17 = ((*(int *)(((long)arg0 + var21 * 4 + 0x74)) + *(int *)(((long)arg0 + var21 * 4 + 0x64))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x54)) + (*(int *)(((long)arg0 + var21 * 4 + 0x44)) + *(int *)(((long)arg0 + var21 * 4 + 0x34)))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x24)) + *(int *)(((long)arg0 + var21 * 4 + 0x14))) + (*(int *)(((long)arg0 + var21 * 4 + 0x4)) + var17))));
                var18 = ((*(int *)(((long)arg0 + var21 * 4 + 0x78)) + *(int *)(((long)arg0 + var21 * 4 + 0x68))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x58)) + (*(int *)(((long)arg0 + var21 * 4 + 0x48)) + *(int *)(((long)arg0 + var21 * 4 + 0x38)))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x28)) + *(int *)(((long)arg0 + var21 * 4 + 0x18))) + (*(int *)(((long)arg0 + var21 * 4 + 0x8)) + var18))));
                var19 = ((*(int *)(((long)arg0 + var21 * 4 + 0x7c)) + *(int *)(((long)arg0 + var21 * 4 + 0x6c))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x5c)) + (*(int *)(((long)arg0 + var21 * 4 + 0x4c)) + *(int *)(((long)arg0 + var21 * 4 + 0x3c)))) + ((*(int *)(((long)arg0 + var21 * 4 + 0x2c)) + *(int *)(((long)arg0 + var21 * 4 + 0x1c))) + (*(int *)(((long)arg0 + var21 * 4 + 0xc)) + var19))));
                ret = ((unsigned long)((unsigned int)(var17)) | (unsigned long)((unsigned int)(var16)));
                var21 = (var21 + 32);
                var14 = (var14 - 8);
                var82 = var21;
                var83 = var16;
                var84 = var17;
                var85 = var18;
                var86 = var19;
            } while ((var14 != 0));
        } else {
            var83 = 0;
            var84 = 0;
            var85 = 0;
            var86 = 0;
            var82 = 0;
        }
        var89 = var83;
        var90 = var84;
        var91 = var85;
        var92 = var86;
        if ((var13 != 0)) {
            var93 = (long)(((long)arg0 + (var82 * 4)));
            var13 = (var13 << 4);
            var95 = 0;
            do {
                var83 = (var83 + *(int *)((var93 + var95)));
                var84 = (var84 + *(int *)((var93 + var95 + 0x4)));
                var85 = (var85 + *(int *)((var93 + var95 + 0x8)));
                var86 = (var86 + *(int *)((var93 + var95 + 0xc)));
                var95 = (var95 + 16);
                var89 = var83;
                var90 = var84;
                var91 = var85;
                var92 = var86;
            } while ((var13 != var95));
        }
        var117 = (unsigned long)((unsigned int)(((var92 + var90) + (var91 + var89))));
        ret = var117;
        if ((var5 == var4)) {
            return ret;
        }
        var119 = var117;
        var120 = (long)(((long)arg0 + (var4 * 4)));
        L_1211: ;
        var122 = (unsigned long)((unsigned int)((arg1 - var4)));
        var124 = 0;
        var125 = var119;
        do {
            total = (var125 + *(int *)((var120 + var124 * 4)));
            var125 = (unsigned long)((unsigned int)(total));
            var124 = (var124 + 1);
            ret = (unsigned long)((unsigned int)(total));
        } while (((unsigned int)(var122) != (unsigned int)(var124)));
    } else {
        var119 = 0;
        var13 = var129;
        var120 = (long)arg0;
        goto L_1211;
    }
    return ret;
}
volatile_const_is_readable pass 5 lines
// glaurung: volatile_const_is_readable @ 0x12c0
int32_t volatile_const_is_readable(int32_t arg0) {
    int total;
    return (unsigned int)(((unsigned long)((unsigned int)(arg0)) + arg0));
}

gcc -O2

3/3
const_pointer_writes pass 29 lines
// glaurung: const_pointer_writes @ 0x1140
int32_t const_pointer_writes(const int32_t * arg0, int32_t arg1) {
    int index;
    long var0;
    int var1;
    long var2;
    long zf_7;
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        return 0xffffffff;
    }
    if (((unsigned long)((unsigned int)(arg1)) == 0)) {
        var0 = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
        var1 = (var0 + arg1);
        return (unsigned int)(var1);
    }
    var2 = (unsigned long)((unsigned int)((arg1 - 1)));
    index = 0;
    do {
        *(int *)(((long)arg0 + index * 4)) = (index + index);
        zf_7 = (index == var2);
        index = (index + 1);
    } while ((zf_7 == 0));
    var0 = (unsigned long)((unsigned int)(*(int *)(((long)arg0))));
    var1 = (var0 + arg1);
    return (unsigned int)(var1);
}
pointer_to_const_walks pass 25 lines
// glaurung: pointer_to_const_walks @ 0x1100
int32_t pointer_to_const_walks(const int32_t * arg0, int32_t arg1) {
    int * cursor;
    int index;
    int total;
    long ret;
    long var2;
    if ((arg0 == 0)) {
        return 0xffffffff;
    }
    if (((unsigned long)(16) < (unsigned long)((unsigned long)((unsigned int)(arg1))))) {
        return 0xffffffff;
    }
    if (((unsigned long)((unsigned int)(arg1)) == 0)) {
        return 0;
    }
    var2 = (long)((((long)arg0 + ((unsigned long)((unsigned int)((arg1 - 1))) * 4)) + 4));
    ret = 0;
    cursor = (int *)arg0;
    do {
        ret = (unsigned long)((unsigned int)((ret + *(int *)((cursor)))));
        cursor = (int *)((cursor + 1));
    } while ((cursor != var2));
    return ret;
}
volatile_const_is_readable pass 7 lines
// glaurung: volatile_const_is_readable @ 0x1180
int32_t volatile_const_is_readable(int32_t arg0) {
    int cell;
    int total;
    cell = arg0;
    return (unsigned int)(((unsigned long)((unsigned int)(cell)) + (unsigned long)((unsigned int)(cell))));
}

← 213 fixtures