On Mon, Jul 30, 2018 at 09:08:31AM +0100, Wei Liu wrote: > Hello, > > We have a program which fails to build with gcc 8.1 -m32 -O2 (version > Debian 8.1.0-12). We couldn't figure out how the optimiser came up with > the idea that array bounds could become negative. Any help would be > appreciated. The attached code has been simplified from the original to > reproduce the issue. > > The same code snippet builds find with 8.1 debug build and older > versions of gcc. > > $ gcc -m32 -march=i686 -std=gnu99 -Wall -O2 -Werror -c -o t.o t.c > t.c: In function 'func': > t.c:41:9: error: 'memcpy' offset [-204, -717] is out of the bounds [0, 216] of object 'ctrl' with type 'struct kdd_ctrl' [-Werror=array-bounds] > memcpy(buf, ((uint8_t *)&ctrl.c32) + offset, len); > ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > t.c:27:21: note: 'ctrl' declared here > struct kdd_ctrl ctrl; > > <code> > #include <stdint.h> > #include <string.h> > > struct kdd_ctrl_32 { > uint8_t _[84]; > }; > > struct kdd_ctrl_64 { > uint8_t _[216]; > }; > > struct kdd_ctrl { > union { > struct kdd_ctrl_32 c32; > struct kdd_ctrl_64 c64; > }; > }; > > typedef struct { > uint8_t buf[17 + 65536]; > uint32_t length_req; > uint64_t addr; > } kdd_state; > > void func(kdd_state *s) > { > struct kdd_ctrl ctrl; > uint8_t *buf = s->buf + 17 + 57; > uint32_t len = s->length_req; > uint64_t addr = s->addr; Sorry for not mentioning this earlier, length_req(len) is bound within [0, 65535] here. I deleted the bound check because it didn't affect how the error is triggered. > > uint32_t offset = addr; > > /* 32-bit control-register space starts at 0x[2]cc, for 84 bytes */ > if (offset > 0x200) > offset -= 0x200; > offset -= 0xcc; > if (offset > sizeof ctrl.c32 || offset + len > sizeof ctrl.c32) { > len = 0; > } else { > memcpy(buf, ((uint8_t *)&ctrl.c32) + offset, len); > } > } > </code> > > Regards, > Wei.