https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108580
Bug ID: 108580 Summary: gcc treats shifts as signed operation, does wrong promotion Product: gcc Version: 12.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: postmaster at raasu dot org Target Milestone: --- I have a simple program that fails to compile correctly on any common compiler: int main() { int bits = 8; char* a = (char*)malloc(1 << bits); char* b = (char*)malloc(1 << bits); memcpy(b, a, 1 << bits); return 0; } when assembled with "gcc -S", the result is main: .LFB6: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $32, %rsp movl $8, -20(%rbp) movl -20(%rbp), %eax movl $1, %edx movl %eax, %ecx sall %cl, %edx movl %edx, %eax cltq movq %rax, %rdi call malloc@PLT movq %rax, -16(%rbp) movl -20(%rbp), %eax movl $1, %edx movl %eax, %ecx sall %cl, %edx movl %edx, %eax cltq movq %rax, %rdi call malloc@PLT movq %rax, -8(%rbp) movl -20(%rbp), %eax movl $1, %edx movl %eax, %ecx sall %cl, %edx movl %edx, %eax movslq %eax, %rdx movq -16(%rbp), %rcx movq -8(%rbp), %rax movq %rcx, %rsi movq %rax, %rdi call memcpy@PLT movl $0, %eax leave .cfi_def_cfa 7, 8 ret .cfi_endproc The part that is incorrect is: sall %cl, %edx movl %edx, %eax cltq movq %rax, %rdi It should zero-extend before the shift, but instead it sign-extends after the shift... Bit shifting is always unsigned operation. It correctly determines the function requires 64-bit parameter, but fails to determine it's unsigned. Integer promotion rules say that unsigned type in expression must be promoted to larger unsigned type if it can hold the result. As bit shift is unsigned operation, the temporary should also be unsigned. Stock gcc headers don't have UINTPTR_C() macro which could be used to explicitly cast the constant "1" to pointer size to give hint that the shift is indeed unsigned operation. gcc version is: gcc (Ubuntu 12.2.0-3ubuntu1) 12.2.0