1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix GH-20838: JIT compiler produces wrong arithmetic results (#21383)

Insert type guards (CHECK_OP1_TRACE_TYPE / CHECK_OP2_TRACE_TYPE) on the
sensitive bailout paths in ADD/SUB/MUL JIT compilation: the MAY_BE_UNDEF
and non-numeric operand breaks. Guards are only emitted when the traced
operand type is IS_LONG or IS_DOUBLE, ensuring TSSA result type
predictions stay valid for side traces without affecting the normal
numeric fast path.


Fixes GH-20838

Co-authored-by: Dmitry Stogov <dmitrystogov@gmail.com>
This commit is contained in:
Ilia Alshanetsky
2026-03-11 08:22:50 -04:00
committed by GitHub
parent 1b61d555fb
commit 80dc4c19d6
3 changed files with 131 additions and 0 deletions

View File

@@ -4510,6 +4510,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
op2_info = OP2_INFO();
op2_addr = OP2_REG_ADDR();
if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
if (op1_type == IS_LONG || op1_type == IS_DOUBLE) {
CHECK_OP1_TRACE_TYPE();
}
if (op2_type == IS_LONG || op2_type == IS_DOUBLE) {
CHECK_OP2_TRACE_TYPE();
}
break;
}
if (opline->opcode == ZEND_ADD &&
@@ -4518,6 +4524,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
/* pass */
} else if (!(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) ||
!(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
if (op1_type == IS_LONG || op1_type == IS_DOUBLE) {
CHECK_OP1_TRACE_TYPE();
}
if (op2_type == IS_LONG || op2_type == IS_DOUBLE) {
CHECK_OP2_TRACE_TYPE();
}
break;
}
if (orig_op1_type != IS_UNKNOWN

View File

@@ -0,0 +1,53 @@
<?php
$result = json_decode('[{"ID":"49"},{"ID":"1080"},{"ID":"4415"},{"ID":"4763"},{"ID":"4926"},{"ID":"4933"},{"ID":"4935"},{"ID":"4938"},{"ID":"4939"},{"ID":"4947"},{"ID":"4952"},{"ID":"4953"},{"ID":"4962"},{"ID":"8558"},{"ID":"14888"},{"ID":"16879"},{"ID":"100003"},{"ID":"100007"},{"ID":"100013"},{"ID":"100017"},{"ID":"100019"},{"ID":"100027"},{"ID":"100031"},{"ID":"106427"},{"ID":"217955"},{"ID":"240000"},{"ID":"240010"},{"ID":"240021"},{"ID":"240079"},{"ID":"240210"},{"ID":"240227"},{"ID":"240249"},{"ID":"240273"},{"ID":"240333"},{"ID":"240335"},{"ID":"300024"},{"ID":"310001"},{"ID":"310025"},{"ID":"310034"},{"ID":"310042"},{"ID":"310111"},{"ID":"310191"},{"ID":"310219"},{"ID":"310236"},{"ID":"310322"},{"ID":"310356"},{"ID":"310360"},{"ID":"310394"},{"ID":"310405"},{"ID":"310411"}]', true);
$result1 = json_decode('[{"ID":"1080","cat":"6","vote":"2"},{"ID":"4415","cat":"1","vote":"5"},{"ID":"4415","cat":"5","vote":"-5"},{"ID":"4763","cat":"1","vote":"5"},{"ID":"4926","cat":"1","vote":"5"},{"ID":"4933","cat":"1","vote":"4"},{"ID":"4935","cat":"1","vote":"5"},{"ID":"4938","cat":"1","vote":"5"},{"ID":"4939","cat":"1","vote":"5"},{"ID":"4947","cat":"1","vote":"4"},{"ID":"4952","cat":"1","vote":"3"},{"ID":"4953","cat":"1","vote":"5"},{"ID":"4962","cat":"1","vote":"4"},{"ID":"8558","cat":"1","vote":"3"},{"ID":"14888","cat":"4","vote":"5"},{"ID":"16879","cat":"4","vote":"-2"},{"ID":"16879","cat":"6","vote":"3"},{"ID":"100003","cat":"1","vote":"0"},{"ID":"100007","cat":"1","vote":"4"},{"ID":"100013","cat":"1","vote":"0"},{"ID":"100017","cat":"6","vote":"4"},{"ID":"100017","cat":"4","vote":"-4"},{"ID":"100019","cat":"1","vote":"1"},{"ID":"100027","cat":"1","vote":"3"},{"ID":"100031","cat":"1","vote":"2"},{"ID":"106427","cat":"5","vote":"-5"},{"ID":"217955","cat":"4","vote":"-1"},{"ID":"217955","cat":"4","vote":"-1"},{"ID":"240000","cat":"1","vote":"2"},{"ID":"240010","cat":"1","vote":"4"},{"ID":"240021","cat":"1","vote":"3"},{"ID":"240079","cat":"1","vote":"4"},{"ID":"240079","cat":"7","vote":"4"},{"ID":"240079","cat":"6","vote":"2"},{"ID":"240210","cat":"1","vote":"3"},{"ID":"240227","cat":"1","vote":"3"},{"ID":"240249","cat":"1","vote":"5"},{"ID":"240273","cat":"1","vote":"5"},{"ID":"240333","cat":"1","vote":"2"},{"ID":"240335","cat":"1","vote":"4"},{"ID":"300024","cat":"3","vote":"4"},{"ID":"300024","cat":"1","vote":"5"},{"ID":"310001","cat":"1","vote":"3"},{"ID":"310025","cat":"1","vote":"3"},{"ID":"310034","cat":"1","vote":"4"},{"ID":"310042","cat":"1","vote":"2"},{"ID":"310111","cat":"1","vote":"5"},{"ID":"310191","cat":"1","vote":"3"},{"ID":"310219","cat":"1","vote":"5"},{"ID":"310236","cat":"1","vote":"1"},{"ID":"310322","cat":"1","vote":"3"},{"ID":"310356","cat":"1","vote":"2"},{"ID":"310360","cat":"1","vote":"3"},{"ID":"310360","cat":"4","vote":"-5"},{"ID":"310394","cat":"1","vote":"1"},{"ID":"310394","cat":"3","vote":"2"},{"ID":"310405","cat":"1","vote":"5"},{"ID":"310411","cat":"1","vote":"4"}]', true);
foreach ($result as $arr) {
$v = [];
foreach ($result1 as $arr1) {
if ($arr1['ID'] == $arr['ID']) $v[] = $arr1;
}
TLVotesStatUpdateBAD($arr['ID'], $v);
}
function TLVotesStatUpdateBAD(int $id, ?array $v = null): float
{
static $k;
if (!isset($k)) $k = json_decode('{"4":{"tp":"20","st":"sum"},"3":{"tp":"30","st":"caa"},"2":{"tp":"60","st":"sum"},"1":{"tp":"50","st":"unique"},"5":{"tp":"50","st":"caa"},"6":{"tp":"20","st":"caa"},"7":{"tp":"60","st":"caa"},"8":{"tp":"60","st":"caa"},"255":{"tp":"0","st":"correction"}}', true);
$pav = 50;
$s = 0.0;
$corrections = 0;
$av = [];
$avc = [];
foreach ($v as $arr) {
if ($k[$arr['cat']]['st'] == 'unique') $av[$arr['cat']] = $arr['vote'];
elseif ($k[$arr['cat']]['st'] == 'correction') {
$av[$arr['cat']] = $arr['vote'];
$corrections++;
} else {
if ($arr['vote'] < 0) $arr['vote'] = $arr['vote'] / 2;
$av[$arr['cat']] ??= 0;
$avc[$arr['cat']] ??= 0;
$av[$arr['cat']] += $arr['vote'];
$avc[$arr['cat']]++;
}
}
if (($c = count($av))) {
$c -= $corrections;
foreach ($av as $key => $value) {
if ($k[$key]['st'] == 'correction') $s += $value;
else {
if ($k[$key]['st'] == 'caa') $value = $value / $avc[$key];
$s += $value / 5 * $k[$key]['tp'] * (1 + 50 / $k[$key]['tp'] * $pav / (100 * $c));
}
}
}
echo("$id $s\n");
return $s;
}

View File

@@ -0,0 +1,66 @@
--TEST--
GH-20838 (JIT compiler produces wrong arithmetic results)
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.jit=tracing
opcache.jit_buffer_size=64M
opcache.jit_hot_loop=61
opcache.jit_hot_func=127
opcache.jit_hot_return=8
opcache.jit_hot_side_exit=8
--EXTENSIONS--
opcache
--FILE_EXTERNAL--
gh20838.inc
--EXPECT--
49 0
1080 18
4415 31.25
4763 75
4926 75
4933 60
4935 75
4938 75
4939 75
4947 60
4952 45
4953 75
4962 60
8558 45
14888 45
16879 13
100003 0
100007 60
100013 0
100017 13
100019 15
100027 45
100031 30
106427 -37.5
217955 -9
240000 30
240010 60
240021 45
240079 112.66666666667
240210 45
240227 45
240249 75
240273 75
240333 30
240335 60
300024 96.5
310001 45
310025 45
310034 60
310042 30
310111 75
310191 45
310219 75
310236 15
310322 45
310356 30
310360 21.25
310394 29.5
310405 75
310411 60