From: Dmitry Stogov Date: Tue, 20 Dec 2016 13:53:06 +0000 (+0300) Subject: Merge branch 'PHP-7.0' into PHP-7.1 X-Git-Tag: php-7.1.1RC1~70 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=43cc3d7d9297328f6b63165a66d0a2d2e485023c;p=php Merge branch 'PHP-7.0' into PHP-7.1 * PHP-7.0: Fixed bug #73792 (invalid foreach loop hangs script) --- 43cc3d7d9297328f6b63165a66d0a2d2e485023c diff --cc NEWS index f94dd9aa9c,98b88cc3f7..374dd1c8ea --- a/NEWS +++ b/NEWS @@@ -1,17 -1,13 +1,18 @@@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? 2016 PHP 7.0.15 +?? ??? 2017, PHP 7.1.1 - Core: + . Fixed bug #73792 (invalid foreach loop hangs script). (Dmitry) + . Fixed bug #73686 (Adding settype()ed values to ArrayObject results in + references). (Nikita, Laruence) . Fixed bug #73663 ("Invalid opcode 65/16/8" occurs with a variable created with list()). (Laruence) - . Fixed bug #73585 (Logging of "Internal Zend error - Missing class - information" missing class name). (Laruence) + . Fixed bug #73727 (ZEND_MM_BITSET_LEN is "undefined symbol" in + zend_bitset.h). (Nikita) + +- CLI: + . Fixed bug #72555 (CLI output(japanese) on Windows). (Anatol) - COM: . Fixed bug #73679 (DOTNET read access violation using invalid codepage). diff --cc Zend/zend_execute.c index 647428f959,dc3db0f9fe..0b98cab44b --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@@ -1131,172 -1311,13 +1131,175 @@@ static zend_never_inline void zend_bina } } -static void zend_assign_to_string_offset(zval *str, zend_long offset, zval *value, zval *result) +static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type) +{ + zend_long offset; + +try_again: + if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) { + switch(Z_TYPE_P(dim)) { + case IS_STRING: + if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) { + break; + } + if (type != BP_VAR_UNSET) { + zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim)); + } + break; + case IS_UNDEF: + zval_undefined_cv(EG(current_execute_data)->opline->op2.var, EG(current_execute_data)); + case IS_DOUBLE: + case IS_NULL: + case IS_FALSE: + case IS_TRUE: + zend_error(E_NOTICE, "String offset cast occurred"); + break; + case IS_REFERENCE: + dim = Z_REFVAL_P(dim); + goto try_again; + default: + zend_error(E_WARNING, "Illegal offset type"); + break; + } + + offset = _zval_get_long_func(dim); + } else { + offset = Z_LVAL_P(dim); + } + + return offset; +} + +static zend_never_inline ZEND_COLD void zend_wrong_string_offset(void) +{ + const char *msg = NULL; + const zend_op *opline = EG(current_execute_data)->opline; + const zend_op *end; + uint32_t var; + + switch (opline->opcode) { + case ZEND_ASSIGN_ADD: + case ZEND_ASSIGN_SUB: + case ZEND_ASSIGN_MUL: + case ZEND_ASSIGN_DIV: + case ZEND_ASSIGN_MOD: + case ZEND_ASSIGN_SL: + case ZEND_ASSIGN_SR: + case ZEND_ASSIGN_CONCAT: + case ZEND_ASSIGN_BW_OR: + case ZEND_ASSIGN_BW_AND: + case ZEND_ASSIGN_BW_XOR: + case ZEND_ASSIGN_POW: + msg = "Cannot use assign-op operators with string offsets"; + break; + case ZEND_FETCH_DIM_W: + case ZEND_FETCH_DIM_RW: + case ZEND_FETCH_DIM_FUNC_ARG: + case ZEND_FETCH_DIM_UNSET: + /* TODO: Encode the "reason" into opline->extended_value??? */ + var = opline->result.var; + opline++; + end = EG(current_execute_data)->func->op_array.opcodes + + EG(current_execute_data)->func->op_array.last; + while (opline < end) { + if (opline->op1_type == IS_VAR && opline->op1.var == var) { + switch (opline->opcode) { + case ZEND_ASSIGN_ADD: + case ZEND_ASSIGN_SUB: + case ZEND_ASSIGN_MUL: + case ZEND_ASSIGN_DIV: + case ZEND_ASSIGN_MOD: + case ZEND_ASSIGN_SL: + case ZEND_ASSIGN_SR: + case ZEND_ASSIGN_CONCAT: + case ZEND_ASSIGN_BW_OR: + case ZEND_ASSIGN_BW_AND: + case ZEND_ASSIGN_BW_XOR: + case ZEND_ASSIGN_POW: + if (opline->extended_value == ZEND_ASSIGN_OBJ) { + msg = "Cannot use string offset as an object"; + } else if (opline->extended_value == ZEND_ASSIGN_DIM) { + msg = "Cannot use string offset as an array"; + } else { + msg = "Cannot use assign-op operators with string offsets"; + } + break; + case ZEND_PRE_INC_OBJ: + case ZEND_PRE_DEC_OBJ: + case ZEND_POST_INC_OBJ: + case ZEND_POST_DEC_OBJ: + case ZEND_PRE_INC: + case ZEND_PRE_DEC: + case ZEND_POST_INC: + case ZEND_POST_DEC: + msg = "Cannot increment/decrement string offsets"; + break; + case ZEND_FETCH_DIM_W: + case ZEND_FETCH_DIM_RW: + case ZEND_FETCH_DIM_FUNC_ARG: + case ZEND_FETCH_DIM_UNSET: + case ZEND_ASSIGN_DIM: + msg = "Cannot use string offset as an array"; + break; + case ZEND_FETCH_OBJ_W: + case ZEND_FETCH_OBJ_RW: + case ZEND_FETCH_OBJ_FUNC_ARG: + case ZEND_FETCH_OBJ_UNSET: + case ZEND_ASSIGN_OBJ: + msg = "Cannot use string offset as an object"; + break; + case ZEND_ASSIGN_REF: + case ZEND_ADD_ARRAY_ELEMENT: + case ZEND_INIT_ARRAY: + case ZEND_MAKE_REF: + msg = "Cannot create references to/from string offsets"; + break; + case ZEND_RETURN_BY_REF: + case ZEND_VERIFY_RETURN_TYPE: + msg = "Cannot return string offsets by reference"; + break; + case ZEND_UNSET_DIM: + case ZEND_UNSET_OBJ: + msg = "Cannot unset string offsets"; + break; + case ZEND_YIELD: + msg = "Cannot yield string offsets by reference"; + break; + case ZEND_SEND_REF: + case ZEND_SEND_VAR_EX: + msg = "Only variables can be passed by reference"; + break; ++ case ZEND_FE_RESET_RW: ++ msg = "Cannot iterate on string offsets by reference"; ++ break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + break; + } + if (opline->op2_type == IS_VAR && opline->op2.var == var) { + ZEND_ASSERT(opline->opcode == ZEND_ASSIGN_REF); + msg = "Cannot create references to/from string offsets"; + break; + } + } + break; + EMPTY_SWITCH_DEFAULT_CASE(); + } + ZEND_ASSERT(msg != NULL); + zend_throw_error(NULL, msg); +} + +static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, zval *value, zval *result) { zend_string *old_str; + zend_uchar c; + size_t string_len; + zend_long offset; - if (offset < 0) { + offset = zend_check_string_offset(dim, BP_VAR_W); + if (offset < (zend_long)(-Z_STRLEN_P(str))) { + /* Error on negative offset */ zend_error(E_WARNING, "Illegal string offset: " ZEND_LONG_FMT, offset); - zend_string_release(Z_STR_P(str)); if (result) { ZVAL_NULL(result); }