Skip to content

Commit 7c7b918

Browse files
committed
Fixed list() behavior inconsistency (string handling is disabled for all cases, ArrayAccess objects handling is enabled for all cases, ZEND_FETCH_DIM_TMP_VAR opcode is renamed into ZEND_FETCH_LIST, ZEND_FETCH_ADD_LOCK flag is removed).
1 parent 429e1b4 commit 7c7b918

14 files changed

+152
-114
lines changed

Zend/tests/bug39304.phpt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,5 @@ echo "I am alive";
88
?>
99
--EXPECTF--
1010
Notice: Uninitialized string offset: 0 in %sbug39304.php on line %d
11-
12-
Notice: Uninitialized string offset: 0 in %sbug39304.php on line %d
13-
14-
Notice: Uninitialized string offset: 1 in %sbug39304.php on line %d
1511
I am alive
1612

Zend/tests/bug39304_2_4.phpt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,5 @@ Bug #39304 (Segmentation fault with list unpacking of string offset)
1010
?>
1111
--EXPECTF--
1212
Notice: Uninitialized string offset: 0 in %sbug39304_2_4.php on line %d
13-
14-
Notice: Uninitialized string offset: 0 in %sbug39304_2_4.php on line %d
15-
16-
Notice: Uninitialized string offset: 1 in %sbug39304_2_4.php on line %d
17-
string(0) ""
18-
string(0) ""
13+
NULL
14+
NULL

Zend/tests/foreach_list_002.phpt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,5 @@ foreach($array as list(, $a)) {
1818
int(1)
1919
int(3)
2020
string(1) "b"
21-
22-
Notice: Uninitialized string offset: 1 in %sforeach_list_002.php on line %d
23-
string(0) ""
24-
25-
Notice: Uninitialized string offset: 1 in %sforeach_list_002.php on line %d
26-
string(0) ""
21+
NULL
22+
NULL

Zend/tests/list_005.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ var_dump($a, $b, $c);
3535

3636
?>
3737
--EXPECTF--
38-
string(1) "f"
39-
string(1) "o"
40-
string(1) "o"
38+
NULL
39+
NULL
40+
NULL
4141
----
4242
NULL
4343
NULL

Zend/tests/list_007.phpt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,5 @@ list($x, $y) = function() { };
88
var_dump($x, $y);
99

1010
?>
11-
--EXPECT--
12-
NULL
13-
NULL
11+
--EXPECTF--
12+
Fatal error: Cannot use object of type Closure as array in %slist_007.php on line 3

Zend/zend_compile.c

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -515,15 +515,17 @@ void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */
515515
}
516516
} else {
517517
while (opline>CG(active_op_array)->opcodes) {
518-
if (opline->opcode == ZEND_FETCH_DIM_R
519-
&& opline->op1_type == IS_VAR
520-
&& opline->op1.var == op1->u.op.var) {
521-
/* This should the end of a list() construct
522-
* Mark its result as unused
523-
*/
524-
opline->extended_value = ZEND_FETCH_STANDARD;
525-
break;
526-
} else if (opline->result_type==IS_VAR
518+
if (opline->opcode == ZEND_FETCH_LIST &&
519+
opline->op1_type == IS_VAR &&
520+
opline->op1.var == op1->u.op.var) {
521+
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
522+
523+
opline->opcode = ZEND_FREE;
524+
SET_NODE(opline->op1, op1);
525+
SET_UNUSED(opline->op2);
526+
return;
527+
}
528+
if (opline->result_type==IS_VAR
527529
&& opline->result.var == op1->u.op.var) {
528530
if (opline->opcode == ZEND_NEW) {
529531
opline->result_type |= EXT_TYPE_UNUSED;
@@ -2174,20 +2176,6 @@ void zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type TSRMLS
21742176
}
21752177
/* }}} */
21762178

2177-
static inline zend_uchar get_list_fetch_opcode(zend_uchar op_type) /* {{{ */
2178-
{
2179-
switch (op_type) {
2180-
case IS_VAR:
2181-
case IS_CV:
2182-
return ZEND_FETCH_DIM_R;
2183-
case IS_TMP_VAR:
2184-
case IS_CONST:
2185-
return ZEND_FETCH_DIM_TMP_VAR;
2186-
EMPTY_SWITCH_DEFAULT_CASE()
2187-
}
2188-
}
2189-
/* }}} */
2190-
21912179
static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node TSRMLS_DC) /* {{{ */
21922180
{
21932181
zend_ast_list *list = zend_ast_get_list(ast);
@@ -2214,8 +2202,7 @@ static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_n
22142202
}
22152203

22162204
opline = zend_emit_op(&fetch_result,
2217-
get_list_fetch_opcode(expr_node->op_type), expr_node, &dim_node TSRMLS_CC);
2218-
opline->extended_value |= ZEND_FETCH_ADD_LOCK;
2205+
ZEND_FETCH_LIST, expr_node, &dim_node TSRMLS_CC);
22192206

22202207
zend_emit_assign_znode(var_ast, &fetch_result TSRMLS_CC);
22212208
}

Zend/zend_compile.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,6 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC);
614614
#define ZEND_FETCH_TYPE_MASK 0x70000000
615615

616616
#define ZEND_FETCH_STANDARD 0x00000000
617-
#define ZEND_FETCH_ADD_LOCK 0x08000000
618617
#define ZEND_FETCH_MAKE_REF 0x04000000
619618

620619
#define ZEND_ISSET 0x02000000

Zend/zend_vm_def.h

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,9 +1209,7 @@ ZEND_VM_HANDLER(81, ZEND_FETCH_DIM_R, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV)
12091209
container = GET_OP1_ZVAL_PTR(BP_VAR_R);
12101210
zend_fetch_dimension_address_read_R(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), OP2_TYPE TSRMLS_CC);
12111211
FREE_OP2();
1212-
if (OP1_TYPE != IS_VAR || !(opline->extended_value & ZEND_FETCH_ADD_LOCK)) {
1213-
FREE_OP1();
1214-
}
1212+
FREE_OP1();
12151213
CHECK_EXCEPTION();
12161214
ZEND_VM_NEXT_OPCODE();
12171215
}
@@ -1506,23 +1504,34 @@ ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
15061504
ZEND_VM_NEXT_OPCODE();
15071505
}
15081506

1509-
ZEND_VM_HANDLER(98, ZEND_FETCH_DIM_TMP_VAR, CONST|TMP, CONST)
1507+
ZEND_VM_HANDLER(98, ZEND_FETCH_LIST, CONST|TMP|VAR|CV, CONST)
15101508
{
15111509
USE_OPLINE
15121510
zend_free_op free_op1;
15131511
zval *container;
15141512

15151513
SAVE_OPLINE();
1516-
container = GET_OP1_ZVAL_PTR(BP_VAR_R);
1514+
container = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
15171515

1518-
if (UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) {
1519-
ZVAL_NULL(EX_VAR(opline->result.var));
1520-
} else {
1516+
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
15211517
zend_free_op free_op2;
15221518
zval *value = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), OP2_TYPE, BP_VAR_R TSRMLS_CC);
15231519

15241520
ZVAL_COPY(EX_VAR(opline->result.var), value);
1525-
FREE_OP2();
1521+
} else if (UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) &&
1522+
EXPECTED(Z_OBJ_HT_P(container)->read_dimension)) {
1523+
zval *result = EX_VAR(opline->result.var);
1524+
zval *retval = Z_OBJ_HT_P(container)->read_dimension(container, GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), BP_VAR_R, result TSRMLS_CC);
1525+
1526+
if (retval) {
1527+
if (result != retval) {
1528+
ZVAL_COPY(result, retval);
1529+
}
1530+
} else {
1531+
ZVAL_NULL(result);
1532+
}
1533+
} else {
1534+
ZVAL_NULL(EX_VAR(opline->result.var));
15261535
}
15271536
CHECK_EXCEPTION();
15281537
ZEND_VM_NEXT_OPCODE();

0 commit comments

Comments
 (0)