Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compiling with optimization gets a condition wrong

This piece of code has a bug in the loop termination condition. However, I still don't understand the compiler's decision - it seems to be getting into the loop one more time.

#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[])
{
    #define ARR_SIZE 25
    int a[ARR_SIZE];
    memset (a,1,sizeof(a)); /*filling the array with non-zeros*/

    int i = 0;

    for (i=0; (a[i] != 0 && i < ARR_SIZE); i++)
    {
        printf ("i=%d a[i]=%d\n",i,a[i]);
    }
    return 0;
}

When compiling this with -O2 or -O3 the loop is not terminated when expected - it prints also a line for when i == ARR_SIZE.

> gcc -O3  test_loop.c
> ./a.out
i=0 a[i]=16843009
i=1 a[i]=16843009
...
i=23 a[i]=16843009
i=24 a[i]=16843009
i=25 a[i]=32766      <=== Don't understand this one.

>  gcc -O0  test_loop.c
>  a.out
i=0 a[i]=16843009
i=1 a[i]=16843009
...
i=23 a[i]=16843009
i=24 a[i]=16843009
>

The gcc version is this: gcc version 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)

I don't see this happening on gcc 4.4.7-18.

Also other sizes of ARR_SIZE doesn't give the same results.

like image 782
banj Avatar asked Dec 23 '22 19:12

banj


1 Answers

When i == ARR_SIZE your condition will evaluate a[i] invoking UB

for (i=0; (a[i] != 0 && i < ARR_SIZE); i++)
//         ^^^^ Undefined Behaviour
{
    printf ("i=%d a[i]=%d\n",i,a[i]);
}

Swap the conditions: for (... (i < ARR_SIZE && a[i] != 0) ...) to take advantage of "short-circuit boolean evaluation".

like image 121
pmg Avatar answered Dec 26 '22 12:12

pmg