https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96447
Martin Sebor <msebor at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |NEW Keywords| |diagnostic, | |missed-optimization Component|other |tree-optimization CC| |msebor at gcc dot gnu.org Summary|False positive |False positive |-Wstringop-overflow with |-Wstringop-overflow with |-O3 |-O3 due to loop unrolling Last reconfirmed| |2020-08-03 Ever confirmed|0 |1 --- Comment #1 from Martin Sebor <msebor at gcc dot gnu.org> --- The warning works as designed. The false positive is caused by the assignment below in the unrolled loop with the index in RANGE [4, 5]. GCC doesn't understand that the constraint on bpp implies that i < 4, likely because the range of bpp is discontiguous. ;; basic block 19, loop depth 0, count 0 (precise), probably never executed ;; prev block 18, next block 20, flags: (NEW, REACHABLE, VISITED) ;; pred: 18 [80.0% (guessed)] count:0 (precise) (TRUE_VALUE,EXECUTABLE) # .MEM_3 = VDEF <.MEM_50> dataD.1941[i_49] = 0; # RANGE [4, 5] NONZERO 5 i_2 = i_49 + 1; # RANGE [32, 32] NONZERO 32 _1 = _6 + 8; if (bpp_25 > 32) goto <bb 20>; [80.00%] else goto <bb 16>; [20.00%] ;; succ: 20 [80.0% (guessed)] count:0 (precise) (TRUE_VALUE,EXECUTABLE) ;; 16 [20.0% (guessed)] count:0 (precise) (FALSE_VALUE,EXECUTABLE) ;; basic block 20, loop depth 0, count 0 (precise), probably never executed ;; prev block 19, next block 21, flags: (NEW, REACHABLE, VISITED) ;; pred: 19 [80.0% (guessed)] count:0 (precise) (TRUE_VALUE,EXECUTABLE) # .MEM_45 = VDEF <.MEM_3> dataD.1941[i_2] = 0; <<< warning The warning can be avoided by constraining the range of bpp to [1, 4] instead (by shifting it to the right by 3 bits) and changing the loop test to i < bpp. That also leads to GCC emitting better code. int load(input * s) { unsigned char bpp = get8u (s); if(bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32) { return 0; } bpp >>= 3; unsigned char data[4]; for(int i = 0; i < bpp; ++i) { data[i] = get8u (s); }