Skip to content

Commit 62ecf54

Browse files
committed
Fix use after free on compound division by zero
We can't destroy the result operand early, because the division might fail, in which case we need to preserve the original value. Place the division result in a temporary zval, and only copy it on success. Fixes oss-fuzz #35876.
1 parent 52a00fe commit 62ecf54

File tree

2 files changed

+22
-6
lines changed

2 files changed

+22
-6
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Division by zero in compound assignment with refcounted operand
3+
--FILE--
4+
<?php
5+
$h = "1";
6+
$h .= "2";
7+
try {
8+
$h /= 0;
9+
} catch (DivisionByZeroError $e) {
10+
echo $e->getMessage(), "\n";
11+
}
12+
var_dump($h);
13+
?>
14+
--EXPECT--
15+
Division by zero
16+
string(2) "12"

Zend/zend_operators.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,7 +1314,7 @@ ZEND_API zend_result ZEND_FASTCALL div_function(zval *result, zval *op1, zval *o
13141314

13151315
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV);
13161316

1317-
zval op1_copy, op2_copy;
1317+
zval result_copy, op1_copy, op2_copy;
13181318
if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
13191319
|| UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
13201320
zend_binop_error("/", op1, op2);
@@ -1324,12 +1324,12 @@ ZEND_API zend_result ZEND_FASTCALL div_function(zval *result, zval *op1, zval *o
13241324
return FAILURE;
13251325
}
13261326

1327-
if (result == op1) {
1328-
zval_ptr_dtor(result);
1329-
}
1330-
1331-
retval = div_function_base(result, &op1_copy, &op2_copy);
1327+
retval = div_function_base(&result_copy, &op1_copy, &op2_copy);
13321328
if (retval == SUCCESS) {
1329+
if (result == op1) {
1330+
zval_ptr_dtor(result);
1331+
}
1332+
ZVAL_COPY_VALUE(result, &result_copy);
13331333
return SUCCESS;
13341334
}
13351335

0 commit comments

Comments
 (0)