Skip to content

Commit 0df31e5

Browse files
committed
Merge branch 'PHP-8.5'
* PHP-8.5: Update NEWS for null deprecation bug fix Fix GH-20194: null offset deprecation not emitted for writes (#20238)
2 parents b5747c3 + ebf9d84 commit 0df31e5

File tree

83 files changed

+982
-2110
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+982
-2110
lines changed

Zend/Optimizer/sccp.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,11 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
11061106

11071107
if (op2) {
11081108
SKIP_IF_TOP(op2);
1109+
if (Z_TYPE_P(op2) == IS_NULL) {
1110+
/* Emits deprecation at run-time. */
1111+
SET_RESULT_BOT(result);
1112+
return;
1113+
}
11091114
}
11101115

11111116
/* We want to avoid keeping around intermediate arrays for each SSA variable in the

Zend/Optimizer/zend_inference.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5253,7 +5253,7 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op
52535253
case ZEND_INIT_ARRAY:
52545254
return (opline->op2_type != IS_UNUSED) && (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
52555255
case ZEND_ADD_ARRAY_ELEMENT:
5256-
return (opline->op2_type == IS_UNUSED) || (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
5256+
return (opline->op2_type == IS_UNUSED) || (t2 & (MAY_BE_NULL|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
52575257
case ZEND_STRLEN:
52585258
return (t1 & MAY_BE_ANY) != MAY_BE_STRING;
52595259
case ZEND_COUNT:

Zend/tests/constexpr/constant_expressions_dynamic.phpt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ var_dump(
4848
Warning: A non-numeric value encountered in %s on line %d
4949

5050
Deprecated: Implicit conversion from float 3.14 to int loses precision in %s on line %d
51+
52+
Deprecated: Using null as an array offset is deprecated, use an empty string instead in %s on line %d
5153
int(3)
5254
string(4) "1foo"
5355
bool(false)

Zend/tests/offsets/gh20194.phpt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
GH-20194: Using null as an array offset does not emit deprecation when resolved at compile time
3+
--FILE--
4+
<?php
5+
6+
$a = [null => 1];
7+
8+
echo $a[null];
9+
10+
?>
11+
--EXPECTF--
12+
Deprecated: Using null as an array offset is deprecated, use an empty string instead in %s on line %d
13+
14+
Deprecated: Using null as an array offset is deprecated, use an empty string instead in %s on line %d
15+
1
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Do not leak when promoting null offset deprecation
3+
--FILE--
4+
<?php
5+
6+
set_error_handler(function ($errno, $errstr) {
7+
throw new Exception($errstr);
8+
});
9+
10+
try {
11+
$a = ['foo' => 'bar', null => new stdClass];
12+
} catch (Throwable $e) {
13+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
14+
}
15+
?>
16+
--EXPECT--
17+
Exception: Using null as an array offset is deprecated, use an empty string instead
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
No UAF on null offset deprecation with unset value
3+
--FILE--
4+
<?php
5+
set_error_handler(function ($errno, $errstr) {
6+
var_dump($errstr);
7+
global $a;
8+
unset($a);
9+
});
10+
11+
$a = new stdClass;
12+
$b = [0, null => $a];
13+
14+
echo "\nSuccess\n";
15+
?>
16+
--EXPECTF--
17+
string(72) "Using null as an array offset is deprecated, use an empty string instead"
18+
19+
Success

Zend/zend_API.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2233,9 +2233,6 @@ ZEND_API zend_result array_set_zval_key(HashTable *ht, zval *key, zval *value) /
22332233
case IS_STRING:
22342234
result = zend_symtable_update(ht, Z_STR_P(key), value);
22352235
break;
2236-
case IS_NULL:
2237-
result = zend_hash_update(ht, ZSTR_EMPTY_ALLOC(), value);
2238-
break;
22392236
case IS_RESOURCE:
22402237
zend_use_resource_as_offset(key);
22412238
result = zend_hash_index_update(ht, Z_RES_HANDLE_P(key), value);
@@ -2252,6 +2249,13 @@ ZEND_API zend_result array_set_zval_key(HashTable *ht, zval *key, zval *value) /
22522249
case IS_DOUBLE:
22532250
result = zend_hash_index_update(ht, zend_dval_to_lval_safe(Z_DVAL_P(key)), value);
22542251
break;
2252+
case IS_NULL:
2253+
zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
2254+
if (UNEXPECTED(EG(exception))) {
2255+
return FAILURE;
2256+
}
2257+
result = zend_hash_update(ht, ZSTR_EMPTY_ALLOC(), value);
2258+
break;
22552259
default:
22562260
zend_illegal_container_offset(ZSTR_KNOWN(ZEND_STR_ARRAY), key, BP_VAR_W);
22572261
result = NULL;

Zend/zend_compile.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10287,9 +10287,7 @@ static bool zend_try_ct_eval_array(zval *result, zend_ast *ast) /* {{{ */
1028710287
zend_long lval = zend_dval_to_lval_silent(Z_DVAL_P(key));
1028810288
/* Incompatible float will generate an error, leave this to run-time */
1028910289
if (!zend_is_long_compatible(Z_DVAL_P(key), lval)) {
10290-
zval_ptr_dtor_nogc(value);
10291-
zval_ptr_dtor(result);
10292-
return 0;
10290+
goto fail;
1029310291
}
1029410292
zend_hash_index_update(Z_ARRVAL_P(result), lval, value);
1029510293
break;
@@ -10301,13 +10299,14 @@ static bool zend_try_ct_eval_array(zval *result, zend_ast *ast) /* {{{ */
1030110299
zend_hash_index_update(Z_ARRVAL_P(result), 1, value);
1030210300
break;
1030310301
case IS_NULL:
10304-
zend_hash_update(Z_ARRVAL_P(result), ZSTR_EMPTY_ALLOC(), value);
10305-
break;
10302+
/* Null key will generate a warning at run-time. */
10303+
goto fail;
1030610304
default:
1030710305
zend_error_noreturn(E_COMPILE_ERROR, "Illegal offset type");
1030810306
break;
1030910307
}
1031010308
} else if (!zend_hash_next_index_insert(Z_ARRVAL_P(result), value)) {
10309+
fail:
1031110310
zval_ptr_dtor_nogc(value);
1031210311
zval_ptr_dtor(result);
1031310312
return 0;

Zend/zend_vm_def.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6278,7 +6278,21 @@ ZEND_VM_C_LABEL(num_index):
62786278
} else if ((OP2_TYPE & (IS_VAR|IS_CV)) && EXPECTED(Z_TYPE_P(offset) == IS_REFERENCE)) {
62796279
offset = Z_REFVAL_P(offset);
62806280
ZEND_VM_C_GOTO(add_again);
6281-
} else if (Z_TYPE_P(offset) == IS_NULL) {
6281+
} else if (UNEXPECTED(Z_TYPE_P(offset) == IS_NULL)) {
6282+
zval tmp;
6283+
if (OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) {
6284+
ZVAL_COPY(&tmp, expr_ptr);
6285+
}
6286+
zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
6287+
if (OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) {
6288+
/* A userland error handler can do funky things to the expression, so reset it */
6289+
zval_ptr_dtor(expr_ptr);
6290+
ZVAL_COPY_VALUE(expr_ptr, &tmp);
6291+
}
6292+
if (UNEXPECTED(EG(exception))) {
6293+
zval_ptr_dtor_nogc(expr_ptr);
6294+
HANDLE_EXCEPTION();
6295+
}
62826296
str = ZSTR_EMPTY_ALLOC();
62836297
ZEND_VM_C_GOTO(str_index);
62846298
} else if (Z_TYPE_P(offset) == IS_DOUBLE) {

0 commit comments

Comments
 (0)