Bug #81225 [Ver->Csd]: Wrong result with pow operator with JIT enabled

From: Date: Mon, 19 Jul 2021 07:43:34 +0000
Subject: Bug #81225 [Ver->Csd]: Wrong result with pow operator with JIT enabled
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-235157@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=81225&edit=1 ID: 81225 Updated by: git@php.net Reported by: smokey101stair at gmail dot com Summary: Wrong result with pow operator with JIT enabled -Status: Verified +Status: Closed Type: Bug Package: JIT Operating System: Ubuntu 20.04 PHP Version: 8.0.8 Assigned To: dmitry Block user comment: N Private report: N New Comment: Automatic comment on behalf of dstogov Revision: https://github.com/php/php-src/commit/9cd437138e2a7c172427876c8754b445fa1e1ab1 Log: Fixed bug #81225 (Wrong result with pow operator with JIT enabled) Previous Comments: ------------------------------------------------------------------------ [2021-07-12 05:48:10] hao dot sun at arm dot com Based on my analysis, the root cause is "lea (%rdx), %rdx". "lea" instruction would be used to optimize "add" or "sub" with constants in JIT/x86. See https://github.com/php/php-src/blob/master/ext/opcache/jit/zend_jit_x86.dasc#L4296-L4310 In this test case, the "lea" is generated at line 4300. As @nikic suspected, it's an issue of encoding of immediate > 32bits. AFAIK, for "lea reg, [reg + imm]" in x86_64, the imm field should not be > 32bits, otherwise, truncation would be done. One possible solution may be adding one check, whether "Z_LVAL_P(Z_ZV(op2_addr))" can be represented by 32-bits, just before L4300. Note that this bug doesn't affect JIT/arm64 in master branch, since "lea" optimization is not conducted in arm64. ------------------------------------------------------------------------ [2021-07-06 12:48:03] nikic@php.net Also reproduces with function JIT. I see these lines: 492d4da3: mov $0x100000000, %rcx 492d4dad: cqo 492d4daf: idiv %rcx 492d4db2: test %rdx, %rdx jge .L2 492d4db7: lea (%rdx), %rdx .L2: The lea looks suspicious to me, maybe there is an issue with encoding of immediates > 32-bit? ------------------------------------------------------------------------ [2021-07-05 23:31:30] smokey101stair at gmail dot com Description: ------------ When the JIT is enabled, the test script sometimes returns -4294967294 instead of 2. This seems to be related to the ** operator as it appears to work fine if replaced with the pow() function. I get the following with opcache.jit_debug=1 TRACE-1$/home/trevor/jit_test.php$16: ; (unknown) mov $EG(jit_trace_num), %rax mov $0x1, (%rax) mov $EG(vm_stack_end), %rax mov (%rax), %rcx mov $EG(vm_stack_top), %rax sub (%rax), %rcx cmp $0xf0, %rcx jb jit$$trace_exit_0 .L1: cmp $0x4, 0x68(%r14) jnz jit$$trace_exit_1 cmp $0xc8, 0x60(%r14) jge jit$$trace_exit_2 add $0xfffffffffffffec0, %r15 mov $0x5633ad4d2080, %rax call *%rax mov $EG(exception), %rcx cmp $0x0, (%rcx) jnz JIT$$exception_handler cmp $0x41675ab8, %r15d jnz jit$$trace_exit_3 mov $EG(vm_stack_top), %r15 mov (%r15), %r15 mov $EG(vm_stack_top), %rdx add $0x70, (%rdx) mov $0x0, 0x28(%r15) mov $0x5633af37bbf0, %rcx mov %rcx, 0x18(%r15) mov $0x0, 0x20(%r15) mov $0x2, 0x2c(%r15) mov $0x0, 0x30(%r15) mov %r15, 0x8(%r14) mov 0x40(%r14), %rax mov 0x10(%rax), %rax test %rax, %rax jz .L7 .L2: mov $EG(vm_stack_top), %r15 mov (%r15), %r15 mov $EG(vm_stack_top), %rdx add $0x80, (%rdx) mov $0x0, 0x28(%r15) mov %rax, 0x18(%r15) mov $0x0, 0x20(%r15) mov $0x1, 0x2c(%r15) cmp $0x4, 0x58(%r14) jnz jit$$trace_exit_4 mov 0x50(%r14), %rdx mov %rdx, 0x50(%r15) mov $0x4, 0x58(%r15) mov $0x41675b18, (%r14) mov %r14, 0x30(%r15) mov $0x0, 0x8(%r15) lea 0x80(%r14), %rdx mov %rdx, 0x10(%r15) mov 0x18(%r15), %rax mov 0x50(%rax), %rdx mov $0x5633ae520f78, %rcx add (%rcx), %rdx mov (%rdx), %rdx mov %rdx, 0x40(%r15) mov $EG(current_execute_data), %rcx mov %r15, (%rcx) mov %r15, %r14 mov $0x0, 0x68(%r15) cmp $0x1, 0x2c(%r14) jb jit$$trace_exit_5 cmp $0x4, 0x58(%r14) jnz .L8 .L3: mov 0x50(%r14), %rax mov $0x100000000, %rcx cqo idiv %rcx test %rdx, %rdx jge jit$$trace_exit_6 lea (%rdx), %rdx mov 0x10(%r14), %rcx mov %rdx, (%rcx) mov $0x4, 0x8(%rcx) mov $EG(vm_stack_top), %rax mov %r14, (%rax) mov 0x30(%r14), %r14 mov $EG(current_execute_data), %rax mov %r14, (%rax) cmp $0x2, 0x80(%r14) setz %al movzx %al, %eax add $0x2, %eax mov %eax, 0x78(%r14) cmp $0x3, 0x78(%r14) jnz jit$$trace_exit_7 mov 0x8(%r14), %r15 mov $0x3, 0x58(%r15) mov $0x40f454d0, 0x60(%r15) mov $0x6, 0x68(%r15) mov $0x41675b98, (%r14) mov $0x0, 0x8(%r14) mov %r14, 0x30(%r15) mov %rsp, %rsi mov $0x1, 0x8(%rsi) mov $EG(current_execute_data), %rcx mov %r15, (%rcx) mov %r15, %rdi mov $0x5633ad3dbfb0, %rax call *%rax mov $EG(current_execute_data), %rax mov %r14, (%rax) test $0x1, 0x59(%r15) jnz .L9 .L4: test $0x1, 0x69(%r15) jnz .L10 .L5: mov $EG(vm_stack_top), %rax mov %r15, (%rax) mov $EG(exception), %rax cmp $0x0, (%rax) jnz JIT$$icall_throw mov $EG(vm_interrupt), %rax cmp $0x0, (%rax) jnz jit$$trace_exit_8 cmp $0x4, 0x68(%r14) jnz jit$$trace_exit_9 add $0x1, 0x60(%r14) jo .L11 .L6: mov $0x41675bd8, %r15 mov $EG(vm_interrupt), %rax cmp $0x0, (%rax) jz .L1 jmp JIT$$interrupt_handler .L7: mov $0x416757a0, %rdi mov $zend_jit_init_func_run_time_cache_helper, %rax call *%rax mov 0x40(%r14), %rcx mov %rax, 0x10(%rcx) jmp .L2 .L8: lea 0x50(%r14), %rdi mov $0x416758a8, (%r14) mov $0x41675988, %rsi mov $zend_jit_verify_arg_slow, %rax call *%rax test %al, %al jnz .L3 jmp JIT$$exception_handler .L9: mov 0x50(%r15), %rdi sub $0x1, (%rdi) jnz .L4 mov $0x41675b98, (%r14) mov $rc_dtor_func, %rax call *%rax jmp .L4 .L10: mov 0x60(%r15), %rdi sub $0x1, (%rdi) jnz .L5 mov $0x41675b98, (%r14) mov $rc_dtor_func, %rax call *%rax jmp .L5 .L11: mov $0x43e0000000000000, %rax mov %rax, 0x60(%r14) mov $0x5, 0x68(%r14) jmp .L6 Test script: --------------- <?php function unsignedLong(int $offset): int { $normalizedOffset = $offset % (2 ** 32); if ($normalizedOffset < 0) { $normalizedOffset += 2 ** 32; } return $normalizedOffset; } $offset = -0x100000000 + 2; for ($i = 0; $i < 200; ++$i) { assert(unsignedLong($offset) === 2); } ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=81225&edit=1

« previous php.bugs (#235157) next »