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