Skip to content

Commit c0e4932

Browse files
committed
Fixed bug #81249 (Intermittent property assignment failure with JIT enabled)
1 parent ee98161 commit c0e4932

File tree

3 files changed

+134
-2
lines changed

3 files changed

+134
-2
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ PHP NEWS
1414
- Opcache:
1515
. Fixed bug #81225 (Wrong result with pow operator with JIT enabled).
1616
(Dmitry)
17+
. Fixed bug #81249 (Intermittent property assignment failure with JIT
18+
enabled). (Dmitry)
1719

1820
- Standard:
1921
. Fixed bug #72146 (Integer overflow on substr_replace). (cmb)

ext/opcache/jit/zend_jit_trace.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3502,12 +3502,12 @@ static zend_bool zend_jit_may_skip_comparison(const zend_op *opline, const zend_
35023502
|| prev_opcode == ZEND_IS_NOT_IDENTICAL
35033503
|| prev_opcode == ZEND_CASE_STRICT) {
35043504
if (ssa_op->op1_use < 0) {
3505-
if (opline->op1.constant != ssa_opcodes[prev_ssa_op - ssa->ops]->op1.constant) {
3505+
if (RT_CONSTANT(opline, opline->op1) != RT_CONSTANT(&ssa_opcodes[prev_ssa_op - ssa->ops], ssa_opcodes[prev_ssa_op - ssa->ops]->op1)) {
35063506
return 0;
35073507
}
35083508
}
35093509
if (ssa_op->op2_use < 0) {
3510-
if (opline->op2.constant != ssa_opcodes[prev_ssa_op - ssa->ops]->op2.constant) {
3510+
if (RT_CONSTANT(opline, opline->op2) != RT_CONSTANT(&ssa_opcodes[prev_ssa_op - ssa->ops], ssa_opcodes[prev_ssa_op - ssa->ops]->op2)) {
35113511
return 0;
35123512
}
35133513
}

ext/opcache/tests/jit/bug81249.phpt

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
--TEST--
2+
Bug #81249: Intermittent property assignment failure with JIT enabled
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.jit_buffer_size=1M
7+
opcache.jit=tracing
8+
--SKIPIF--
9+
<?php require_once('skipif.inc'); ?>
10+
<?php if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); ?>
11+
--FILE--
12+
<?php
13+
14+
declare(strict_types=1);
15+
16+
final class EucJpDecoder
17+
{
18+
private const JIS0212_INDEX = [108 => 728];
19+
private const JIS0208_INDEX = [];
20+
21+
private const CONTINUE = -1;
22+
private const FINISHED = -2;
23+
private const ERROR = -3;
24+
25+
/**
26+
* @var int
27+
*/
28+
private $lead;
29+
30+
/**
31+
* @var bool
32+
*/
33+
private $isJis0212;
34+
35+
public function __construct()
36+
{
37+
$this->lead = 0x00;
38+
$this->isJis0212 = false;
39+
}
40+
41+
public function handle(array &$ioQueue, string $byte): int
42+
{
43+
if ($byte === '') {
44+
if ($this->lead !== 0x00) {
45+
$this->lead = 0x00;
46+
47+
return self::ERROR;
48+
}
49+
50+
return self::FINISHED;
51+
}
52+
53+
$byte = ord($byte);
54+
55+
if ($this->lead === 0x8E && ($byte >= 0xA1 && $byte <= 0xDF)) {
56+
$this->lead = 0x00;
57+
58+
return 0xFF61 - 0xA1 + $byte;
59+
}
60+
61+
if ($this->lead === 0x8F && ($byte >= 0xA1 && $byte <= 0xFE)) {
62+
$this->isJis0212 = true;
63+
$this->lead = $byte;
64+
65+
return self::CONTINUE;
66+
}
67+
68+
if ($this->lead !== 0x00) {
69+
$lead = $this->lead;
70+
$this->lead = 0x00;
71+
$codePoint = null;
72+
73+
if (($lead >= 0xA1 && $lead <= 0xFE) && ($byte >= 0xA1 && $byte <= 0xFE)) {
74+
$index = self::JIS0208_INDEX;
75+
76+
if ($this->isJis0212) {
77+
$index = self::JIS0212_INDEX;
78+
}
79+
80+
$codePoint = $index[($lead - 0xA1) * 94 + $byte - 0xA1] ?? null;
81+
}
82+
83+
$this->isJis0212 = false;
84+
85+
if ($codePoint !== null) {
86+
return $codePoint;
87+
}
88+
89+
if ($byte <= 0x7F) {
90+
array_unshift($ioQueue, chr($byte));
91+
}
92+
93+
return self::ERROR;
94+
}
95+
96+
if ($byte <= 0x7F) {
97+
return $byte;
98+
}
99+
100+
if ($byte === 0x8E || $byte === 0x8F || ($byte >= 0xA1 && $byte <= 0xFE)) {
101+
$this->lead = $byte;
102+
103+
return self::CONTINUE;
104+
}
105+
106+
return self::ERROR;
107+
}
108+
}
109+
110+
for ($i = 0; $i < 2000; ++$i) {
111+
$decoder = new EucJpDecoder();
112+
113+
$bytes = ["\x8F", "\xA2", "\xAF", ''];
114+
$out = null;
115+
116+
foreach ($bytes as $byte) {
117+
$result = $decoder->handle($bytes, $byte);
118+
119+
if ($result >= 0) {
120+
$out = $result;
121+
}
122+
}
123+
124+
// $bytes array should be decoded to U+2D8, decimal 728
125+
assert($out === 728);
126+
}
127+
?>
128+
OK
129+
--EXPECT--
130+
OK

0 commit comments

Comments
 (0)