Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

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.)


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!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: