Fixed bug #47704 (crashes on some "bad" operations with string offsets)

Removed unnecessary checks
This commit is contained in:
Dmitry Stogov 2009-03-18 12:53:17 +00:00
parent 15de25b228
commit ff5620524c
4 changed files with 622 additions and 939 deletions

9
Zend/tests/bug47704.phpt Normal file
View File

@ -0,0 +1,9 @@
--TEST--
Bug #47704 (crashes on some "bad" operations with string offsets)
--FILE--
<?php
$s = "abd";
$s[0]->a += 1;
?>
--EXPECTF--
Fatal error: Cannot use string offset as an object in %sbug47704.php on line %d

View File

@ -861,17 +861,8 @@ num_index:
default:
zend_error(E_WARNING, "Illegal offset type");
switch (type) {
case BP_VAR_R:
case BP_VAR_IS:
case BP_VAR_UNSET:
retval = &EG(uninitialized_zval_ptr);
break;
default:
retval = &EG(error_zval_ptr);
break;
}
break;
return (type == BP_VAR_W || type == BP_VAR_RW) ?
&EG(error_zval_ptr) : &EG(uninitialized_zval_ptr);
}
return retval;
}
@ -1048,12 +1039,7 @@ static void zend_fetch_dimension_address_read(temp_variable *result, zval **cont
break;
case IS_NULL:
if (container == EG(error_zval_ptr)) {
if (result) {
AI_SET_PTR(result->var, EG(error_zval_ptr));
PZVAL_LOCK(EG(error_zval_ptr));
}
} else if (result) {
if (result) {
AI_SET_PTR(result->var, EG(uninitialized_zval_ptr));
PZVAL_LOCK(EG(uninitialized_zval_ptr));
}
@ -1119,8 +1105,8 @@ static void zend_fetch_dimension_address_read(temp_variable *result, zval **cont
zval_ptr_dtor(&overloaded_result);
}
} else if (result) {
AI_SET_PTR(result->var, EG(error_zval_ptr));
PZVAL_LOCK(EG(error_zval_ptr));
AI_SET_PTR(result->var, EG(uninitialized_zval_ptr));
PZVAL_LOCK(EG(uninitialized_zval_ptr));
}
if (dim_is_tmp_var) {
zval_ptr_dtor(&dim);

View File

@ -303,6 +303,10 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR
znode *result = &opline->result;
int have_get_ptr = 0;
if (OP1_TYPE == IS_VAR && !object_ptr) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
}
EX_T(result->u.var).var.ptr_ptr = NULL;
make_real_object(object_ptr TSRMLS_CC);
object = *object_ptr;
@ -343,17 +347,14 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR
if (!have_get_ptr) {
zval *z = NULL;
switch (opline->extended_value) {
case ZEND_ASSIGN_OBJ:
if (Z_OBJ_HT_P(object)->read_property) {
z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R TSRMLS_CC);
}
break;
case ZEND_ASSIGN_DIM:
if (Z_OBJ_HT_P(object)->read_dimension) {
z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R TSRMLS_CC);
}
break;
if (opline->extended_value == ZEND_ASSIGN_OBJ) {
if (Z_OBJ_HT_P(object)->read_property) {
z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R TSRMLS_CC);
}
} else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ {
if (Z_OBJ_HT_P(object)->read_dimension) {
z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R TSRMLS_CC);
}
}
if (z) {
if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) {
@ -369,13 +370,10 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR
Z_ADDREF_P(z);
SEPARATE_ZVAL_IF_NOT_REF(&z);
binary_op(z, z, value TSRMLS_CC);
switch (opline->extended_value) {
case ZEND_ASSIGN_OBJ:
Z_OBJ_HT_P(object)->write_property(object, property, z TSRMLS_CC);
break;
case ZEND_ASSIGN_DIM:
Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC);
break;
if (opline->extended_value == ZEND_ASSIGN_OBJ) {
Z_OBJ_HT_P(object)->write_property(object, property, z TSRMLS_CC);
} else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ {
Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC);
}
if (!RETURN_VALUE_UNUSED(result)) {
EX_T(result->u.var).var.ptr = z;
@ -413,33 +411,29 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNU
zend_free_op free_op1, free_op2, free_op_data2, free_op_data1;
zval **var_ptr;
zval *value;
zend_bool increment_opline = 0;
switch (opline->extended_value) {
case ZEND_ASSIGN_OBJ:
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, binary_op);
break;
case ZEND_ASSIGN_DIM: {
zval **object_ptr = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W);
zval **container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW);
if (object_ptr && OP1_TYPE != IS_CV && !OP1_FREE) {
Z_ADDREF_PP(object_ptr); /* undo the effect of get_obj_zval_ptr_ptr() */
}
if (object_ptr && Z_TYPE_PP(object_ptr) == IS_OBJECT) {
if (OP1_TYPE == IS_VAR && !container) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
} else if (Z_TYPE_PP(container) == IS_OBJECT) {
if (OP1_TYPE == IS_VAR && !OP1_FREE) {
Z_ADDREF_PP(container); /* undo the effect of get_obj_zval_ptr_ptr() */
}
ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, binary_op);
} else {
zend_op *op_data = opline+1;
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
zval **container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW);
if (OP1_TYPE == IS_VAR && !container) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
}
zend_fetch_dimension_address(&EX_T(op_data->op2.u.var), container, dim, IS_OP2_TMP_FREE(), BP_VAR_RW TSRMLS_CC);
value = get_zval_ptr(&op_data->op1, EX(Ts), &free_op_data1, BP_VAR_R);
var_ptr = _get_zval_ptr_ptr_var(&op_data->op2, EX(Ts), &free_op_data2 TSRMLS_CC);
increment_opline = 1;
ZEND_VM_INC_OPCODE();
}
}
break;
@ -461,9 +455,6 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNU
}
FREE_OP2();
FREE_OP1_VAR_PTR();
if (increment_opline) {
ZEND_VM_INC_OPCODE();
}
ZEND_VM_NEXT_OPCODE();
}
@ -487,8 +478,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNU
}
FREE_OP2();
if (increment_opline) {
ZEND_VM_INC_OPCODE();
if (opline->extended_value == ZEND_ASSIGN_DIM) {
FREE_OP(free_op_data1);
FREE_OP_VAR_PTR(free_op_data2);
}
@ -561,6 +551,10 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR|
zval **retval = &EX_T(opline->result.u.var).var.ptr;
int have_get_ptr = 0;
if (OP1_TYPE == IS_VAR && !object_ptr) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
make_real_object(object_ptr TSRMLS_CC); /* this should modify object only if it's empty */
object = *object_ptr;
@ -654,6 +648,10 @@ ZEND_VM_HELPER_EX(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR
zval *retval = &EX_T(opline->result.u.var).tmp_var;
int have_get_ptr = 0;
if (OP1_TYPE == IS_VAR && !object_ptr) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
make_real_object(object_ptr TSRMLS_CC); /* this should modify object only if it's empty */
object = *object_ptr;
@ -745,7 +743,7 @@ ZEND_VM_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY)
if (OP1_TYPE == IS_VAR && !var_ptr) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
if (*var_ptr == EG(error_zval_ptr)) {
if (OP1_TYPE == IS_VAR && *var_ptr == EG(error_zval_ptr)) {
if (!RETURN_VALUE_UNUSED(&opline->result)) {
AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr));
PZVAL_LOCK(EG(uninitialized_zval_ptr));
@ -786,7 +784,7 @@ ZEND_VM_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY)
if (OP1_TYPE == IS_VAR && !var_ptr) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
if (*var_ptr == EG(error_zval_ptr)) {
if (OP1_TYPE == IS_VAR && *var_ptr == EG(error_zval_ptr)) {
if (!RETURN_VALUE_UNUSED(&opline->result)) {
AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr));
PZVAL_LOCK(EG(uninitialized_zval_ptr));
@ -827,7 +825,7 @@ ZEND_VM_HANDLER(36, ZEND_POST_INC, VAR|CV, ANY)
if (OP1_TYPE == IS_VAR && !var_ptr) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
if (*var_ptr == EG(error_zval_ptr)) {
if (OP1_TYPE == IS_VAR && *var_ptr == EG(error_zval_ptr)) {
if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).tmp_var = *EG(uninitialized_zval_ptr);
}
@ -865,7 +863,7 @@ ZEND_VM_HANDLER(37, ZEND_POST_DEC, VAR|CV, ANY)
if (OP1_TYPE == IS_VAR && !var_ptr) {
zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
}
if (*var_ptr == EG(error_zval_ptr)) {
if (OP1_TYPE == IS_VAR && *var_ptr == EG(error_zval_ptr)) {
if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).tmp_var = *EG(uninitialized_zval_ptr);
}
@ -1239,17 +1237,6 @@ ZEND_VM_HELPER_EX(zend_fetch_property_address_read_helper, VAR|UNUSED|CV, CONST|
zend_free_op free_op2;
zval *offset = GET_OP2_ZVAL_PTR(BP_VAR_R);
if (container == EG(error_zval_ptr)) {
if (!RETURN_VALUE_UNUSED(&opline->result)) {
AI_SET_PTR(EX_T(opline->result.u.var).var, EG(error_zval_ptr));
PZVAL_LOCK(EG(error_zval_ptr));
}
FREE_OP2();
FREE_OP1();
ZEND_VM_NEXT_OPCODE();
}
if (Z_TYPE_P(container) != IS_OBJECT || !Z_OBJ_HT_P(container)->read_property) {
if (type != BP_VAR_IS) {
zend_error(E_NOTICE, "Trying to get property of non-object");
@ -1510,16 +1497,12 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
zend_op *opline = EX(opline);
zend_op *op_data = opline+1;
zend_free_op free_op1;
zval **object_ptr;
zval **object_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
if (OP1_TYPE == IS_CV || EX_T(opline->op1.u.var).var.ptr_ptr) {
/* not an array offset */
object_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
} else {
object_ptr = NULL;
if (OP1_TYPE == IS_VAR && !object_ptr) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
}
if (object_ptr && Z_TYPE_PP(object_ptr) == IS_OBJECT) {
if (Z_TYPE_PP(object_ptr) == IS_OBJECT) {
zend_free_op free_op2;
zval *property_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
@ -1538,9 +1521,6 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R);
zval **variable_ptr_ptr;
if (OP1_TYPE == IS_VAR && !object_ptr) {
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array");
}
zend_fetch_dimension_address(&EX_T(op_data->op2.u.var), object_ptr, dim, IS_OP2_TMP_FREE(), BP_VAR_W TSRMLS_CC);
FREE_OP2();
@ -1581,7 +1561,7 @@ ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV)
zval *value = GET_OP2_ZVAL_PTR(BP_VAR_R);
zval **variable_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
if (!variable_ptr_ptr) {
if (OP1_TYPE == IS_VAR && !variable_ptr_ptr) {
if (zend_assign_to_string_offset(&EX_T(opline->op1.u.var), value, OP2_TYPE TSRMLS_CC)) {
if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr;
@ -2915,10 +2895,6 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMP|VAR|UNUSED|CV, ANY)
if (!obj || Z_TYPE_P(obj) != IS_OBJECT) {
zend_error_noreturn(E_ERROR, "__clone method called on non-object");
EX_T(opline->result.u.var).var.ptr = EG(error_zval_ptr);
Z_ADDREF_P(EX_T(opline->result.u.var).var.ptr);
FREE_OP1_IF_VAR();
ZEND_VM_NEXT_OPCODE();
}
ce = Z_OBJCE_P(obj);
@ -2930,8 +2906,6 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMP|VAR|UNUSED|CV, ANY)
} else {
zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object");
}
EX_T(opline->result.u.var).var.ptr = EG(error_zval_ptr);
Z_ADDREF_P(EX_T(opline->result.u.var).var.ptr);
}
if (ce && clone) {
@ -3394,7 +3368,7 @@ ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
zval *offset = GET_OP2_ZVAL_PTR(BP_VAR_R);
long index;
if (container) {
if (OP1_TYPE != IS_VAR || container) {
if (OP1_TYPE == IS_CV && container != &EG(uninitialized_zval_ptr)) {
SEPARATE_ZVAL_IF_NOT_REF(container);
}
@ -3487,7 +3461,7 @@ ZEND_VM_HANDLER(76, ZEND_UNSET_OBJ, VAR|UNUSED|CV, CONST|TMP|VAR|CV)
zval **container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET);
zval *offset = GET_OP2_ZVAL_PTR(BP_VAR_R);
if (container) {
if (OP1_TYPE != IS_VAR || container) {
if (OP1_TYPE == IS_CV && container != &EG(uninitialized_zval_ptr)) {
SEPARATE_ZVAL_IF_NOT_REF(container);
}
@ -3893,7 +3867,7 @@ ZEND_VM_HELPER_EX(zend_isset_isempty_dim_prop_obj_handler, VAR|UNUSED|CV, CONST|
int result = 0;
long index;
if (container) {
if (OP1_TYPE != IS_VAR || container) {
zend_free_op free_op2;
zval *offset = GET_OP2_ZVAL_PTR(BP_VAR_R);

File diff suppressed because it is too large Load Diff