Skip to content

Commit f4770bc

Browse files
committed
Fix GH-20733: heap buffer overflow in optimizer
Some (conditional) jump instructions can be the last one in the op_array, because they can jump to themselves. In those cases `i + 1` in the CFG builder can point to outside the op_array because `i` is already the last opline. To solve this we need to check against the end and prevent setting the successor out of bounds.
1 parent 983be08 commit f4770bc

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

Zend/Optimizer/zend_cfg.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,9 +370,14 @@ ZEND_API void zend_build_cfg(zend_arena **arena, const zend_op_array *op_array,
370370
case ZEND_JMPZ_EX:
371371
case ZEND_JMPNZ_EX:
372372
case ZEND_JMP_SET:
373+
case ZEND_JMP_NULL:
374+
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
375+
if (i + 1 < op_array->last) {
376+
BB_START(i + 1);
377+
}
378+
break;
373379
case ZEND_COALESCE:
374380
case ZEND_ASSERT_CHECK:
375-
case ZEND_JMP_NULL:
376381
case ZEND_BIND_INIT_STATIC_OR_JMP:
377382
BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes);
378383
BB_START(i + 1);
@@ -524,9 +529,17 @@ ZEND_API void zend_build_cfg(zend_arena **arena, const zend_op_array *op_array,
524529
case ZEND_JMPZ_EX:
525530
case ZEND_JMPNZ_EX:
526531
case ZEND_JMP_SET:
532+
case ZEND_JMP_NULL:
533+
block->successors_count = 2;
534+
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];
535+
if (j + 1 < blocks_count) {
536+
block->successors[1] = j + 1;
537+
} else {
538+
block->successors[1] = j; /* last instruction and its own target */
539+
}
540+
break;
527541
case ZEND_COALESCE:
528542
case ZEND_ASSERT_CHECK:
529-
case ZEND_JMP_NULL:
530543
case ZEND_BIND_INIT_STATIC_OR_JMP:
531544
block->successors_count = 2;
532545
block->successors[0] = block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes];

ext/opcache/tests/opt/gh20733.phpt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
GH-20733 (heap buffer overflow in optimizer)
3+
--INI--
4+
opcache.jit=tracing
5+
opcache.jit_buffer_size=16M
6+
--EXTENSIONS--
7+
opcache
8+
--FILE--
9+
<?php
10+
function test()
11+
{
12+
$arr1 = ['line-break-chars' => 'php://temp','line-length' => $undef];
13+
$arr2 = [];
14+
$and = $arr1 and $arr2;
15+
16+
while ($and) {
17+
}
18+
}
19+
echo "Done";
20+
?>
21+
--EXPECT--
22+
Done

0 commit comments

Comments
 (0)