https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77673
Bug ID: 77673 Summary: 4-byte load generated instead of 1-byte load, possibly reading past the end of object Product: gcc Version: 5.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: laurynas.biveinis at gmail dot com Target Milestone: --- For the following function void mach_parse_compressed(unsigned char* ptr, unsigned long int* val) { if (ptr[0] < 0xC0U) { *val = ptr[0] + ptr[1]; return; } *val = ((unsigned long int)(ptr[0]) << 24) | ((unsigned long int)(ptr[1]) << 16) | ((unsigned long int)(ptr[2]) << 8) | ptr[3]; } starting with GCC 5.1, with -O2 -fPIC, the following is generated on x86_64: mach_parse_compressed(unsigned char*, unsigned long*): movl (%rdi), %eax <--- this load is not safe before branching bswap %eax movl %eax, %edx movzbl (%rdi), %eax cmpb $-65, %al jbe .L5 movl %edx, %eax movq %rax, (%rsi) ret .L5: movzbl 1(%rdi), %edx addl %edx, %eax cltq movq %rax, (%rsi) ret "movl (%rdi), %eax" loads all of ptr[0]..ptr[3] even though before we compare ptr[0] with 0xC0U, we don't know whether we can assume that ptr[1]..ptr[3] does not point past the end of an object. GCC 5.1/5.2/5.3/5.4/6.1/6.2 are all affected. Versions 4.7, 4.8, 4.9 are not. I have checked this using Ubuntu GCC build and http://gcc.godbolt.org/. If necessary, I can build GCC from pristine .tar.gz and re-test.