Skip to content

Commit c69b942

Browse files
committed
Merge branch 'PHP-8.0' into PHP-8.1
* PHP-8.0: iSeparate tests JIT: Fix array clobbering by user error handler
2 parents 5d4bef0 + 206bcff commit c69b942

File tree

3 files changed

+232
-3
lines changed

3 files changed

+232
-3
lines changed

ext/opcache/jit/zend_jit_helpers.c

Lines changed: 196 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,8 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_r_helper(zend_array *ht, zval *dim,
377377
zend_ulong hval;
378378
zend_string *offset_key;
379379
zval *retval;
380+
zend_execute_data *execute_data;
381+
const zend_op *opline;
380382

381383
if (Z_TYPE_P(dim) == IS_REFERENCE) {
382384
dim = Z_REFVAL_P(dim);
@@ -390,16 +392,91 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_r_helper(zend_array *ht, zval *dim,
390392
offset_key = Z_STR_P(dim);
391393
goto str_index;
392394
case IS_UNDEF:
395+
/* The array may be destroyed while throwing the notice.
396+
* Temporarily increase the refcount to detect this situation. */
397+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
398+
GC_ADDREF(ht);
399+
}
400+
execute_data = EG(current_execute_data);
401+
opline = EX(opline);
393402
zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
403+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
404+
zend_array_destroy(ht);
405+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
406+
if (EG(exception)) {
407+
ZVAL_UNDEF(EX_VAR(opline->result.var));
408+
} else {
409+
ZVAL_NULL(EX_VAR(opline->result.var));
410+
}
411+
}
412+
return;
413+
}
414+
if (EG(exception)) {
415+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
416+
ZVAL_UNDEF(EX_VAR(opline->result.var));
417+
}
418+
return;
419+
}
394420
ZEND_FALLTHROUGH;
395421
case IS_NULL:
396422
offset_key = ZSTR_EMPTY_ALLOC();
397423
goto str_index;
398424
case IS_DOUBLE:
399-
hval = zend_dval_to_lval_safe(Z_DVAL_P(dim));
425+
hval = zend_dval_to_lval(Z_DVAL_P(dim));
426+
if (!zend_is_long_compatible(Z_DVAL_P(dim), hval)) {
427+
/* The array may be destroyed while throwing the notice.
428+
* Temporarily increase the refcount to detect this situation. */
429+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
430+
GC_ADDREF(ht);
431+
}
432+
execute_data = EG(current_execute_data);
433+
opline = EX(opline);
434+
zend_incompatible_double_to_long_error(Z_DVAL_P(dim));
435+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
436+
zend_array_destroy(ht);
437+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
438+
if (EG(exception)) {
439+
ZVAL_UNDEF(EX_VAR(opline->result.var));
440+
} else {
441+
ZVAL_NULL(EX_VAR(opline->result.var));
442+
}
443+
}
444+
return;
445+
}
446+
if (EG(exception)) {
447+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
448+
ZVAL_UNDEF(EX_VAR(opline->result.var));
449+
}
450+
return;
451+
}
452+
}
400453
goto num_index;
401454
case IS_RESOURCE:
455+
/* The array may be destroyed while throwing the notice.
456+
* Temporarily increase the refcount to detect this situation. */
457+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
458+
GC_ADDREF(ht);
459+
}
460+
execute_data = EG(current_execute_data);
461+
opline = EX(opline);
402462
zend_use_resource_as_offset(dim);
463+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
464+
zend_array_destroy(ht);
465+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
466+
if (EG(exception)) {
467+
ZVAL_UNDEF(EX_VAR(opline->result.var));
468+
} else {
469+
ZVAL_NULL(EX_VAR(opline->result.var));
470+
}
471+
}
472+
return;
473+
}
474+
if (EG(exception)) {
475+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
476+
ZVAL_UNDEF(EX_VAR(opline->result.var));
477+
}
478+
return;
479+
}
403480
hval = Z_RES_HANDLE_P(dim);
404481
goto num_index;
405482
case IS_FALSE:
@@ -442,6 +519,8 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_is_helper(zend_array *ht, zval *dim
442519
zend_ulong hval;
443520
zend_string *offset_key;
444521
zval *retval;
522+
zend_execute_data *execute_data;
523+
const zend_op *opline;
445524

446525
if (Z_TYPE_P(dim) == IS_REFERENCE) {
447526
dim = Z_REFVAL_P(dim);
@@ -455,16 +534,91 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_is_helper(zend_array *ht, zval *dim
455534
offset_key = Z_STR_P(dim);
456535
goto str_index;
457536
case IS_UNDEF:
537+
/* The array may be destroyed while throwing the notice.
538+
* Temporarily increase the refcount to detect this situation. */
539+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
540+
GC_ADDREF(ht);
541+
}
542+
execute_data = EG(current_execute_data);
543+
opline = EX(opline);
458544
zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
545+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
546+
zend_array_destroy(ht);
547+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
548+
if (EG(exception)) {
549+
ZVAL_UNDEF(EX_VAR(opline->result.var));
550+
} else {
551+
ZVAL_NULL(EX_VAR(opline->result.var));
552+
}
553+
}
554+
return;
555+
}
556+
if (EG(exception)) {
557+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
558+
ZVAL_UNDEF(EX_VAR(opline->result.var));
559+
}
560+
return;
561+
}
459562
ZEND_FALLTHROUGH;
460563
case IS_NULL:
461564
offset_key = ZSTR_EMPTY_ALLOC();
462565
goto str_index;
463566
case IS_DOUBLE:
464-
hval = zend_dval_to_lval_safe(Z_DVAL_P(dim));
567+
hval = zend_dval_to_lval(Z_DVAL_P(dim));
568+
if (!zend_is_long_compatible(Z_DVAL_P(dim), hval)) {
569+
/* The array may be destroyed while throwing the notice.
570+
* Temporarily increase the refcount to detect this situation. */
571+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
572+
GC_ADDREF(ht);
573+
}
574+
execute_data = EG(current_execute_data);
575+
opline = EX(opline);
576+
zend_incompatible_double_to_long_error(Z_DVAL_P(dim));
577+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
578+
zend_array_destroy(ht);
579+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
580+
if (EG(exception)) {
581+
ZVAL_UNDEF(EX_VAR(opline->result.var));
582+
} else {
583+
ZVAL_NULL(EX_VAR(opline->result.var));
584+
}
585+
}
586+
return;
587+
}
588+
if (EG(exception)) {
589+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
590+
ZVAL_UNDEF(EX_VAR(opline->result.var));
591+
}
592+
return;
593+
}
594+
}
465595
goto num_index;
466596
case IS_RESOURCE:
597+
/* The array may be destroyed while throwing the notice.
598+
* Temporarily increase the refcount to detect this situation. */
599+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
600+
GC_ADDREF(ht);
601+
}
602+
execute_data = EG(current_execute_data);
603+
opline = EX(opline);
467604
zend_use_resource_as_offset(dim);
605+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
606+
zend_array_destroy(ht);
607+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
608+
if (EG(exception)) {
609+
ZVAL_UNDEF(EX_VAR(opline->result.var));
610+
} else {
611+
ZVAL_NULL(EX_VAR(opline->result.var));
612+
}
613+
}
614+
return;
615+
}
616+
if (EG(exception)) {
617+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
618+
ZVAL_UNDEF(EX_VAR(opline->result.var));
619+
}
620+
return;
621+
}
468622
hval = Z_RES_HANDLE_P(dim);
469623
goto num_index;
470624
case IS_FALSE:
@@ -518,16 +672,55 @@ static int ZEND_FASTCALL zend_jit_fetch_dim_isset_helper(zend_array *ht, zval *d
518672
offset_key = Z_STR_P(dim);
519673
goto str_index;
520674
case IS_UNDEF:
675+
/* The array may be destroyed while throwing the notice.
676+
* Temporarily increase the refcount to detect this situation. */
677+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
678+
GC_ADDREF(ht);
679+
}
521680
zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
681+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
682+
zend_array_destroy(ht);
683+
return 0;
684+
}
685+
if (EG(exception)) {
686+
return 0;
687+
}
522688
ZEND_FALLTHROUGH;
523689
case IS_NULL:
524690
offset_key = ZSTR_EMPTY_ALLOC();
525691
goto str_index;
526692
case IS_DOUBLE:
527-
hval = zend_dval_to_lval_safe(Z_DVAL_P(dim));
693+
hval = zend_dval_to_lval(Z_DVAL_P(dim));
694+
if (!zend_is_long_compatible(Z_DVAL_P(dim), hval)) {
695+
/* The array may be destroyed while throwing the notice.
696+
* Temporarily increase the refcount to detect this situation. */
697+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
698+
GC_ADDREF(ht);
699+
}
700+
zend_incompatible_double_to_long_error(Z_DVAL_P(dim));
701+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
702+
zend_array_destroy(ht);
703+
return 0;
704+
}
705+
if (EG(exception)) {
706+
return 0;
707+
}
708+
}
528709
goto num_index;
529710
case IS_RESOURCE:
711+
/* The array may be destroyed while throwing the notice.
712+
* Temporarily increase the refcount to detect this situation. */
713+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
714+
GC_ADDREF(ht);
715+
}
530716
zend_use_resource_as_offset(dim);
717+
if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
718+
zend_array_destroy(ht);
719+
return 0;
720+
}
721+
if (EG(exception)) {
722+
return 0;
723+
}
531724
hval = Z_RES_HANDLE_P(dim);
532725
goto num_index;
533726
case IS_FALSE:
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
JIT FETCH_DIM_R: 010
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
opcache.jit_buffer_size=1M
8+
--FILE--
9+
<?php
10+
set_error_handler(function() {
11+
$GLOBALS['a'] = 0;
12+
});
13+
$a = [$y];
14+
($a[$b]);
15+
?>
16+
DONE
17+
--EXPECT--
18+
DONE
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
JIT FETCH_DIM_R: 011
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
opcache.jit_buffer_size=1M
8+
--FILE--
9+
<?php
10+
set_error_handler(function() {
11+
$GLOBALS['a'] = 0;
12+
});
13+
$a = [$y];
14+
($a[17604692317316877817]);
15+
?>
16+
DONE
17+
--EXPECT--
18+
DONE

0 commit comments

Comments
 (0)