diff options
Diffstat (limited to 'Zend/zend_vm_execute.h')
| -rw-r--r-- | Zend/zend_vm_execute.h | 2007 |
1 files changed, 1568 insertions, 439 deletions
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index c60cef5c88..4328aac4ce 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -108,11 +108,18 @@ static int ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zval *tmp = &EX_T(EX(opline)->result.u.var).tmp_var; - tmp->value.str.val = emalloc(1); - tmp->value.str.val[0] = 0; - tmp->value.str.len = 0; + if (EX(opline)->extended_value == IS_UNICODE) { + tmp->value.ustr.val = eumalloc(1); + tmp->value.ustr.val[0] = 0; + tmp->value.ustr.len = 0; + tmp->type = IS_UNICODE; + } else { + tmp->value.str.val = emalloc(1); + tmp->value.str.val[0] = 0; + tmp->value.str.len = 0; + tmp->type = EX(opline)->extended_value; + } tmp->refcount = 1; - tmp->type = IS_STRING; tmp->is_ref = 0; ZEND_VM_NEXT_OPCODE(); } @@ -127,7 +134,8 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) zend_bool should_change_scope; if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) { - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name); + /* FIXME: output identifiers properly */ + zend_error_noreturn(E_ERROR, "Cannot call abstract method %v::%v()", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name); ZEND_VM_NEXT_OPCODE(); /* Never reached */ } @@ -159,7 +167,8 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) severity = E_ERROR; severity_word = "cannot"; } - zend_error(severity, "Non-static method %s::%s() %s be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name, severity_word); + /* FIXME: output identifiers properly */ + zend_error(severity, "Non-static method %v::%v() %s be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name, severity_word); } } if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { @@ -207,7 +216,7 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) EX(function_state).function_symbol_table = *(EG(symtable_cache_ptr)--); } else { ALLOC_HASHTABLE(EX(function_state).function_symbol_table); - zend_hash_init(EX(function_state).function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_u_hash_init(EX(function_state).function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); /*printf("Cache miss! Initialized %x\n", function_state.function_symbol_table);*/ } calling_symbol_table = EG(active_symbol_table); @@ -327,8 +336,8 @@ static int ZEND_CATCH_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } - zend_hash_update(EG(active_symbol_table), opline->op2.u.constant.value.str.val, - opline->op2.u.constant.value.str.len+1, &EG(exception), sizeof(zval *), (void **) NULL); + zend_u_hash_update(EG(active_symbol_table), Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), + Z_UNILEN(opline->op2.u.constant)+1, &EG(exception), sizeof(zval *), (void **) NULL); EG(exception) = NULL; ZEND_VM_NEXT_OPCODE(); } @@ -346,9 +355,9 @@ static int ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL TSRMLS_CC); if(ptr && ptr->op_array) { - zend_error(E_WARNING, "Missing argument %ld for %s%s%s(), called in %s on line %d and defined", opline->op1.u.constant.value.lval, class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename, ptr->opline->lineno); + zend_error(E_WARNING, "Missing argument %ld for %v%s%v(), called in %s on line %d and defined", opline->op1.u.constant.value.lval, class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename, ptr->opline->lineno); } else { - zend_error(E_WARNING, "Missing argument %ld for %s%s%s()", opline->op1.u.constant.value.lval, class_name, space, get_active_function_name(TSRMLS_C)); + zend_error(E_WARNING, "Missing argument %ld for %v%s%v()", opline->op1.u.constant.value.lval, class_name, space, get_active_function_name(TSRMLS_C)); } if (opline->result.op_type == IS_VAR) { PZVAL_UNLOCK_FREE(*EX_T(opline->result.u.var).var.ptr_ptr); @@ -383,7 +392,7 @@ static int ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } else { class_type = "abstract class"; } - zend_error_noreturn(E_ERROR, "Cannot instantiate %s %s", class_type, EX_T(opline->op1.u.var).class_entry->name); + zend_error_noreturn(E_ERROR, "Cannot instantiate %s %v", class_type, EX_T(opline->op1.u.var).class_entry->name); } ALLOC_ZVAL(object_zval); object_init_ex(object_zval, EX_T(opline->op1.u.var).class_entry); @@ -432,7 +441,7 @@ static int ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) static int ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EG(scope)->name, EX(op_array)->function_name); + zend_error_noreturn(E_ERROR, "Cannot call abstract method %v::%v()", EG(scope)->name, EX(op_array)->function_name); ZEND_VM_NEXT_OPCODE(); /* Never reached */ } @@ -499,7 +508,7 @@ static int ZEND_ADD_INTERFACE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_class_entry *iface = EX_T(opline->op2.u.var).class_entry; if (!(iface->ce_flags & ZEND_ACC_INTERFACE)) { - zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ce->name, iface->name); + zend_error_noreturn(E_ERROR, "%v cannot implement %v - it is not an interface", ce->name, iface->name); } ce->interfaces[opline->extended_value] = iface; @@ -591,7 +600,8 @@ static int ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) EX_T(opline->result.u.var).class_entry = Z_OBJCE_P(class_name); break; case IS_STRING: - EX_T(opline->result.u.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC); + case IS_UNICODE: + EX_T(opline->result.u.var).class_entry = zend_u_fetch_class(Z_TYPE_P(class_name), Z_UNIVAL_P(class_name), Z_UNILEN_P(class_name), opline->extended_value TSRMLS_CC); break; default: zend_error_noreturn(E_ERROR, "Class name must be a valid object or a string"); @@ -612,21 +622,20 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A ce = EX_T(opline->op1.u.var).class_entry; if(IS_CONST != IS_UNUSED) { char *function_name_strval; - int function_name_strlen; + unsigned int function_name_strlen; zend_bool is_const = (IS_CONST == IS_CONST); if (is_const) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); } else { function_name = &opline->op2.u.constant; - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); } EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); @@ -660,29 +669,28 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_op *opline = EX(opline); zval *function_name; zend_function *function; - char *function_name_strval, *lcname; - int function_name_strlen; + void *function_name_strval, *lcname; + unsigned int function_name_strlen, lcname_len; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); if (IS_CONST == IS_CONST) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name = &opline->op2.u.constant; } else { function_name = &opline->op2.u.constant; - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; } + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); - if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE) { + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_STRVAL_P(function_name), function_name_strlen, 1, &lcname_len); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { efree(lcname); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); } efree(lcname); @@ -787,7 +795,8 @@ static int ZEND_FETCH_CLASS_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) EX_T(opline->result.u.var).class_entry = Z_OBJCE_P(class_name); break; case IS_STRING: - EX_T(opline->result.u.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC); + case IS_UNICODE: + EX_T(opline->result.u.var).class_entry = zend_u_fetch_class(Z_TYPE_P(class_name), Z_UNIVAL_P(class_name), Z_UNILEN_P(class_name), opline->extended_value TSRMLS_CC); break; default: zend_error_noreturn(E_ERROR, "Class name must be a valid object or a string"); @@ -809,21 +818,20 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG ce = EX_T(opline->op1.u.var).class_entry; if(IS_TMP_VAR != IS_UNUSED) { char *function_name_strval; - int function_name_strlen; + unsigned int function_name_strlen; zend_bool is_const = (IS_TMP_VAR == IS_CONST); zend_free_op free_op2; if (is_const) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); } else { function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); } EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); @@ -857,29 +865,28 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_op *opline = EX(opline); zval *function_name; zend_function *function; - char *function_name_strval, *lcname; - int function_name_strlen; + void *function_name_strval, *lcname; + unsigned int function_name_strlen, lcname_len; zend_free_op free_op2; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); if (IS_TMP_VAR == IS_CONST) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name = &opline->op2.u.constant; } else { function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; } + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); - if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE) { + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_STRVAL_P(function_name), function_name_strlen, 1, &lcname_len); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { efree(lcname); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); } efree(lcname); @@ -941,7 +948,8 @@ static int ZEND_FETCH_CLASS_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) EX_T(opline->result.u.var).class_entry = Z_OBJCE_P(class_name); break; case IS_STRING: - EX_T(opline->result.u.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC); + case IS_UNICODE: + EX_T(opline->result.u.var).class_entry = zend_u_fetch_class(Z_TYPE_P(class_name), Z_UNIVAL_P(class_name), Z_UNILEN_P(class_name), opline->extended_value TSRMLS_CC); break; default: zend_error_noreturn(E_ERROR, "Class name must be a valid object or a string"); @@ -963,21 +971,20 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG ce = EX_T(opline->op1.u.var).class_entry; if(IS_VAR != IS_UNUSED) { char *function_name_strval; - int function_name_strlen; + unsigned int function_name_strlen; zend_bool is_const = (IS_VAR == IS_CONST); zend_free_op free_op2; if (is_const) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); } else { function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); } EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); @@ -1011,29 +1018,28 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_op *opline = EX(opline); zval *function_name; zend_function *function; - char *function_name_strval, *lcname; - int function_name_strlen; + void *function_name_strval, *lcname; + unsigned int function_name_strlen, lcname_len; zend_free_op free_op2; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); if (IS_VAR == IS_CONST) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name = &opline->op2.u.constant; } else { function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; } + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); - if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE) { + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_STRVAL_P(function_name), function_name_strlen, 1, &lcname_len); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { efree(lcname); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); } efree(lcname); @@ -1095,7 +1101,8 @@ static int ZEND_FETCH_CLASS_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) EX_T(opline->result.u.var).class_entry = Z_OBJCE_P(class_name); break; case IS_STRING: - EX_T(opline->result.u.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC); + case IS_UNICODE: + EX_T(opline->result.u.var).class_entry = zend_u_fetch_class(Z_TYPE_P(class_name), Z_UNIVAL_P(class_name), Z_UNILEN_P(class_name), opline->extended_value TSRMLS_CC); break; default: zend_error_noreturn(E_ERROR, "Class name must be a valid object or a string"); @@ -1116,21 +1123,20 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ ce = EX_T(opline->op1.u.var).class_entry; if(IS_UNUSED != IS_UNUSED) { char *function_name_strval; - int function_name_strlen; + unsigned int function_name_strlen; zend_bool is_const = (IS_UNUSED == IS_CONST); if (is_const) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); } else { function_name = NULL; - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); } EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); @@ -1178,7 +1184,8 @@ static int ZEND_FETCH_CLASS_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) EX_T(opline->result.u.var).class_entry = Z_OBJCE_P(class_name); break; case IS_STRING: - EX_T(opline->result.u.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC); + case IS_UNICODE: + EX_T(opline->result.u.var).class_entry = zend_u_fetch_class(Z_TYPE_P(class_name), Z_UNIVAL_P(class_name), Z_UNILEN_P(class_name), opline->extended_value TSRMLS_CC); break; default: zend_error_noreturn(E_ERROR, "Class name must be a valid object or a string"); @@ -1199,21 +1206,20 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS ce = EX_T(opline->op1.u.var).class_entry; if(IS_CV != IS_UNUSED) { char *function_name_strval; - int function_name_strlen; + unsigned int function_name_strlen; zend_bool is_const = (IS_CV == IS_CONST); if (is_const) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name_strval = Z_UNIVAL(opline->op2.u.constant); + function_name_strlen = Z_UNILEN(opline->op2.u.constant); } else { function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; + function_name_strval = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_UNIVAL_P(function_name), Z_UNILEN_P(function_name), 1, &function_name_strlen); } EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); @@ -1247,29 +1253,28 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_op *opline = EX(opline); zval *function_name; zend_function *function; - char *function_name_strval, *lcname; - int function_name_strlen; + void *function_name_strval, *lcname; + unsigned int function_name_strlen, lcname_len; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); if (IS_CV == IS_CONST) { - function_name_strval = opline->op2.u.constant.value.str.val; - function_name_strlen = opline->op2.u.constant.value.str.len; + function_name = &opline->op2.u.constant; } else { function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; } + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); - if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE) { + lcname = zend_u_str_case_fold(Z_TYPE_P(function_name), Z_STRVAL_P(function_name), function_name_strlen, 1, &lcname_len); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(function_name), lcname, lcname_len+1, (void **) &function)==FAILURE) { efree(lcname); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined function %R()", Z_TYPE_P(function_name), function_name_strval); } efree(lcname); @@ -1342,11 +1347,27 @@ static int ZEND_ECHO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval *z = &opline->op1.u.constant; if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL && - zend_std_cast_object_tostring(z, &z_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) { + zend_std_cast_object_tostring(z, &z_copy, UG(unicode) ? IS_UNICODE : IS_STRING, 0 TSRMLS_CC) == SUCCESS) { zend_print_variable(&z_copy); zval_dtor(&z_copy); } else { - zend_print_variable(z); + UErrorCode status = U_ZERO_ERROR; + /* Convert inline HTML blocks to the output encoding, but only if necessary. */ + if (opline->extended_value && + strcmp(ucnv_getName(ZEND_U_CONVERTER(UG(output_encoding_conv)), &status), + ucnv_getName(ZEND_U_CONVERTER(UG(script_encoding_conv)), &status))) { + zval z_conv; + zend_convert_encodings(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_U_CONVERTER(UG(script_encoding_conv)), &z_conv.value.str.val, &z_conv.value.str.len, z->value.str.val, z->value.str.len, &status); + z_conv.type = IS_BINARY; + if (U_SUCCESS(status)) { + zend_print_variable(&z_conv); + } else { + zend_error(E_WARNING, "Could not convert inline HTML for output"); + } + zval_dtor(&z_conv); + } else { + zend_print_variable(z); + } } ZEND_VM_NEXT_OPCODE(); @@ -1387,23 +1408,23 @@ static int zend_fetch_var_address_helper_SPEC_CONST(int type, ZEND_OPCODE_HANDLE ZEND_VM_NEXT_OPCODE(); } */ - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &retval) == FAILURE) { switch (type) { case BP_VAR_R: case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_IS: retval = &EG(uninitialized_zval_ptr); break; case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_W: { zval *new_zval = &EG(uninitialized_zval); new_zval->refcount++; - zend_hash_update(target_symbol_table, varname->value.str.val, varname->value.str.len+1, &new_zval, sizeof(zval *), (void **) &retval); + zend_u_hash_update(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, &new_zval, sizeof(zval *), (void **) &retval); } break; EMPTY_SWITCH_DEFAULT_CASE() @@ -1411,6 +1432,10 @@ static int zend_fetch_var_address_helper_SPEC_CONST(int type, ZEND_OPCODE_HANDLE } switch (opline->op2.u.EA.type) { case ZEND_FETCH_GLOBAL: + if (IS_CONST != IS_TMP_VAR) { + + } + break; case ZEND_FETCH_LOCAL: break; @@ -1577,8 +1602,9 @@ static int ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); - if (zend_hash_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { - zend_error_noreturn(E_ERROR, "Unknown function: %s()\n", fname->value.str.val); + if (zend_u_hash_find(EG(function_table), Z_TYPE_P(fname), Z_UNIVAL_P(fname), Z_UNILEN_P(fname)+1, (void **) &EX(function_state).function)==FAILURE) { + /* FIXME: output identifiers properly */ + zend_error_noreturn(E_ERROR, "Unknown function: %R()\n", Z_TYPE_P(fname), Z_UNIVAL_P(fname)); } EX(object) = NULL; EX(calling_scope) = EX(function_state).function->common.scope; @@ -1638,9 +1664,9 @@ return_by_value: INIT_PZVAL_COPY(ret, retval_ptr); dup = zend_get_object_classname(retval_ptr, &class_name, &class_name_len TSRMLS_CC); if (Z_OBJ_HT_P(retval_ptr)->clone_obj == NULL) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", Z_OBJCE_P(retval_ptr)->name); } - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + zend_error(E_STRICT, "Implicit cloning object of class '%v' because of 'zend.ze1_compatibility_mode'", Z_OBJCE_P(retval_ptr)->name); ret->value.obj = Z_OBJ_HT_P(retval_ptr)->clone_obj(retval_ptr TSRMLS_CC); *EG(return_value_ptr_ptr) = ret; if (!dup) { @@ -1753,7 +1779,7 @@ static int ZEND_CLONE_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) clone = ce ? ce->clone : NULL; clone_call = Z_OBJ_HT_P(obj)->clone_obj; if (!clone_call) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", ce->name); EX_T(opline->result.u.var).var.ptr = EG(error_zval_ptr); EX_T(opline->result.u.var).var.ptr->refcount++; } @@ -1763,13 +1789,13 @@ static int ZEND_CLONE_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* Ensure that if we're calling a private function, we're allowed to do so. */ if (ce != EG(scope)) { - zend_error_noreturn(E_ERROR, "Call to private %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to private %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(clone->common.scope, EG(scope))) { - zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to protected %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } } @@ -1816,13 +1842,27 @@ static int ZEND_CAST_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval var_copy; int use_copy; - zend_make_printable_zval(result, &var_copy, &use_copy); + zend_make_string_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + break; + } + case IS_UNICODE: { + zval var_copy; + int use_copy; + + zend_make_unicode_zval(result, &var_copy, &use_copy); if (use_copy) { zval_dtor(result); *result = var_copy; } break; } + case IS_BINARY: + convert_to_binary(result); + break; case IS_ARRAY: convert_to_array(result); break; @@ -1845,7 +1885,14 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval tmp_inc_filename; zend_bool failure_retval=0; - if (inc_filename->type!=IS_STRING) { + if (UG(unicode) && opline->op2.u.constant.value.lval == ZEND_EVAL) { + if (inc_filename->type != IS_UNICODE) { + tmp_inc_filename = *inc_filename; + zval_copy_ctor(&tmp_inc_filename); + convert_to_unicode(&tmp_inc_filename); + inc_filename = &tmp_inc_filename; + } + } else if (inc_filename->type!=IS_STRING) { tmp_inc_filename = *inc_filename; zval_copy_ctor(&tmp_inc_filename); convert_to_string(&tmp_inc_filename); @@ -1962,10 +2009,10 @@ static int ZEND_UNSET_VAR_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) varname = &opline->op1.u.constant; - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -1973,17 +2020,17 @@ static int ZEND_UNSET_VAR_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_std_unset_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname) TSRMLS_CC); } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_del(target_symbol_table, varname->value.str.val, varname->value.str.len+1) == SUCCESS) { + if (zend_u_hash_del(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1) == SUCCESS) { zend_execute_data *ex = execute_data; - ulong hash_value = zend_inline_hash_func(varname->value.str.val, varname->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1); do { int i; for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == varname->value.str.len && - !memcmp(ex->op_array->vars[i].name, varname->value.str.val, varname->value.str.len)) { + ex->op_array->vars[i].name_len == Z_UNILEN_P(varname) && + !memcmp(ex->op_array->vars[i].name, Z_UNIVAL_P(varname), Z_TYPE_P(varname)==IS_UNICODE?UBYTES(Z_UNILEN_P(varname)):Z_UNILEN_P(varname))) { ex->CVs[i] = NULL; break; } @@ -2059,7 +2106,7 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } if (!EG(exception)) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name); + zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %v did not create an Iterator", ce->name); } zend_throw_exception_internal(NULL TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); @@ -2094,8 +2141,11 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *str_key; uint str_key_len; ulong int_key; - if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING - && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + zend_uchar key_type; + + key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); + if (key_type != HASH_KEY_NON_EXISTANT && + zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { break; } zend_hash_move_forward(fe_ht); @@ -2129,10 +2179,10 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_bool isset = 1; HashTable *target_symbol_table; - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -2143,7 +2193,7 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &value) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &value) == FAILURE) { isset = 0; } } @@ -2219,6 +2269,41 @@ static int ZEND_TICKS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_U_NORMALIZE_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + + zval *string = &opline->op1.u.constant; + zval *result = &EX_T(opline->result.u.var).tmp_var; + + *result = *string; + if (!0) { + zendi_zval_copy_ctor(*result); + } + + if (UG(unicode)) { + zval var_copy; + int use_copy; + UChar *norm; + int32_t norm_len; + + zend_make_unicode_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + if (!zend_normalize_identifier(&norm, &norm_len, + Z_USTRVAL_P(result), Z_USTRLEN_P(result), 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", Z_USTRVAL_P(result)); + } else if (norm != Z_USTRVAL_P(result)) { + efree(Z_USTRVAL_P(result)); + ZVAL_UNICODEL(result, norm, norm_len, 0); + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_ADD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -2502,10 +2587,12 @@ static int ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS } } */ - if (!zend_get_constant(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len, &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { - zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", - opline->op2.u.constant.value.str.val, - opline->op2.u.constant.value.str.val); + if (!zend_get_constant(Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { + zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'", + Z_TYPE(opline->op2.u.constant), + Z_UNIVAL(opline->op2.u.constant), + Z_TYPE(opline->op2.u.constant), + Z_UNIVAL(opline->op2.u.constant)); EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant; zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); } @@ -2514,12 +2601,12 @@ static int ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS ce = EX_T(opline->op1.u.var).class_entry; - if (zend_hash_find(&ce->constants_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, (void **) &value) == SUCCESS) { + if (zend_u_hash_find(&ce->constants_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) { zval_update_constant(value, (void *) 1 TSRMLS_CC); EX_T(opline->result.u.var).tmp_var = **value; zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); } else { - zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", opline->op2.u.constant.value.str.val); + zend_error_noreturn(E_ERROR, "Undefined class constant '%R'", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant)); } ZEND_VM_NEXT_OPCODE(); @@ -2578,7 +2665,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_A zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -2925,7 +3014,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -3272,7 +3363,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -3353,7 +3446,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -3699,7 +3794,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -3757,11 +3854,27 @@ static int ZEND_ECHO_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval *z = _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL && - zend_std_cast_object_tostring(z, &z_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) { + zend_std_cast_object_tostring(z, &z_copy, UG(unicode) ? IS_UNICODE : IS_STRING, 0 TSRMLS_CC) == SUCCESS) { zend_print_variable(&z_copy); zval_dtor(&z_copy); } else { - zend_print_variable(z); + UErrorCode status = U_ZERO_ERROR; + /* Convert inline HTML blocks to the output encoding, but only if necessary. */ + if (opline->extended_value && + strcmp(ucnv_getName(ZEND_U_CONVERTER(UG(output_encoding_conv)), &status), + ucnv_getName(ZEND_U_CONVERTER(UG(script_encoding_conv)), &status))) { + zval z_conv; + zend_convert_encodings(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_U_CONVERTER(UG(script_encoding_conv)), &z_conv.value.str.val, &z_conv.value.str.len, z->value.str.val, z->value.str.len, &status); + z_conv.type = IS_BINARY; + if (U_SUCCESS(status)) { + zend_print_variable(&z_conv); + } else { + zend_error(E_WARNING, "Could not convert inline HTML for output"); + } + zval_dtor(&z_conv); + } else { + zend_print_variable(z); + } } zval_dtor(free_op1.var); @@ -3803,23 +3916,23 @@ static int zend_fetch_var_address_helper_SPEC_TMP(int type, ZEND_OPCODE_HANDLER_ ZEND_VM_NEXT_OPCODE(); } */ - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &retval) == FAILURE) { switch (type) { case BP_VAR_R: case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_IS: retval = &EG(uninitialized_zval_ptr); break; case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_W: { zval *new_zval = &EG(uninitialized_zval); new_zval->refcount++; - zend_hash_update(target_symbol_table, varname->value.str.val, varname->value.str.len+1, &new_zval, sizeof(zval *), (void **) &retval); + zend_u_hash_update(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, &new_zval, sizeof(zval *), (void **) &retval); } break; EMPTY_SWITCH_DEFAULT_CASE() @@ -3827,6 +3940,10 @@ static int zend_fetch_var_address_helper_SPEC_TMP(int type, ZEND_OPCODE_HANDLER_ } switch (opline->op2.u.EA.type) { case ZEND_FETCH_GLOBAL: + if (IS_TMP_VAR != IS_TMP_VAR) { + zval_dtor(free_op1.var); + } + break; case ZEND_FETCH_LOCAL: zval_dtor(free_op1.var); break; @@ -4048,9 +4165,9 @@ return_by_value: INIT_PZVAL_COPY(ret, retval_ptr); dup = zend_get_object_classname(retval_ptr, &class_name, &class_name_len TSRMLS_CC); if (Z_OBJ_HT_P(retval_ptr)->clone_obj == NULL) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", Z_OBJCE_P(retval_ptr)->name); } - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + zend_error(E_STRICT, "Implicit cloning object of class '%v' because of 'zend.ze1_compatibility_mode'", Z_OBJCE_P(retval_ptr)->name); ret->value.obj = Z_OBJ_HT_P(retval_ptr)->clone_obj(retval_ptr TSRMLS_CC); *EG(return_value_ptr_ptr) = ret; if (!dup) { @@ -4170,7 +4287,7 @@ static int ZEND_CLONE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) clone = ce ? ce->clone : NULL; clone_call = Z_OBJ_HT_P(obj)->clone_obj; if (!clone_call) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", ce->name); EX_T(opline->result.u.var).var.ptr = EG(error_zval_ptr); EX_T(opline->result.u.var).var.ptr->refcount++; } @@ -4180,13 +4297,13 @@ static int ZEND_CLONE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* Ensure that if we're calling a private function, we're allowed to do so. */ if (ce != EG(scope)) { - zend_error_noreturn(E_ERROR, "Call to private %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to private %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(clone->common.scope, EG(scope))) { - zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to protected %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } } @@ -4233,13 +4350,27 @@ static int ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval var_copy; int use_copy; - zend_make_printable_zval(result, &var_copy, &use_copy); + zend_make_string_zval(result, &var_copy, &use_copy); if (use_copy) { zval_dtor(result); *result = var_copy; } break; } + case IS_UNICODE: { + zval var_copy; + int use_copy; + + zend_make_unicode_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + break; + } + case IS_BINARY: + convert_to_binary(result); + break; case IS_ARRAY: convert_to_array(result); break; @@ -4262,7 +4393,14 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval tmp_inc_filename; zend_bool failure_retval=0; - if (inc_filename->type!=IS_STRING) { + if (UG(unicode) && opline->op2.u.constant.value.lval == ZEND_EVAL) { + if (inc_filename->type != IS_UNICODE) { + tmp_inc_filename = *inc_filename; + zval_copy_ctor(&tmp_inc_filename); + convert_to_unicode(&tmp_inc_filename); + inc_filename = &tmp_inc_filename; + } + } else if (inc_filename->type!=IS_STRING) { tmp_inc_filename = *inc_filename; zval_copy_ctor(&tmp_inc_filename); convert_to_string(&tmp_inc_filename); @@ -4379,10 +4517,10 @@ static int ZEND_UNSET_VAR_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) varname = _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -4390,17 +4528,17 @@ static int ZEND_UNSET_VAR_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_std_unset_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname) TSRMLS_CC); } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_del(target_symbol_table, varname->value.str.val, varname->value.str.len+1) == SUCCESS) { + if (zend_u_hash_del(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1) == SUCCESS) { zend_execute_data *ex = execute_data; - ulong hash_value = zend_inline_hash_func(varname->value.str.val, varname->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1); do { int i; for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == varname->value.str.len && - !memcmp(ex->op_array->vars[i].name, varname->value.str.val, varname->value.str.len)) { + ex->op_array->vars[i].name_len == Z_UNILEN_P(varname) && + !memcmp(ex->op_array->vars[i].name, Z_UNIVAL_P(varname), Z_TYPE_P(varname)==IS_UNICODE?UBYTES(Z_UNILEN_P(varname)):Z_UNILEN_P(varname))) { ex->CVs[i] = NULL; break; } @@ -4476,7 +4614,7 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } if (!EG(exception)) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name); + zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %v did not create an Iterator", ce->name); } zend_throw_exception_internal(NULL TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); @@ -4511,8 +4649,11 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *str_key; uint str_key_len; ulong int_key; - if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING - && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + zend_uchar key_type; + + key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); + if (key_type != HASH_KEY_NON_EXISTANT && + zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { break; } zend_hash_move_forward(fe_ht); @@ -4546,10 +4687,10 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_bool isset = 1; HashTable *target_symbol_table; - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -4560,7 +4701,7 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &value) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &value) == FAILURE) { isset = 0; } } @@ -4656,6 +4797,41 @@ static int ZEND_INSTANCEOF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_U_NORMALIZE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zend_free_op free_op1; + zval *string = _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); + zval *result = &EX_T(opline->result.u.var).tmp_var; + + *result = *string; + if (!1) { + zendi_zval_copy_ctor(*result); + } + + if (UG(unicode)) { + zval var_copy; + int use_copy; + UChar *norm; + int32_t norm_len; + + zend_make_unicode_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + if (!zend_normalize_identifier(&norm, &norm_len, + Z_USTRVAL_P(result), Z_USTRLEN_P(result), 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", Z_USTRVAL_P(result)); + } else if (norm != Z_USTRVAL_P(result)) { + efree(Z_USTRVAL_P(result)); + ZVAL_UNICODEL(result, norm, norm_len, 0); + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_ADD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -4919,8 +5095,8 @@ static int ZEND_ADD_CHAR_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_free_op free_op1; add_char_to_string(&EX_T(opline->result.u.var).tmp_var, - _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), - &opline->op2.u.constant); + _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), + &opline->op2.u.constant); /* FREE_OP is missing intentionally here - we're always working on the same temporary variable */ ZEND_VM_NEXT_OPCODE(); } @@ -4931,8 +5107,8 @@ static int ZEND_ADD_STRING_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_free_op free_op1; add_string_to_string(&EX_T(opline->result.u.var).tmp_var, - _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), - &opline->op2.u.constant); + _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), + &opline->op2.u.constant); /* FREE_OP is missing intentionally here - we're always working on the same temporary variable */ ZEND_VM_NEXT_OPCODE(); } @@ -4944,17 +5120,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS char *function_name_strval; int function_name_strlen; zend_free_op free_op1; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = &opline->op2.u.constant; - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -4968,10 +5146,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -5082,7 +5260,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -5352,13 +5532,16 @@ static int ZEND_ADD_VAR_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval var_copy; int use_copy; - zend_make_printable_zval(var, &var_copy, &use_copy); + if (opline->extended_value == IS_UNICODE) { + zend_make_unicode_zval(var, &var_copy, &use_copy); + } else { + zend_make_printable_zval(var, &var_copy, &use_copy); + } if (use_copy) { var = &var_copy; } - add_string_to_string( &EX_T(opline->result.u.var).tmp_var, - _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), - var); + add_string_to_string(&EX_T(opline->result.u.var).tmp_var, + _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), var); if (use_copy) { zval_dtor(var); } @@ -5380,17 +5563,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -5404,10 +5589,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -5520,7 +5705,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -5790,13 +5977,16 @@ static int ZEND_ADD_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval var_copy; int use_copy; - zend_make_printable_zval(var, &var_copy, &use_copy); + if (opline->extended_value == IS_UNICODE) { + zend_make_unicode_zval(var, &var_copy, &use_copy); + } else { + zend_make_printable_zval(var, &var_copy, &use_copy); + } if (use_copy) { var = &var_copy; } - add_string_to_string( &EX_T(opline->result.u.var).tmp_var, - _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), - var); + add_string_to_string(&EX_T(opline->result.u.var).tmp_var, + _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), var); if (use_copy) { zval_dtor(var); } @@ -5818,17 +6008,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -5842,10 +6034,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -5958,7 +6150,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -6039,7 +6233,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_AR zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -6309,13 +6505,16 @@ static int ZEND_ADD_VAR_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval var_copy; int use_copy; - zend_make_printable_zval(var, &var_copy, &use_copy); + if (opline->extended_value == IS_UNICODE) { + zend_make_unicode_zval(var, &var_copy, &use_copy); + } else { + zend_make_printable_zval(var, &var_copy, &use_copy); + } if (use_copy) { var = &var_copy; } - add_string_to_string( &EX_T(opline->result.u.var).tmp_var, - _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), - var); + add_string_to_string(&EX_T(opline->result.u.var).tmp_var, + _get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC), var); if (use_copy) { zval_dtor(var); } @@ -6336,17 +6535,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op1; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -6360,10 +6561,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -6474,7 +6675,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -6694,11 +6897,27 @@ static int ZEND_ECHO_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval *z = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL && - zend_std_cast_object_tostring(z, &z_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) { + zend_std_cast_object_tostring(z, &z_copy, UG(unicode) ? IS_UNICODE : IS_STRING, 0 TSRMLS_CC) == SUCCESS) { zend_print_variable(&z_copy); zval_dtor(&z_copy); } else { - zend_print_variable(z); + UErrorCode status = U_ZERO_ERROR; + /* Convert inline HTML blocks to the output encoding, but only if necessary. */ + if (opline->extended_value && + strcmp(ucnv_getName(ZEND_U_CONVERTER(UG(output_encoding_conv)), &status), + ucnv_getName(ZEND_U_CONVERTER(UG(script_encoding_conv)), &status))) { + zval z_conv; + zend_convert_encodings(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_U_CONVERTER(UG(script_encoding_conv)), &z_conv.value.str.val, &z_conv.value.str.len, z->value.str.val, z->value.str.len, &status); + z_conv.type = IS_BINARY; + if (U_SUCCESS(status)) { + zend_print_variable(&z_conv); + } else { + zend_error(E_WARNING, "Could not convert inline HTML for output"); + } + zval_dtor(&z_conv); + } else { + zend_print_variable(z); + } } if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; @@ -6740,23 +6959,23 @@ static int zend_fetch_var_address_helper_SPEC_VAR(int type, ZEND_OPCODE_HANDLER_ ZEND_VM_NEXT_OPCODE(); } */ - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &retval) == FAILURE) { switch (type) { case BP_VAR_R: case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_IS: retval = &EG(uninitialized_zval_ptr); break; case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_W: { zval *new_zval = &EG(uninitialized_zval); new_zval->refcount++; - zend_hash_update(target_symbol_table, varname->value.str.val, varname->value.str.len+1, &new_zval, sizeof(zval *), (void **) &retval); + zend_u_hash_update(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, &new_zval, sizeof(zval *), (void **) &retval); } break; EMPTY_SWITCH_DEFAULT_CASE() @@ -6764,6 +6983,10 @@ static int zend_fetch_var_address_helper_SPEC_VAR(int type, ZEND_OPCODE_HANDLER_ } switch (opline->op2.u.EA.type) { case ZEND_FETCH_GLOBAL: + if (IS_VAR != IS_TMP_VAR) { + if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + } + break; case ZEND_FETCH_LOCAL: if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; break; @@ -6979,9 +7202,9 @@ return_by_value: INIT_PZVAL_COPY(ret, retval_ptr); dup = zend_get_object_classname(retval_ptr, &class_name, &class_name_len TSRMLS_CC); if (Z_OBJ_HT_P(retval_ptr)->clone_obj == NULL) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", Z_OBJCE_P(retval_ptr)->name); } - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + zend_error(E_STRICT, "Implicit cloning object of class '%v' because of 'zend.ze1_compatibility_mode'", Z_OBJCE_P(retval_ptr)->name); ret->value.obj = Z_OBJ_HT_P(retval_ptr)->clone_obj(retval_ptr TSRMLS_CC); *EG(return_value_ptr_ptr) = ret; if (!dup) { @@ -7190,7 +7413,7 @@ static int ZEND_CLONE_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) clone = ce ? ce->clone : NULL; clone_call = Z_OBJ_HT_P(obj)->clone_obj; if (!clone_call) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", ce->name); EX_T(opline->result.u.var).var.ptr = EG(error_zval_ptr); EX_T(opline->result.u.var).var.ptr->refcount++; } @@ -7200,13 +7423,13 @@ static int ZEND_CLONE_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* Ensure that if we're calling a private function, we're allowed to do so. */ if (ce != EG(scope)) { - zend_error_noreturn(E_ERROR, "Call to private %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to private %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(clone->common.scope, EG(scope))) { - zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to protected %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } } @@ -7253,13 +7476,27 @@ static int ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval var_copy; int use_copy; - zend_make_printable_zval(result, &var_copy, &use_copy); + zend_make_string_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + break; + } + case IS_UNICODE: { + zval var_copy; + int use_copy; + + zend_make_unicode_zval(result, &var_copy, &use_copy); if (use_copy) { zval_dtor(result); *result = var_copy; } break; } + case IS_BINARY: + convert_to_binary(result); + break; case IS_ARRAY: convert_to_array(result); break; @@ -7282,7 +7519,14 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval tmp_inc_filename; zend_bool failure_retval=0; - if (inc_filename->type!=IS_STRING) { + if (UG(unicode) && opline->op2.u.constant.value.lval == ZEND_EVAL) { + if (inc_filename->type != IS_UNICODE) { + tmp_inc_filename = *inc_filename; + zval_copy_ctor(&tmp_inc_filename); + convert_to_unicode(&tmp_inc_filename); + inc_filename = &tmp_inc_filename; + } + } else if (inc_filename->type!=IS_STRING) { tmp_inc_filename = *inc_filename; zval_copy_ctor(&tmp_inc_filename); convert_to_string(&tmp_inc_filename); @@ -7399,10 +7643,10 @@ static int ZEND_UNSET_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) varname = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -7410,17 +7654,17 @@ static int ZEND_UNSET_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_std_unset_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname) TSRMLS_CC); } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_del(target_symbol_table, varname->value.str.val, varname->value.str.len+1) == SUCCESS) { + if (zend_u_hash_del(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1) == SUCCESS) { zend_execute_data *ex = execute_data; - ulong hash_value = zend_inline_hash_func(varname->value.str.val, varname->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1); do { int i; for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == varname->value.str.len && - !memcmp(ex->op_array->vars[i].name, varname->value.str.val, varname->value.str.len)) { + ex->op_array->vars[i].name_len == Z_UNILEN_P(varname) && + !memcmp(ex->op_array->vars[i].name, Z_UNIVAL_P(varname), Z_TYPE_P(varname)==IS_UNICODE?UBYTES(Z_UNILEN_P(varname)):Z_UNILEN_P(varname))) { ex->CVs[i] = NULL; break; } @@ -7496,7 +7740,7 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; } if (!EG(exception)) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name); + zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %v did not create an Iterator", ce->name); } zend_throw_exception_internal(NULL TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); @@ -7531,8 +7775,11 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *str_key; uint str_key_len; ulong int_key; - if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING - && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + zend_uchar key_type; + + key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); + if (key_type != HASH_KEY_NON_EXISTANT && + zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { break; } zend_hash_move_forward(fe_ht); @@ -7594,11 +7841,16 @@ static int ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); zend_hash_move_forward(fe_ht); - } while (key_type != HASH_KEY_IS_STRING || zend_check_property_access(zobj, str_key TSRMLS_CC) != SUCCESS); + } while (key_type == HASH_KEY_NON_EXISTANT || zend_check_property_access(zobj, str_key TSRMLS_CC) != SUCCESS); if (use_key) { - zend_unmangle_property_name(str_key, &class_name, &prop_name); - str_key_len = strlen(prop_name); - str_key = estrndup(prop_name, str_key_len); + zend_u_unmangle_property_name(key_type == HASH_KEY_IS_UNICODE?IS_UNICODE:IS_STRING, str_key, &class_name, &prop_name); + if (key_type == HASH_KEY_IS_UNICODE) { + str_key_len = u_strlen((UChar*)prop_name); + str_key = (char*)eustrndup((UChar*)prop_name, str_key_len); + } else { + str_key_len = strlen(prop_name); + str_key = estrndup(prop_name, str_key_len); + } str_key_len++; } break; @@ -7688,6 +7940,16 @@ static int ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) key->value.str.len = str_key_len-1; key->type = IS_STRING; break; + case HASH_KEY_IS_BINARY: + key->value.str.val = str_key; + key->value.str.len = str_key_len-1; + key->type = IS_BINARY; + break; + case HASH_KEY_IS_UNICODE: + key->value.ustr.val = (UChar*)str_key; + key->value.ustr.len = str_key_len-1; + key->type = IS_UNICODE; + break; case HASH_KEY_IS_LONG: key->value.lval = int_key; key->type = IS_LONG; @@ -7709,10 +7971,10 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_bool isset = 1; HashTable *target_symbol_table; - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -7723,7 +7985,7 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &value) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &value) == FAILURE) { isset = 0; } } @@ -7804,6 +8066,41 @@ static int ZEND_INSTANCEOF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_U_NORMALIZE_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zend_free_op free_op1; + zval *string = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); + zval *result = &EX_T(opline->result.u.var).tmp_var; + + *result = *string; + if (!0) { + zendi_zval_copy_ctor(*result); + } + + if (UG(unicode)) { + zval var_copy; + int use_copy; + UChar *norm; + int32_t norm_len; + + zend_make_unicode_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + if (!zend_normalize_identifier(&norm, &norm_len, + Z_USTRVAL_P(result), Z_USTRLEN_P(result), 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", Z_USTRVAL_P(result)); + } else if (norm != Z_USTRVAL_P(result)) { + efree(Z_USTRVAL_P(result)); + ZVAL_UNICODEL(result, norm, norm_len, 0); + } + } + if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_ADD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -8799,17 +9096,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS char *function_name_strval; int function_name_strlen; zend_free_op free_op1; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = &opline->op2.u.constant; - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -8823,10 +9122,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -8938,7 +9237,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -8996,10 +9297,31 @@ static int ZEND_UNSET_DIM_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -9007,8 +9329,8 @@ static int ZEND_UNSET_DIM_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -9016,7 +9338,11 @@ static int ZEND_UNSET_DIM_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -9122,10 +9448,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_CONST(int prop_dim, } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -9168,7 +9518,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_CONST(int prop_dim, } else { } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -9180,12 +9532,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_CONST(int prop_dim, if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -10220,17 +10577,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -10244,10 +10603,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -10361,7 +10720,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -10419,10 +10780,31 @@ static int ZEND_UNSET_DIM_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -10430,8 +10812,8 @@ static int ZEND_UNSET_DIM_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -10439,7 +10821,11 @@ static int ZEND_UNSET_DIM_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -10545,10 +10931,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_TMP(int prop_dim, ZE } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -10591,7 +11001,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_TMP(int prop_dim, ZE } else { zval_dtor(free_op2.var); } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -10603,12 +11015,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_TMP(int prop_dim, ZE if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -11681,17 +12098,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -11705,10 +12124,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -11822,7 +12241,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -11880,10 +12301,31 @@ static int ZEND_UNSET_DIM_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -11891,8 +12333,8 @@ static int ZEND_UNSET_DIM_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -11900,7 +12342,11 @@ static int ZEND_UNSET_DIM_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -12006,10 +12452,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_VAR(int prop_dim, ZE } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -12052,7 +12522,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_VAR(int prop_dim, ZE } else { if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -12064,12 +12536,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_VAR(int prop_dim, ZE if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -12487,7 +12964,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_AR zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -13546,17 +14025,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op1; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -13570,10 +14051,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -13685,7 +14166,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -13743,10 +14226,31 @@ static int ZEND_UNSET_DIM_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -13754,8 +14258,8 @@ static int ZEND_UNSET_DIM_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -13763,7 +14267,11 @@ static int ZEND_UNSET_DIM_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -13869,10 +14377,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_CV(int prop_dim, ZEN } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -13915,7 +14447,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_CV(int prop_dim, ZEN } else { } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -13927,12 +14461,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_VAR_CV(int prop_dim, ZEN if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -13991,7 +14530,7 @@ static int ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) clone = ce ? ce->clone : NULL; clone_call = Z_OBJ_HT_P(obj)->clone_obj; if (!clone_call) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", ce->name); EX_T(opline->result.u.var).var.ptr = EG(error_zval_ptr); EX_T(opline->result.u.var).var.ptr->refcount++; } @@ -14001,13 +14540,13 @@ static int ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* Ensure that if we're calling a private function, we're allowed to do so. */ if (ce != EG(scope)) { - zend_error_noreturn(E_ERROR, "Call to private %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to private %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(clone->common.scope, EG(scope))) { - zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to protected %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } } @@ -14693,17 +15232,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_A char *function_name_strval; int function_name_strlen; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = &opline->op2.u.constant; - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -14717,10 +15258,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_A /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -14765,10 +15306,12 @@ static int ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG } } */ - if (!zend_get_constant(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len, &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { - zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", - opline->op2.u.constant.value.str.val, - opline->op2.u.constant.value.str.val); + if (!zend_get_constant(Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { + zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'", + Z_TYPE(opline->op2.u.constant), + Z_UNIVAL(opline->op2.u.constant), + Z_TYPE(opline->op2.u.constant), + Z_UNIVAL(opline->op2.u.constant)); EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant; zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); } @@ -14777,12 +15320,12 @@ static int ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG ce = EX_T(opline->op1.u.var).class_entry; - if (zend_hash_find(&ce->constants_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, (void **) &value) == SUCCESS) { + if (zend_u_hash_find(&ce->constants_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) { zval_update_constant(value, (void *) 1 TSRMLS_CC); EX_T(opline->result.u.var).tmp_var = **value; zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); } else { - zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", opline->op2.u.constant.value.str.val); + zend_error_noreturn(E_ERROR, "Undefined class constant '%R'", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant)); } ZEND_VM_NEXT_OPCODE(); @@ -14841,7 +15384,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -14899,10 +15444,31 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -14910,8 +15476,8 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -14919,7 +15485,11 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -15023,10 +15593,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_CONST(int prop_di } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -15069,7 +15663,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_CONST(int prop_di } else { } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -15081,12 +15677,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_CONST(int prop_di if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -15773,17 +16374,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG char *function_name_strval; int function_name_strlen; zend_free_op free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -15797,10 +16400,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -15881,7 +16484,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -15939,10 +16544,31 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -15950,8 +16576,8 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -15959,7 +16585,11 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -16063,10 +16693,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_TMP(int prop_dim, } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -16109,7 +16763,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_TMP(int prop_dim, } else { zval_dtor(free_op2.var); } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -16121,12 +16777,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_TMP(int prop_dim, if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -16813,17 +17474,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG char *function_name_strval; int function_name_strlen; zend_free_op free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -16837,10 +17500,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -16921,7 +17584,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -16979,10 +17644,31 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -16990,8 +17676,8 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -16999,7 +17685,11 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -17103,10 +17793,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_VAR(int prop_dim, } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -17149,7 +17863,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_VAR(int prop_dim, } else { if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -17161,12 +17877,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_VAR(int prop_dim, if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -17540,7 +18261,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -18217,17 +18940,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS char *function_name_strval; int function_name_strlen; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -18241,10 +18966,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -18324,7 +19049,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -18382,10 +19109,31 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -18393,8 +19141,8 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -18402,7 +19150,11 @@ static int ZEND_UNSET_DIM_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -18506,10 +19258,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_CV(int prop_dim, } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -18552,7 +19328,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_CV(int prop_dim, } else { } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -18564,12 +19342,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_UNUSED_CV(int prop_dim, if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -18793,11 +19576,27 @@ static int ZEND_ECHO_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval *z = _get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC); if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL && - zend_std_cast_object_tostring(z, &z_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) { + zend_std_cast_object_tostring(z, &z_copy, UG(unicode) ? IS_UNICODE : IS_STRING, 0 TSRMLS_CC) == SUCCESS) { zend_print_variable(&z_copy); zval_dtor(&z_copy); } else { - zend_print_variable(z); + UErrorCode status = U_ZERO_ERROR; + /* Convert inline HTML blocks to the output encoding, but only if necessary. */ + if (opline->extended_value && + strcmp(ucnv_getName(ZEND_U_CONVERTER(UG(output_encoding_conv)), &status), + ucnv_getName(ZEND_U_CONVERTER(UG(script_encoding_conv)), &status))) { + zval z_conv; + zend_convert_encodings(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_U_CONVERTER(UG(script_encoding_conv)), &z_conv.value.str.val, &z_conv.value.str.len, z->value.str.val, z->value.str.len, &status); + z_conv.type = IS_BINARY; + if (U_SUCCESS(status)) { + zend_print_variable(&z_conv); + } else { + zend_error(E_WARNING, "Could not convert inline HTML for output"); + } + zval_dtor(&z_conv); + } else { + zend_print_variable(z); + } } ZEND_VM_NEXT_OPCODE(); @@ -18838,23 +19637,23 @@ static int zend_fetch_var_address_helper_SPEC_CV(int type, ZEND_OPCODE_HANDLER_A ZEND_VM_NEXT_OPCODE(); } */ - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &retval) == FAILURE) { switch (type) { case BP_VAR_R: case BP_VAR_UNSET: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_IS: retval = &EG(uninitialized_zval_ptr); break; case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined variable: %s", varname->value.str.val); + zend_error(E_NOTICE,"Undefined variable: %R", Z_TYPE_P(varname), Z_UNIVAL_P(varname)); /* break missing intentionally */ case BP_VAR_W: { zval *new_zval = &EG(uninitialized_zval); new_zval->refcount++; - zend_hash_update(target_symbol_table, varname->value.str.val, varname->value.str.len+1, &new_zval, sizeof(zval *), (void **) &retval); + zend_u_hash_update(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, &new_zval, sizeof(zval *), (void **) &retval); } break; EMPTY_SWITCH_DEFAULT_CASE() @@ -18862,6 +19661,10 @@ static int zend_fetch_var_address_helper_SPEC_CV(int type, ZEND_OPCODE_HANDLER_A } switch (opline->op2.u.EA.type) { case ZEND_FETCH_GLOBAL: + if (IS_CV != IS_TMP_VAR) { + + } + break; case ZEND_FETCH_LOCAL: break; @@ -19072,9 +19875,9 @@ return_by_value: INIT_PZVAL_COPY(ret, retval_ptr); dup = zend_get_object_classname(retval_ptr, &class_name, &class_name_len TSRMLS_CC); if (Z_OBJ_HT_P(retval_ptr)->clone_obj == NULL) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", Z_OBJCE_P(retval_ptr)->name); } - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + zend_error(E_STRICT, "Implicit cloning object of class '%v' because of 'zend.ze1_compatibility_mode'", Z_OBJCE_P(retval_ptr)->name); ret->value.obj = Z_OBJ_HT_P(retval_ptr)->clone_obj(retval_ptr TSRMLS_CC); *EG(return_value_ptr_ptr) = ret; if (!dup) { @@ -19275,7 +20078,7 @@ static int ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) clone = ce ? ce->clone : NULL; clone_call = Z_OBJ_HT_P(obj)->clone_obj; if (!clone_call) { - zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name); + zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %v", ce->name); EX_T(opline->result.u.var).var.ptr = EG(error_zval_ptr); EX_T(opline->result.u.var).var.ptr->refcount++; } @@ -19285,13 +20088,13 @@ static int ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* Ensure that if we're calling a private function, we're allowed to do so. */ if (ce != EG(scope)) { - zend_error_noreturn(E_ERROR, "Call to private %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to private %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(clone->common.scope, EG(scope))) { - zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); + zend_error_noreturn(E_ERROR, "Call to protected %v::__clone() from context '%v'", ce->name, EG(scope) ? EG(scope)->name : EMPTY_STR); } } } @@ -19338,13 +20141,27 @@ static int ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval var_copy; int use_copy; - zend_make_printable_zval(result, &var_copy, &use_copy); + zend_make_string_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + break; + } + case IS_UNICODE: { + zval var_copy; + int use_copy; + + zend_make_unicode_zval(result, &var_copy, &use_copy); if (use_copy) { zval_dtor(result); *result = var_copy; } break; } + case IS_BINARY: + convert_to_binary(result); + break; case IS_ARRAY: convert_to_array(result); break; @@ -19367,7 +20184,14 @@ static int ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval tmp_inc_filename; zend_bool failure_retval=0; - if (inc_filename->type!=IS_STRING) { + if (UG(unicode) && opline->op2.u.constant.value.lval == ZEND_EVAL) { + if (inc_filename->type != IS_UNICODE) { + tmp_inc_filename = *inc_filename; + zval_copy_ctor(&tmp_inc_filename); + convert_to_unicode(&tmp_inc_filename); + inc_filename = &tmp_inc_filename; + } + } else if (inc_filename->type!=IS_STRING) { tmp_inc_filename = *inc_filename; zval_copy_ctor(&tmp_inc_filename); convert_to_string(&tmp_inc_filename); @@ -19484,10 +20308,10 @@ static int ZEND_UNSET_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) varname = _get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC); - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -19495,17 +20319,17 @@ static int ZEND_UNSET_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_std_unset_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname) TSRMLS_CC); } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_del(target_symbol_table, varname->value.str.val, varname->value.str.len+1) == SUCCESS) { + if (zend_u_hash_del(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1) == SUCCESS) { zend_execute_data *ex = execute_data; - ulong hash_value = zend_inline_hash_func(varname->value.str.val, varname->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1); do { int i; for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == varname->value.str.len && - !memcmp(ex->op_array->vars[i].name, varname->value.str.val, varname->value.str.len)) { + ex->op_array->vars[i].name_len == Z_UNILEN_P(varname) && + !memcmp(ex->op_array->vars[i].name, Z_UNIVAL_P(varname), Z_TYPE_P(varname)==IS_UNICODE?UBYTES(Z_UNILEN_P(varname)):Z_UNILEN_P(varname))) { ex->CVs[i] = NULL; break; } @@ -19581,7 +20405,7 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } if (!EG(exception)) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name); + zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %v did not create an Iterator", ce->name); } zend_throw_exception_internal(NULL TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); @@ -19616,8 +20440,11 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *str_key; uint str_key_len; ulong int_key; - if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING - && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + zend_uchar key_type; + + key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); + if (key_type != HASH_KEY_NON_EXISTANT && + zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { break; } zend_hash_move_forward(fe_ht); @@ -19651,10 +20478,10 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_bool isset = 1; HashTable *target_symbol_table; - if (varname->type != IS_STRING) { + if (varname->type != IS_STRING && varname->type != IS_UNICODE) { tmp = *varname; zval_copy_ctor(&tmp); - convert_to_string(&tmp); + convert_to_text(&tmp); varname = &tmp; } @@ -19665,7 +20492,7 @@ static int ZEND_ISSET_ISEMPTY_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } else { target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &value) == FAILURE) { + if (zend_u_hash_find(target_symbol_table, Z_TYPE_P(varname), Z_UNIVAL_P(varname), Z_UNILEN_P(varname)+1, (void **) &value) == FAILURE) { isset = 0; } } @@ -19745,6 +20572,41 @@ static int ZEND_INSTANCEOF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_U_NORMALIZE_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + + zval *string = _get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC); + zval *result = &EX_T(opline->result.u.var).tmp_var; + + *result = *string; + if (!0) { + zendi_zval_copy_ctor(*result); + } + + if (UG(unicode)) { + zval var_copy; + int use_copy; + UChar *norm; + int32_t norm_len; + + zend_make_unicode_zval(result, &var_copy, &use_copy); + if (use_copy) { + zval_dtor(result); + *result = var_copy; + } + if (!zend_normalize_identifier(&norm, &norm_len, + Z_USTRVAL_P(result), Z_USTRLEN_P(result), 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", Z_USTRVAL_P(result)); + } else if (norm != Z_USTRVAL_P(result)) { + efree(Z_USTRVAL_P(result)); + ZVAL_UNICODEL(result, norm, norm_len, 0); + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_ADD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -20737,17 +21599,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = &opline->op2.u.constant; - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -20761,10 +21625,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -20875,7 +21739,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -20933,10 +21799,31 @@ static int ZEND_UNSET_DIM_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -20944,8 +21831,8 @@ static int ZEND_UNSET_DIM_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -20953,7 +21840,11 @@ static int ZEND_UNSET_DIM_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -21057,10 +21948,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_CONST(int prop_dim, Z } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -21103,7 +22018,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_CONST(int prop_dim, Z } else { } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -21115,12 +22032,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_CONST(int prop_dim, Z if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -22150,17 +23072,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -22174,10 +23098,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -22290,7 +23214,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -22348,10 +23274,31 @@ static int ZEND_UNSET_DIM_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -22359,8 +23306,8 @@ static int ZEND_UNSET_DIM_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -22368,7 +23315,11 @@ static int ZEND_UNSET_DIM_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -22472,10 +23423,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_TMP(int prop_dim, ZEN } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -22518,7 +23493,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_TMP(int prop_dim, ZEN } else { zval_dtor(free_op2.var); } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -22530,12 +23507,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_TMP(int prop_dim, ZEN if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -23602,17 +24584,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; zend_free_op free_op2; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -23626,10 +24610,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -23742,7 +24726,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -23800,10 +24786,31 @@ static int ZEND_UNSET_DIM_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -23811,8 +24818,8 @@ static int ZEND_UNSET_DIM_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -23820,7 +24827,11 @@ static int ZEND_UNSET_DIM_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -23924,10 +24935,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_VAR(int prop_dim, ZEN } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -23970,7 +25005,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_VAR(int prop_dim, ZEN } else { if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -23982,12 +25019,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_VAR(int prop_dim, ZEN if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -24402,7 +25444,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -25457,17 +26501,19 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) char *function_name_strval; int function_name_strlen; + /* FIXME: type is default */ + zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(calling_scope)); function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (Z_TYPE_P(function_name) != IS_STRING && Z_TYPE_P(function_name) != IS_UNICODE) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } - function_name_strval = function_name->value.str.val; - function_name_strlen = function_name->value.str.len; + function_name_strval = Z_UNIVAL_P(function_name); + function_name_strlen = Z_UNILEN_P(function_name); EX(calling_scope) = EG(scope); @@ -25481,10 +26527,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { - zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); + zend_error_noreturn(E_ERROR, "Call to undefined method %R::%R()", type, Z_OBJ_CLASS_NAME_P(EX(object)), Z_TYPE_P(function_name), function_name_strval); } } else { - zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { @@ -25595,7 +26641,9 @@ static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_update(array_ptr->value.ht, offset->value.lval, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(array_ptr->value.ht, offset->value.str.val, offset->value.str.len+1, &expr_ptr, sizeof(zval *), NULL); + case IS_BINARY: + case IS_UNICODE: + zend_u_symtable_update(array_ptr->value.ht, Z_TYPE_P(offset), Z_UNIVAL_P(offset), Z_UNILEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: zend_hash_update(array_ptr->value.ht, "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); @@ -25653,10 +26701,31 @@ static int ZEND_UNSET_DIM_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_hash_index_del(ht, index); break; case IS_STRING: - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { + case IS_BINARY: + case IS_UNICODE: { + void *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && offset->type == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + + if (zend_u_symtable_del(ht, Z_TYPE_P(offset), offset_key, offset_len+1) == SUCCESS && + ht == &EG(symbol_table)) { zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); + ulong hash_value = zend_u_inline_hash_func(Z_TYPE_P(offset), offset_key, offset_len+1); for (ex = execute_data; ex; ex = ex->prev_execute_data) { if (ex->symbol_table == ht) { @@ -25664,8 +26733,8 @@ static int ZEND_UNSET_DIM_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) for (i = 0; i < ex->op_array->last_var; i++) { if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { + ex->op_array->vars[i].name_len == offset_len && + !memcmp(ex->op_array->vars[i].name, offset_key, Z_TYPE_P(offset)==IS_UNICODE?UBYTES(offset_len):offset_len)) { ex->CVs[i] = NULL; break; } @@ -25673,7 +26742,11 @@ static int ZEND_UNSET_DIM_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: zend_hash_del(ht, "", sizeof("")); break; @@ -25777,10 +26850,34 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_CV(int prop_dim, ZEND } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + case IS_BINARY: + case IS_UNICODE: { + char *offset_key = Z_UNIVAL_P(offset); + int offset_len = Z_UNILEN_P(offset); + int free_offset = 0; + + if (UG(unicode) && ht == &EG(symbol_table) && Z_TYPE_P(offset) == IS_UNICODE) { + /* Identifier normalization */ + UChar *norm; + int32_t norm_len; + + if (!zend_normalize_identifier(&norm, &norm_len, + (UChar*)offset_key, offset_len, 0)) { + zend_error(E_WARNING, "Could not normalize identifier: %r", offset_key); + } else if ((char*)norm != offset_key) { + offset_key = (char*)norm; + offset_len = norm_len; + free_offset = 1; + } + } + if (zend_u_symtable_find(ht, Z_TYPE_P(offset), offset_key, offset_len+1, (void **) &value) == SUCCESS) { isset = 1; } + if (free_offset) { + efree(offset_key); + } break; + } case IS_NULL: if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) { isset = 1; @@ -25823,7 +26920,9 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_CV(int prop_dim, ZEND } else { } - } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ + } else if (((*container)->type == IS_STRING || + (*container)->type == IS_BINARY || + (*container)->type == IS_UNICODE) && !prop_dim) { /* string offsets */ zval tmp; if (offset->type != IS_LONG) { @@ -25835,12 +26934,17 @@ static int zend_isset_isempty_dim_prop_obj_handler_SPEC_CV_CV(int prop_dim, ZEND if (offset->type == IS_LONG) { switch (opline->extended_value) { case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container)) { result = 1; } break; case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + if (offset->value.lval >= 0 && + offset->value.lval < Z_UNILEN_PP(container) && + ((Z_TYPE_PP(container) == IS_UNICODE)? + (Z_USTRVAL_PP(container)[offset->value.lval] != 0): + (Z_STRVAL_PP(container)[offset->value.lval] != '0'))) { result = 1; } break; @@ -29661,6 +30765,31 @@ void zend_init_opcodes_handlers() ZEND_USER_OPCODE_SPEC_HANDLER, ZEND_USER_OPCODE_SPEC_HANDLER, ZEND_USER_OPCODE_SPEC_HANDLER, + ZEND_U_NORMALIZE_SPEC_CONST_HANDLER, + ZEND_U_NORMALIZE_SPEC_CONST_HANDLER, + ZEND_U_NORMALIZE_SPEC_CONST_HANDLER, + ZEND_U_NORMALIZE_SPEC_CONST_HANDLER, + ZEND_U_NORMALIZE_SPEC_CONST_HANDLER, + ZEND_U_NORMALIZE_SPEC_TMP_HANDLER, + ZEND_U_NORMALIZE_SPEC_TMP_HANDLER, + ZEND_U_NORMALIZE_SPEC_TMP_HANDLER, + ZEND_U_NORMALIZE_SPEC_TMP_HANDLER, + ZEND_U_NORMALIZE_SPEC_TMP_HANDLER, + ZEND_U_NORMALIZE_SPEC_VAR_HANDLER, + ZEND_U_NORMALIZE_SPEC_VAR_HANDLER, + ZEND_U_NORMALIZE_SPEC_VAR_HANDLER, + ZEND_U_NORMALIZE_SPEC_VAR_HANDLER, + ZEND_U_NORMALIZE_SPEC_VAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_U_NORMALIZE_SPEC_CV_HANDLER, + ZEND_U_NORMALIZE_SPEC_CV_HANDLER, + ZEND_U_NORMALIZE_SPEC_CV_HANDLER, + ZEND_U_NORMALIZE_SPEC_CV_HANDLER, + ZEND_U_NORMALIZE_SPEC_CV_HANDLER, ZEND_NULL_HANDLER }; zend_opcode_handlers = (opcode_handler_t*)labels; |
