Thiago
Thiago

Reputation: 65

Erroneous Code + GCC 5.4 Optimisation Causes Infinite Loop

Disclaimer:

The following code compiled using gcc 5.4.0 with optimisation enabled on Ubuntu 16.04, when executed, generates a infinite loop:

#include <stdio.h>


void *loop(char *filename){

    int counter = 10;
    int level = 0;
    char *filenames[10];
    filenames[0] = filename;

    while (counter-- > 0) {

        level++;
        if (level > 10) {
            break;
        }

        printf("Level %d - MAX_LEVELS %d\n", level, 10);
        filenames[level] = filename;

    }

    return NULL;
}

int main(int argc, char *argv[]) {
    loop(argv[0]);
}

The compiler versions:

gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.

The compilation command used:

gcc infinite.c -O2  -o infinite

I know that it is caused by the optimisation flag "-02" because it doesn't happen without it. I also Know that adding volatile to the variable "level" also fix the error. But I can't add this keyword to all my variables.

My question is, why this happen and what can I do to avoid it in the future?

Is there any gcc flag that still optimise the code at a similar level of -O2 without this kind of problem?

Upvotes: 2

Views: 213

Answers (2)

Joon Park
Joon Park

Reputation: 11

To prevent this optimization, you can use "-fno-aggressive-loop-optimizations".

Upvotes: 1

You've found an example of undefined behaviour causing the optimizer to do something unexpected! GCC can see that if the loop runs 10 times then there is undefined behaviour.

This code will write filenames[1] through filenames[10] i.e. the 2nd through 11th elements of filenames. However filenames is 10 elements long, so the last one is undefined behaviour.

Because you aren't allowed to have undefined behaviour, it can assume that the loop will stop some other way before it gets to 10 (perhaps you have a modified version of printf that will call exit?).

And it sees that if the loop is going to stop anyway before it gets to 10, there is no point having code to make it only run 10 times. So it removes that code.

Upvotes: 6

Related Questions