[Bug c/108580] New: gcc treats shifts as signed operation, does wrong promotion
postmaster at raasu dot org
gcc-bugzilla@gcc.gnu.org
Sat Jan 28 07:42:06 GMT 2023
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
More information about the Gcc-bugs
mailing list