php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #81249 Intermittent property assignment failure with JIT enabled
Submitted: 2021-07-12 03:46 UTC Modified: 2021-07-12 08:13 UTC
From: smokey101stair at gmail dot com Assigned: dmitry (profile)
Status: Closed Package: JIT
PHP Version: 8.0.8 OS: Ubuntu 20.04
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: smokey101stair at gmail dot com
New email:
PHP Version: OS:

 

 [2021-07-12 03:46 UTC] smokey101stair at gmail dot com
Description:
------------
PHP 8.0.8 (cli) (built: Jul  4 2021 21:22:34) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.8, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.8, Copyright (c), by Zend Technologies

PHP was compiled using PHPBrew, if that makes a difference.

opcache.jit=1255
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.jit_buffer_size=256M
zend.assertions=1

The test script decodes EUC-JP text to Unicode Code Points. I tried to reduce the script as much as possible, but it was very temperamental when removing if statements.

When processing the first byte, 8F, the assignment at https://gist.github.com/TRowbotham/4dc7c8dc1714edab69019e0d71c17c02#file-jit1-php-L90 fails intermittently. This leaves $this->lead set to its initial value of 0, which eventually leads to the script returning an error instead of a code point.

The script is expected to transform the EUC-JP encoded bytes to the Unicode U+2D8 code point.

Test script:
---------------
https://gist.github.com/TRowbotham/4dc7c8dc1714edab69019e0d71c17c02


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-07-12 08:13 UTC] nikic@php.net
-Status: Open +Status: Verified -Assigned To: +Assigned To: dmitry
 [2021-07-19 00:30 UTC] hao dot sun at arm dot com
FYI.

1. This bug occurred for master branch as well, for both JIT/x86 and JIT/arm64.
2. In my test, the test case can be further downsized, that is, Lines 85 to 87 can be removed as well, i.e. https://gist.github.com/TRowbotham/4dc7c8dc1714edab69019e0d71c17c02#file-jit1-php-L85-L87
3. I suspect this bug is due to "hot side exit".
1) -d opcache.jit_hot_side_exit=0, this bug is gone.
2) -d opcache.jit_hot_side_exit=N, the smaller the number we assigned, the earlier this bug showed up.
 [2021-07-19 06:27 UTC] hao dot sun at arm dot com
Based on my local debugging, I suspected function zend_jit_may_skip_comparison().

Code is not generated as expected for the hot side trace for statement: "if ($byte === 0x8E || $byte === 0x8F || ($byte >= 0xA1 && $byte <= 0xFE)) {"
Here is trace #5: (Note several "echo" statements are inserted in my local debugging). For "$byte === 0x8E || $byte === 0x8F", there are two IS_IDENTICAL opcodes.

     TRACE 3 exit 1 EucJpDecoder::handle() /home/haosun01/php/7.php:91
---- TRACE 5 start (side trace 3/1) EucJpDecoder::handle() /home/haosun01/php/7.php:91
========3333333 143
===== 44444444 set lead here: 143 : 143
0086 T7 = ROPE_INIT 3 string("========3333333 ")
0087 T7 = ROPE_ADD 1 T7 CV1($byte) ; op2(int)
0088 T6 = ROPE_END 2 T7 string("
")
0089 ECHO T6 ; op1(string)
0090 T6 = IS_IDENTICAL CV1($byte) int(142) ; op1(int)
0091 ;JMPNZ T6 0098
0092 T6 = IS_IDENTICAL CV1($byte) int(143) ; op1(int)
0093 ;JMPNZ T6 0098
0098 ASSIGN_OBJ THIS string("lead") ; op3(int)
0099 ;OP_DATA CV1($byte)
0100 T7 = ROPE_INIT 5 string("===== 44444444 set lead here: ")
0101 T7 = ROPE_ADD 1 T7 CV1($byte) ; op2(int)
0102 T7 = ROPE_ADD 2 T7 string(" : ")
0103 T6 = FETCH_OBJ_R THIS string("lead")
0104 T7 = ROPE_ADD 3 T7 T6 ; op2(int)
0105 T6 = ROPE_END 4 T7 string("
")
0106 ECHO T6 ; op1(string)
0107 RETURN int(-1)
---- TRACE 5 stop (return)


However, in the compiled code, I found that only the code for "$byte === 0x8E" is generated. Here is part of the code. See "cmp x15, #0x8e".

.L1:
    ffffbb9c8250:       movz x15, #0x51c0
    ffffbb9c8254:       movk x15, #0xabb6, lsl #16
    ffffbb9c8258:       movk x15, #0xaaaa, lsl #32
    ffffbb9c825c:       ldr x8, [x15]
    ffffbb9c8260:       cbnz x8, #JIT$$exception_handler
    ffffbb9c8264:       ldr x15, [x27, #0x60]
    ffffbb9c8268:       cmp x15, #0x8e
    ffffbb9c826c:       b.eq #jit$$trace_exit_0
    ffffbb9c8270:       b.ne #jit$$trace_exit_1
    ffffbb9c8274:       ldr x0, [x27, #0x20]
    ffffbb9c8278:       ldrb w16, [x0, #0x30]
    ffffbb9c827c:       cbz w16, #jit$$trace_exit_2
    ffffbb9c8280:       add x0, x0, #0x28
    ffffbb9c8284:       add x1, x27, #0x60
    ffffbb9c8288:       adrp x8, #0xffffb4298000
    ffffbb9c828c:       add x8, x8, #0xa70
    ffffbb9c8290:       str x8, [x27]
    ffffbb9c8294:       bl #JIT$$assign_tmp
    ffffbb9c8298:       movz x15, #0x51c0
    ffffbb9c829c:       movk x15, #0xabb6, lsl #16
    ffffbb9c82a0:       movk x15, #0xaaaa, lsl #32
    ffffbb9c82a4:       ldr x8, [x15]
    ffffbb9c82a8:       cbnz x8, #JIT$$exception_handler
    ffffbb9c82ac:       movz x15, #0x160
    ffffbb9c82b0:       add x28, x28, x15


That is because "skip_comparison" is set as true for the second ZEND_IS_IDENTICAL, i.e. JIT is bypassed.
In details, in file zend_jit_trace.c, these code (https://github.com/php/php-src/blob/master/ext/opcache/jit/zend_jit_trace.c#L4762-L4812) is used to generate the JIT code for ZEND_IS_IDENTICAL. However, I found that variable "skip_comparison" is set as false for "$byte === 0x8E", but is set as true for "$byte === 0x8F".
I further looked at function zend_jit_may_skip_comparison(). I noticed that for $byte === 0x8F, this function returns "1" at https://github.com/php/php-src/blob/master/ext/opcache/jit/zend_jit_trace.c#L3568



In one word, I guess the root cause of this bug lies in how to determine "skip_comparison" for the case of two consecutive "ZEND_IS_IDENTICAL".
As I tried, if we always set variable "skip_comparison" as false, this bug can be gone.
 [2021-07-19 09:15 UTC] git@php.net
Automatic comment on behalf of dstogov
Revision: https://github.com/php/php-src/commit/c0e49328168bee315e72f21543b2ef2c01ad9169
Log: Fixed bug #81249 (Intermittent property assignment failure with JIT enabled)
 [2021-07-19 09:15 UTC] git@php.net
-Status: Verified +Status: Closed
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 14:01:29 2024 UTC