1--TEST-- 2Bug #81249: Intermittent property assignment failure with JIT enabled 3--INI-- 4opcache.enable=1 5opcache.enable_cli=1 6opcache.jit_buffer_size=1M 7opcache.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 14declare(strict_types=1); 15 16final 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 110for ($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?> 128OK 129--EXPECT-- 130OK 131