Hacker News new | ask | show | jobs
by comex 4398 days ago
C:

    #include <stdio.h>
    #include <stdbool.h>
    #include <stdlib.h>

    int nums[5] = {1, 0, 1, 0, 1};
    static int cur;

    int main(int argc, char **argv) {
        for(int i = 1; nums[i] != 5 && i < 10; i++) {
            cur = i;
            if(i/4 == 1) {
                printf("2 + 2 <= %d = %s\n", cur, 2 + 2 <= i ? "true" : "false");
                printf("2 + 2 == %d = %s\n", cur, 2 + 2 == i ? "true" : "false");
                printf("\n");
            }
        }
    }
No strange array writes! No indirect writes at all!

It's finicky and I believe depends on register allocation, but when I compile it using whatever version of gcc-mp-4.9 I have installed from MacPorts at -O3, it outputs, among other things:

    2 + 2 == 5 = true
(For all they say about evil optimizing compilers, it was really hard to make this work.)
1 comments

Can anyone explain? It didn't work for me but still gives odd results depending on optimization level that I don't understand.
Because nums is a length 5 array, and the loop condition checks nums[i], GCC assumes going into the loop that i is a valid index, i.e. i <= 4. The division then rules out the possibility that i < 4, so for the purposes of optimization, my version of GCC thinks that i always equals 4 at the printfs, even if it's actually higher.

It's based on an old Linux bug... I should learn more about GCC internals in order to tell tell why I couldn't get it to work without a loop. In general, any sequence where some property not holding would cause undefined behavior to occur allows a conforming compiler to assume it does hold, but for most basic examples neither GCC nor Clang does anything special.

Great explanation and fun exploit, thanks!