Bug 71567 - Incorrect loop optimization
Summary: Incorrect loop optimization
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.8.5
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-06-17 13:42 UTC by Artem
Modified: 2016-06-27 22:37 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Artem 2016-06-17 13:42:08 UTC
#define NIN 2


struct struct1 {
    char ggint[NIN][6];
    char dummy;
};
/*----------------------------------------------------------------------*/
int get_struct1cnt(struct struct1 *gr)
{
    int i=0 ;
    for ( i=0 ; *(gr->ggint[i]) != '\0' && i < NIN ; ++i )
        ;
    return i ;
}
/*----------------------------------------------------------------------*/
int main (int argc, char **argv)
{
    struct struct1 grp = {0};

    for ( int i=0 ; i < NIN ; i++ )
        grp.ggint[i][0] = 'A'+i;
    printf("%d\n", get_struct1cnt (&grp));

    return 0;
}

When compiled with gcc -O -std=c99 one.c: the program display 1.
When compiled with gcc -std=c99 one.c: the programm display 2 as expcted

If optimization level is -Og or not, the program displays 2, if optimization level is -O or higher, the program displays 1.

Note: removing dummy field from struct struct1 make this bug not reproducable
Comment 1 Andrew Pinski 2016-06-17 14:20:33 UTC
This:
*(gr->ggint[i]) != '\0' && i < NIN 

is reading one past the array bounds.  Swapping the operands of && fixes the problem.

The reason dummy influences GCC optimization is that if it is not there, GCC assumes struct1 has a flexible array at the end of it.
Comment 2 Artem 2016-06-21 06:55:00 UTC
Thank you for help.
Could you please also advise which kind of optimization performed here. Could it be switched off by using some compiler options? (because there are a lot of such places in the source code)
Also I notice that such behavior reproduced only with NIN defined to values from 2 to 4. If the value is grater such behavior is not reproduced.
Comment 3 Andrew Pinski 2016-06-21 06:56:28 UTC
Try -fno-aggressive-loop-optimizations .
Comment 4 Artem 2016-06-21 07:17:33 UTC
Thank you very much.
This help
Comment 5 Manuel López-Ibáñez 2016-06-21 20:55:12 UTC
(In reply to Andrew Pinski from comment #3)
> Try -fno-aggressive-loop-optimizations .

Note that it is not ensured that switch will disable all optimizations that rely on undefined behavior: https://gcc.gnu.org/wiki/FAQ#misoptimization

Your code is still broken and it may get miscompiled with a different version of GCC or a different compiler or due to any changes to the surrounding code.
Comment 6 Artem 2016-06-22 22:35:15 UTC
(In reply to Manuel López-Ibáñez from comment #5)
> 
> Your code is still broken and it may get miscompiled with a different
> version of GCC or a different compiler or due to any changes to the
> surrounding code.

Is there any way to indicate such kind of errors during compilation.
I tried to add options -Wall -Waggressive-loop-optimizations for compilation code from the description. But I didn't get any warnings related to "reading one past the array bounds".
Which kind of warnings are switched on by adding -Waggressive-loop-optimizations?

Could you please advise
Thank you
Artem
Comment 7 Manuel López-Ibáñez 2016-06-23 09:45:26 UTC
(In reply to Artem from comment #6)
> Is there any way to indicate such kind of errors during compilation.
> I tried to add options -Wall -Waggressive-loop-optimizations for compilation
> code from the description. But I didn't get any warnings related to "reading
> one past the array bounds".
> Which kind of warnings are switched on by adding
> -Waggressive-loop-optimizations?

See https://gcc.gnu.org/wiki/FAQ#misoptimization

and https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#Warning-Options
Comment 8 Artem 2016-06-23 15:31:28 UTC
(In reply to Manuel López-Ibáñez from comment #7)
> See https://gcc.gnu.org/wiki/FAQ#misoptimization
> 
> and https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#Warning-Options

Thank you for the links.

However I am not able to find compilation keys to indicate initial problem. Could you please provide an example when -Waggressive-loop-optimizations returns warning?
You say that solution with using -fno-aggressive-loop-optimizations does not guaranty correct compilation.
Maybe switch off optimization at all could help to avoid problems related to "undefined behavior" during optimization. Could you please, advise. I understand that source code will be broken but it have already worked correctly for many years with xlC compiler.
Comment 9 Artem 2016-06-27 21:22:21 UTC
The described behaviour of optimizer seems to be very dengerous because it is hard to indicate such kind of errors (it cannot be indicated during compilation, cppcheck does not report such kind of errors, such errors could not be reproduced in debug mode and could exist alive in silent mode for years).
Is it possible to report such kind of errors during compilation? Looks like such kind of errors could be indicated during compilation or static code anlisys.
Comment 10 Andrew Pinski 2016-06-27 22:37:07 UTC
-fsanitize=undefined can be used to find some of these.

This enables:

-fsanitize=bounds
This option enables instrumentation of array bounds. Various out of bounds accesses are detected. Flexible array members, flexible array member-like arrays, and initializers of variables with static storage are not instrumented. 

Note the last part of it too because without dummy, GCC considers the array as "flexible array member-like arrays"