diff --git a/.gitignore b/.gitignore index be17e244550..06dac174a96 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ *.tgz *.tar.gz *.tar.bz2 +*.tar.xz .FBCIndex .FBCLockFolder .deps diff --git a/EXTENSIONS b/EXTENSIONS index 61a1688b3c9..757a1a8fd6b 100644 --- a/EXTENSIONS +++ b/EXTENSIONS @@ -228,13 +228,6 @@ MAINTENANCE: Maintained STATUS: Working COMMENT: Use PostgreSQL 7.0.x or later. PostgreSQL 6.5.3 or less have fatal bug. ------------------------------------------------------------------------------- -EXTENSION: sqlite -PRIMARY MAINTAINER: Marcus Boerger , Wez Furlong , Ilia Alshanetsky -MAINTENANCE: Maintained -STATUS: Working -SINCE: 5.0 (Since 4.3.2 in PECL) -COMMENT: Integrates SQLite 2 embeddable SQL database engine. -------------------------------------------------------------------------------- EXTENSION: sqlite3 PRIMARY MAINTAINER: Scott MacVicar MAINTENANCE: Maintained @@ -385,6 +378,12 @@ MAINTENANCE: Maintained STATUS: Working SINCE: 4.0.4 ------------------------------------------------------------------------------- +EXTENSION: hash +PRIMARY MAINTAINER: Sara Golemon , Mike Wallner , Anatol Belski +MAINTENANCE: Maintained +STATUS: Working +SINCE: 5.1.2 +------------------------------------------------------------------------------- EXTENSION: iconv PRIMARY MAINTAINER: Moriyoshi Koizumi MAINTENANCE: Maintained @@ -422,22 +421,6 @@ PRIMARY MAINTAINER: Derick Rethans MAINTENANCE: Maintained STATUS: Working ------------------------------------------------------------------------------- -EXTENSION: mhash -PRIMARY MAINTAINER: Sascha Schumann , Scott MacVicar -MAINTENANCE: Unknown -STATUS: Working -------------------------------------------------------------------------------- -EXTENSION: mime_magic -PRIMARY MAINTAINER: Unknown -MAINTENANCE: Deprecated -STATUS: Experimental -COMMENT: Use the fileinfo extension instead -------------------------------------------------------------------------------- -EXTENSION: ming -PRIMARY MAINTAINER: Frank M. Kromann -MAINTENANCE: Unknown -STATUS: Experimental -------------------------------------------------------------------------------- EXTENSION: openssl PRIMARY MAINTAINER: Wez Furlong , Pierre-Alain Joye MAINTENANCE: Maintained diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 9d8cda84d68..03a148a473a 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1761,7 +1761,7 @@ static int copy_function_name(zval *zv TSRMLS_DC, int num_args, va_list args, ze Returns an array of all defined functions */ ZEND_FUNCTION(get_defined_functions) { - zval internal, user, *ret; + zval internal, user; if (zend_parse_parameters_none() == FAILURE) { return; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ee256e4d8d1..91bfbfeebba 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -132,6 +132,19 @@ static zend_string *zend_build_runtime_definition_key(zend_string *name, unsigne } /* }}} */ +static zend_bool zend_get_unqualified_name(const zend_string *name, const char **result, size_t *result_len) /* {{{ */ +{ + const char *ns_separator = zend_memrchr(name->val, '\\', name->len); + if (ns_separator != NULL) { + *result = ns_separator + 1; + *result_len = name->val + name->len - *result; + return 1; + } + + return 0; +} +/* }}} */ + static void init_compiler_declarables(TSRMLS_D) /* {{{ */ { ZVAL_LONG(&CG(declarables).ticks, 0); @@ -331,8 +344,10 @@ static inline int zend_add_literal_string(zend_op_array *op_array, zend_string * static int zend_add_func_name_literal(zend_op_array *op_array, zend_string *name TSRMLS_DC) /* {{{ */ { + /* Original name */ int ret = zend_add_literal_string(op_array, &name TSRMLS_CC); + /* Lowercased name */ zend_string *lc_name = zend_string_alloc(name->len, 0); zend_str_tolower_copy(lc_name->val, name->val, name->len); zend_add_literal_string(op_array, &lc_name TSRMLS_CC); @@ -343,19 +358,21 @@ static int zend_add_func_name_literal(zend_op_array *op_array, zend_string *name static int zend_add_ns_func_name_literal(zend_op_array *op_array, zend_string *name TSRMLS_DC) /* {{{ */ { - const char *ns_separator; + const char *unqualified_name; + size_t unqualified_name_len; + /* Original name */ int ret = zend_add_literal_string(op_array, &name TSRMLS_CC); + /* Lowercased name */ zend_string *lc_name = zend_string_alloc(name->len, 0); zend_str_tolower_copy(lc_name->val, name->val, name->len); zend_add_literal_string(op_array, &lc_name TSRMLS_CC); - ns_separator = zend_memrchr(name->val, '\\', name->len); - if (ns_separator != NULL) { - size_t len = name->len - (ns_separator - name->val + 1); - lc_name = zend_string_alloc(len, 0); - zend_str_tolower_copy(lc_name->val, ns_separator + 1, len); + /* Lowercased unqualfied name */ + if (zend_get_unqualified_name(name, &unqualified_name, &unqualified_name_len)) { + lc_name = zend_string_alloc(unqualified_name_len, 0); + zend_str_tolower_copy(lc_name->val, unqualified_name, unqualified_name_len); zend_add_literal_string(op_array, &lc_name TSRMLS_CC); } @@ -365,8 +382,10 @@ static int zend_add_ns_func_name_literal(zend_op_array *op_array, zend_string *n static int zend_add_class_name_literal(zend_op_array *op_array, zend_string *name TSRMLS_DC) /* {{{ */ { + /* Original name */ int ret = zend_add_literal_string(op_array, &name TSRMLS_CC); + /* Lowercased name */ zend_string *lc_name = zend_string_alloc(name->len, 0); zend_str_tolower_copy(lc_name->val, name->val, name->len); zend_add_literal_string(op_array, &lc_name TSRMLS_CC); @@ -576,12 +595,16 @@ zend_string *zend_prefix_with_ns(zend_string *name TSRMLS_DC) { } } -void *zend_hash_find_ptr_lc(HashTable *ht, char *str, size_t len) { +void *zend_hash_find_ptr_lc(HashTable *ht, const char *str, size_t len) { void *result; - zend_string *lcname = zend_string_alloc(len, 0); + zend_string *lcname; + ALLOCA_FLAG(use_heap); + + STR_ALLOCA_ALLOC(lcname, len, use_heap); zend_str_tolower_copy(lcname->val, str, len); result = zend_hash_find_ptr(ht, lcname); - zend_string_free(lcname); + STR_ALLOCA_FREE(lcname, use_heap); + return result; } @@ -1131,55 +1154,45 @@ ZEND_API int zend_unmangle_property_name_ex(const zend_string *name, const char } /* }}} */ -static zend_constant *zend_get_ct_const(zend_string *name, int all_internal_constants_substitution TSRMLS_DC) /* {{{ */ +static zend_constant *zend_lookup_reserved_const(const char *name, size_t len TSRMLS_DC) /* {{{ */ { - zend_constant *c = NULL; - char *lookup_name; - - if (name->val[0] == '\\') { - c = zend_hash_str_find_ptr(EG(zend_constants), name->val + 1, name->len - 1); - if (!c) { - lookup_name = zend_str_tolower_dup(name->val + 1, name->len - 1); - c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, name->len - 1); - efree(lookup_name); - - if (c && (c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) { - return c; - } - return NULL; - } - } else if ((c = zend_hash_find_ptr(EG(zend_constants), name)) == NULL) { - lookup_name = zend_str_tolower_dup(name->val, name->len); - c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, name->len); - efree(lookup_name); - - if (c && (c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) { - return c; - } - return NULL; - } - - if (c->flags & CONST_CT_SUBST) { - return c; - } - if (all_internal_constants_substitution && - (c->flags & CONST_PERSISTENT) && - !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION) && - !Z_CONSTANT(c->value)) { + zend_constant *c = zend_hash_find_ptr_lc(EG(zend_constants), name, len); + if (c && !(c->flags & CONST_CS) && (c->flags & CONST_CT_SUBST)) { return c; } return NULL; } /* }}} */ -static int zend_constant_ct_subst(zval *result, zend_string *name, int all_internal_constants_substitution TSRMLS_DC) /* {{{ */ +static zend_bool zend_try_ct_eval_const(zval *zv, zend_string *name, zend_bool is_fully_qualified TSRMLS_DC) /* {{{ */ { - zend_constant *c = zend_get_ct_const(name, all_internal_constants_substitution TSRMLS_CC); + zend_constant *c; - if (c) { - ZVAL_DUP(result, &c->value); - return 1; + if (!(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) { + /* Substitute case-sensitive (or lowercase) persistent constants */ + c = zend_hash_find_ptr(EG(zend_constants), name); + if (c && (c->flags & CONST_PERSISTENT)) { + ZVAL_DUP(zv, &c->value); + return 1; + } } + + { + /* Substitute true, false and null (including unqualified usage in namespaces) */ + const char *lookup_name = name->val; + size_t lookup_len = name->len; + + if (!is_fully_qualified) { + zend_get_unqualified_name(name, &lookup_name, &lookup_len); + } + + c = zend_lookup_reserved_const(lookup_name, lookup_len TSRMLS_CC); + if (c) { + ZVAL_DUP(zv, &c->value); + return 1; + } + } + return 0; } /* }}} */ @@ -3922,8 +3935,6 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo } if (op_array->fn_flags & ZEND_ACC_ABSTRACT) { - //zend_op *opline; - if (op_array->fn_flags & ZEND_ACC_PRIVATE) { zend_error_noreturn(E_COMPILE_ERROR, "%s function %s::%s() cannot be declared private", in_interface ? "Interface" : "Abstract", ce->name->val, name->val); @@ -3935,11 +3946,6 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo } ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS; - - /*opline = get_next_op(op_array TSRMLS_CC); - opline->opcode = ZEND_RAISE_ABSTRACT_ERROR; - SET_UNUSED(opline->op1); - SET_UNUSED(opline->op2);*/ } else if (!has_body) { zend_error_noreturn(E_COMPILE_ERROR, "Non-abstract method %s::%s() must contain body", ce->name->val, name->val); @@ -4692,10 +4698,11 @@ void zend_compile_use(zend_ast *ast TSRMLS_DC) /* {{{ */ if (new_name_ast) { new_name = zend_string_copy(zend_ast_get_str(new_name_ast)); } else { - /* The form "use A\B" is eqivalent to "use A\B as B" */ - const char *p = zend_memrchr(old_name->val, '\\', old_name->len); - if (p) { - new_name = zend_string_init(p + 1, old_name->len - (p - old_name->val + 1), 0); + const char *unqualified_name; + size_t unqualified_name_len; + if (zend_get_unqualified_name(old_name, &unqualified_name, &unqualified_name_len)) { + /* The form "use A\B" is eqivalent to "use A\B as B" */ + new_name = zend_string_init(unqualified_name, unqualified_name_len, 0); } else { new_name = zend_string_copy(old_name); @@ -4799,7 +4806,7 @@ void zend_compile_const_decl(zend_ast *ast TSRMLS_DC) /* {{{ */ value_node.op_type = IS_CONST; zend_const_expr_to_zval(value_zv, value_ast TSRMLS_CC); - if (zend_get_ct_const(name, 0 TSRMLS_CC)) { + if (zend_lookup_reserved_const(name->val, name->len TSRMLS_CC)) { zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare constant '%s'", name->val); } @@ -5552,7 +5559,7 @@ void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ { zend_ast_list *list = zend_ast_get_list(ast); zend_op *opline; - uint32_t i, opnum_init; + uint32_t i, opnum_init = -1; zend_bool packed = 1; if (zend_try_ct_eval_array(&result->u.constant, ast TSRMLS_CC)) { @@ -5560,8 +5567,6 @@ void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ return; } - opnum_init = get_next_op_number(CG(active_op_array)); - for (i = 0; i < list->children; ++i) { zend_ast *elem_ast = list->child[i]; zend_ast *value_ast = elem_ast->child[0]; @@ -5584,6 +5589,7 @@ void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ } if (i == 0) { + opnum_init = get_next_op_number(CG(active_op_array)); opline = zend_emit_op_tmp(result, ZEND_INIT_ARRAY, &value_node, key_node_ptr TSRMLS_CC); opline->extended_value = list->children << ZEND_ARRAY_SIZE_SHIFT; } else { @@ -5605,6 +5611,7 @@ void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ /* Add a flag to INIT_ARRAY if we know this array cannot be packed */ if (!packed) { + ZEND_ASSERT(opnum_init != -1); opline = &CG(active_op_array)->opcodes[opnum_init]; opline->extended_value |= ZEND_ARRAY_NOT_PACKED; } @@ -5622,7 +5629,7 @@ void zend_compile_const(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ zend_string *resolved_name = zend_resolve_const_name( orig_name, name_ast->attr, &is_fully_qualified TSRMLS_CC); - if (zend_constant_ct_subst(&result->u.constant, resolved_name, 1 TSRMLS_CC)) { + if (zend_try_ct_eval_const(&result->u.constant, resolved_name, is_fully_qualified TSRMLS_CC)) { result->op_type = IS_CONST; zend_string_release(resolved_name); return; @@ -5858,16 +5865,16 @@ void zend_compile_const_expr_const(zend_ast **ast_ptr TSRMLS_DC) /* {{{ */ zend_bool is_fully_qualified; zval result, resolved_name; + ZVAL_STR(&resolved_name, zend_resolve_const_name( + orig_name, name_ast->attr, &is_fully_qualified TSRMLS_CC)); - if (zend_constant_ct_subst(&result, orig_name, 0 TSRMLS_CC)) { + if (zend_try_ct_eval_const(&result, Z_STR(resolved_name), is_fully_qualified TSRMLS_CC)) { + zend_string_release(Z_STR(resolved_name)); zend_ast_destroy(ast); *ast_ptr = zend_ast_create_zval(&result); return; } - ZVAL_STR(&resolved_name, zend_resolve_const_name( - orig_name, name_ast->attr, &is_fully_qualified TSRMLS_CC)); - Z_TYPE_INFO(resolved_name) = IS_CONSTANT_EX; if (!is_fully_qualified) { Z_CONST_FLAGS(resolved_name) = IS_CONSTANT_UNQUALIFIED; @@ -6352,10 +6359,20 @@ void zend_eval_const_expr(zend_ast **ast_ptr TSRMLS_DC) /* {{{ */ } break; case ZEND_AST_CONST: - if (!zend_constant_ct_subst(&result, zend_ast_get_str(ast->child[0]), 0 TSRMLS_CC)) { + { + zend_ast *name_ast = ast->child[0]; + zend_bool is_fully_qualified; + zend_string *resolved_name = zend_resolve_const_name( + zend_ast_get_str(name_ast), name_ast->attr, &is_fully_qualified TSRMLS_CC); + + if (!zend_try_ct_eval_const(&result, resolved_name, is_fully_qualified TSRMLS_CC)) { + zend_string_release(resolved_name); return; } + + zend_string_release(resolved_name); break; + } default: return; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 573f1fe5ec0..cf1256ab3c7 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -367,7 +367,6 @@ struct _zend_execute_data { zend_uchar frame_kind; zend_class_entry *called_scope; zend_object *object; - zend_execute_data *prev_nested_call; zend_execute_data *prev_execute_data; zval *return_value; zend_class_entry *scope; /* function scope (self) */ diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 999b6d790e0..b3770526dbb 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -85,7 +85,7 @@ void zend_exception_restore(TSRMLS_D) /* {{{ */ } /* }}} */ -void zend_throw_exception_internal(zval *exception TSRMLS_DC) /* {{{ */ +ZEND_API void zend_throw_exception_internal(zval *exception TSRMLS_DC) /* {{{ */ { #ifdef HAVE_DTRACE if (DTRACE_EXCEPTION_THROWN_ENABLED()) { diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index 5aa6544e5da..3118ce10538 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -30,7 +30,7 @@ ZEND_API void zend_exception_set_previous(zend_object *exception, zend_object *a ZEND_API void zend_exception_save(TSRMLS_D); ZEND_API void zend_exception_restore(TSRMLS_D); -void zend_throw_exception_internal(zval *exception TSRMLS_DC); +ZEND_API void zend_throw_exception_internal(zval *exception TSRMLS_DC); void zend_register_default_exception(TSRMLS_D); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 517cbf530da..012e2f5acec 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1609,11 +1609,13 @@ ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data */ zend_execute_data *execute_data; uint32_t num_args = call->num_args; + size_t stack_size = (ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args)) * sizeof(zval); EG(argument_stack) = zend_vm_stack_new_page( - MAX(ZEND_VM_STACK_PAGE_SIZE, - ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args))); - EG(argument_stack)->prev = NULL; + EXPECTED(stack_size < ZEND_VM_STACK_FREE_PAGE_SIZE) ? + ZEND_VM_STACK_PAGE_SIZE : + ZEND_VM_STACK_PAGE_ALIGNED_SIZE(stack_size), + NULL); execute_data = zend_vm_stack_push_call_frame( (zend_function*)op_array, @@ -1663,7 +1665,7 @@ static zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call, int used_stack = (EG(argument_stack)->top - (zval*)call) + additional_args; /* copy call frame into new stack segment */ - zend_vm_stack_extend(used_stack TSRMLS_CC); + zend_vm_stack_extend(used_stack * sizeof(zval) TSRMLS_CC); new_call = (zend_execute_data*)EG(argument_stack)->top; EG(argument_stack)->top += used_stack; *new_call = *call; diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 334a4ccc038..ce01e51d3f5 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -137,7 +137,9 @@ ZEND_API int zval_update_constant_no_inline_change(zval *pp, zend_class_entry *s ZEND_API int zval_update_constant_ex(zval *pp, zend_bool inline_change, zend_class_entry *scope TSRMLS_DC); /* dedicated Zend executor functions - do not use! */ -#define ZEND_VM_STACK_PAGE_SIZE (16 * 1024) /* should be a power of 2 */ +#define ZEND_VM_STACK_PAGE_SLOTS (16 * 1024) /* should be a power of 2 */ + +#define ZEND_VM_STACK_PAGE_SIZE (ZEND_VM_STACK_PAGE_SLOTS * sizeof(zval)) struct _zend_vm_stack { zval *top; @@ -145,33 +147,30 @@ struct _zend_vm_stack { zend_vm_stack prev; }; -#define ZEND_VM_STACK_HEADER_SLOT \ +#define ZEND_VM_STACK_HEADER_SLOTS \ ((ZEND_MM_ALIGNED_SIZE(sizeof(struct _zend_vm_stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval))) +#define ZEND_VM_STACK_FREE_PAGE_SIZE \ + ((ZEND_VM_STACK_PAGE_SLOTS - ZEND_VM_STACK_HEADER_SLOTS) * sizeof(zval)) + +#define ZEND_VM_STACK_PAGE_ALIGNED_SIZE(size) \ + (((size) + (ZEND_VM_STACK_FREE_PAGE_SIZE - 1)) & ~ZEND_VM_STACK_PAGE_SIZE) + #define ZEND_VM_STACK_ELEMETS(stack) \ - (((zval*)(stack)) + ZEND_VM_STACK_HEADER_SLOT) + (((zval*)(stack)) + ZEND_VM_STACK_HEADER_SLOTS) -#define ZEND_VM_STACK_GROW_IF_NEEDED(count) \ - do { \ - if (UNEXPECTED(((count) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) > \ - (size_t)(((char*)EG(argument_stack)->end) - \ - ((char*)EG(argument_stack)->top)))) { \ - zend_vm_stack_extend((count) TSRMLS_CC); \ - } \ - } while (0) - -static zend_always_inline zend_vm_stack zend_vm_stack_new_page(int count) { - zend_vm_stack page = (zend_vm_stack)emalloc(count * ZEND_MM_ALIGNED_SIZE(sizeof(zval))); +static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend_vm_stack prev) { + zend_vm_stack page = (zend_vm_stack)emalloc(size); page->top = ZEND_VM_STACK_ELEMETS(page); - page->end = (zval*)page + count; - page->prev = NULL; + page->end = (zval*)((char*)page + size); + page->prev = prev; return page; } static zend_always_inline void zend_vm_stack_init(TSRMLS_D) { - EG(argument_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE); + EG(argument_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE, NULL); EG(argument_stack)->top++; } @@ -186,16 +185,24 @@ static zend_always_inline void zend_vm_stack_destroy(TSRMLS_D) } } -static zend_always_inline void zend_vm_stack_extend(uint32_t count TSRMLS_DC) +static zend_always_inline void zend_vm_stack_extend(size_t size TSRMLS_DC) { - uint32_t size = count * ZEND_MM_ALIGNED_SIZE(sizeof(zval)); - zend_vm_stack p = zend_vm_stack_new_page( - (size >= (ZEND_VM_STACK_PAGE_SIZE - ZEND_VM_STACK_HEADER_SLOT) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) ? - (size + ((ZEND_VM_STACK_HEADER_SLOT + ZEND_VM_STACK_PAGE_SIZE) * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) - 1) & - ~((ZEND_VM_STACK_PAGE_SIZE * ZEND_MM_ALIGNED_SIZE(sizeof(zval))) - 1) : - ZEND_VM_STACK_PAGE_SIZE); - p->prev = EG(argument_stack); - EG(argument_stack) = p; + EG(argument_stack) = zend_vm_stack_new_page( + EXPECTED(size < ZEND_VM_STACK_FREE_PAGE_SIZE) ? + ZEND_VM_STACK_PAGE_SIZE : ZEND_VM_STACK_PAGE_ALIGNED_SIZE(size), + EG(argument_stack)); +} + +static zend_always_inline zval* zend_vm_stack_alloc(size_t size TSRMLS_DC) +{ + char *top = (char*)EG(argument_stack)->top; + + if (UNEXPECTED(size > (size_t)(((char*)EG(argument_stack)->end) - top))) { + zend_vm_stack_extend(size TSRMLS_CC); + top = (char*)EG(argument_stack)->top; + } + EG(argument_stack)->top = (zval*)(top + size); + return (zval*)top; } static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(zend_function *func, uint32_t num_args, zend_uchar flags, zend_class_entry *called_scope, zend_object *object, zend_execute_data *prev TSRMLS_DC) @@ -206,15 +213,13 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(zend_ if (ZEND_USER_CODE(func->type)) { used_stack += func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args); } - ZEND_VM_STACK_GROW_IF_NEEDED(used_stack); - call = (zend_execute_data*)EG(argument_stack)->top; - EG(argument_stack)->top += used_stack; + call = (zend_execute_data*)zend_vm_stack_alloc(used_stack * sizeof(zval) TSRMLS_CC); call->func = func; call->num_args = 0; call->flags = flags; call->called_scope = called_scope; call->object = object; - call->prev_nested_call = prev; + call->prev_execute_data = prev; return call; } @@ -249,13 +254,12 @@ static zend_always_inline void zend_vm_stack_free_args(zend_execute_data *call T static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data *call TSRMLS_DC) { - if (UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (zval*)call)) { - zend_vm_stack p = EG(argument_stack); - + zend_vm_stack p = EG(argument_stack); + if (UNEXPECTED(ZEND_VM_STACK_ELEMETS(p) == (zval*)call)) { EG(argument_stack) = p->prev; efree(p); } else { - EG(argument_stack)->top = (zval*)call; + p->top = (zval*)call; } } diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index f59a10179b6..b528bd0ab5f 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -703,7 +703,6 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS dummy_execute_data = *EG(current_execute_data); dummy_execute_data.prev_execute_data = EG(current_execute_data); dummy_execute_data.call = NULL; - dummy_execute_data.prev_nested_call = NULL; dummy_execute_data.opline = NULL; dummy_execute_data.func = NULL; EG(current_execute_data) = &dummy_execute_data; diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index b038600ead2..4c64cb75907 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -71,7 +71,7 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato if (execute_data->call->object) { OBJ_RELEASE(execute_data->call->object); } - execute_data->call = execute_data->call->prev_nested_call; + execute_data->call = execute_data->call->prev_execute_data; } } /* }}} */ diff --git a/Zend/zend_objects_API.h b/Zend/zend_objects_API.h index df22a26cc92..362d79a68c2 100644 --- a/Zend/zend_objects_API.h +++ b/Zend/zend_objects_API.h @@ -37,14 +37,7 @@ } while (0) -#define OBJ_RELEASE(obj) do { \ - zend_object *_obj = (obj); \ - if (--GC_REFCOUNT(_obj) == 0) { \ - zend_objects_store_del(_obj TSRMLS_CC); \ - } else { \ - gc_possible_root(&_obj->gc TSRMLS_CC); \ - } \ - } while (0) +#define OBJ_RELEASE(obj) zend_object_release(obj TSRMLS_CC) typedef struct _zend_objects_store { zend_object **object_buckets; @@ -78,6 +71,15 @@ ZEND_API zend_object *zend_object_create_proxy(zval *object, zval *member TSRMLS ZEND_API zend_object_handlers *zend_get_std_object_handlers(void); END_EXTERN_C() +static zend_always_inline void zend_object_release(zend_object *obj TSRMLS_DC) +{ + if (--GC_REFCOUNT(obj) == 0) { + zend_objects_store_del(obj TSRMLS_CC); + } else if (UNEXPECTED(!GC_INFO(obj))) { + gc_possible_root(&obj->gc TSRMLS_CC); + } +} + #endif /* ZEND_OBJECTS_H */ /* diff --git a/Zend/zend_virtual_cwd.c b/Zend/zend_virtual_cwd.c index b061d5a00d0..01a91cad80f 100644 --- a/Zend/zend_virtual_cwd.c +++ b/Zend/zend_virtual_cwd.c @@ -294,7 +294,7 @@ CWD_API int php_sys_readlink(const char *link, char *target, size_t target_len){ CWD_API int php_sys_stat_ex(const char *path, zend_stat_t *buf, int lstat) /* {{{ */ { WIN32_FILE_ATTRIBUTE_DATA data; - __int64 t; + LARGE_INTEGER t; const size_t path_len = strlen(path); ALLOCA_FLAG(use_heap_large); @@ -393,10 +393,11 @@ CWD_API int php_sys_stat_ex(const char *path, zend_stat_t *buf, int lstat) /* {{ } buf->st_nlink = 1; - t = data.nFileSizeHigh; - t = t << 32; - t |= data.nFileSizeLow; - buf->st_size = t; + t.HighPart = data.nFileSizeHigh; + t.LowPart = data.nFileSizeLow; + /* It's an overflow on 32 bit, however it won't fix as long + as zend_long is 32 bit. */ + buf->st_size = (zend_long)t.QuadPart; buf->st_atime = FileTimeToUnixTime(&data.ftLastAccessTime); buf->st_ctime = FileTimeToUnixTime(&data.ftCreationTime); buf->st_mtime = FileTimeToUnixTime(&data.ftLastWriteTime); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 405c3f45c96..966cf915763 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1985,17 +1985,6 @@ ZEND_VM_HANDLER(70, ZEND_FREE, TMP|VAR, ANY) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(53, ZEND_INIT_STRING, ANY, ANY) -{ - USE_OPLINE - zval *tmp = EX_VAR(opline->result.var); - - SAVE_OPLINE(); - ZVAL_EMPTY_STRING(tmp); - /*CHECK_EXCEPTION();*/ - ZEND_VM_NEXT_OPCODE(); -} - ZEND_VM_HANDLER(54, ZEND_ADD_CHAR, TMP|UNUSED, CONST) { USE_OPLINE @@ -2545,7 +2534,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) zend_function *fbc = call->func; SAVE_OPLINE(); - EX(call) = call->prev_nested_call; + EX(call) = call->prev_execute_data; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name->val, fbc->common.function_name->val); @@ -2669,11 +2658,12 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) zend_vm_stack_free_call_frame(call TSRMLS_CC); } else { call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, return_value, EXPECTED(zend_execute_ex == execute_ex) ? VM_FRAME_NESTED_FUNCTION : VM_FRAME_TOP_FUNCTION TSRMLS_CC); + i_init_func_execute_data(call, &fbc->op_array, return_value, VM_FRAME_NESTED_FUNCTION TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + call->frame_kind = VM_FRAME_TOP_FUNCTION; zend_execute_ex(call TSRMLS_CC); } } @@ -2721,11 +2711,7 @@ ZEND_VM_C_LABEL(fcall_end_change_scope): zend_object_store_ctor_failed(Z_OBJ(EG(This)) TSRMLS_CC); } } - if (!Z_DELREF(EG(This))) { - _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); - } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { - gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); - } + OBJ_RELEASE(Z_OBJ(EG(This))); } Z_OBJ(EG(This)) = EX(object); EG(scope) = EX(scope); @@ -4145,10 +4131,11 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY) } call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value, EXPECTED(zend_execute_ex == execute_ex) ? VM_FRAME_NESTED_CODE : VM_FRAME_TOP_CODE TSRMLS_CC); + i_init_code_execute_data(call, new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + call->frame_kind = VM_FRAME_TOP_CODE; zend_execute_ex(call TSRMLS_CC); } @@ -5082,13 +5069,6 @@ ZEND_VM_HANDLER(57, ZEND_BEGIN_SILENCE, ANY, ANY) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(142, ZEND_RAISE_ABSTRACT_ERROR, ANY, ANY) -{ - SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EX(scope)->name->val, EX(func)->op_array.function_name->val); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ -} - ZEND_VM_HANDLER(58, ZEND_END_SILENCE, TMP, ANY) { USE_OPLINE @@ -5427,7 +5407,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } OBJ_RELEASE(call->object); } - EX(call) = call->prev_nested_call; + EX(call) = call->prev_execute_data; zend_vm_stack_free_call_frame(call TSRMLS_CC); call = EX(call); } while (call); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index d49926aa1c0..eeb6d5cd3f0 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -488,17 +488,6 @@ static int ZEND_FASTCALL ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_CONTINUE(); } -static int ZEND_FASTCALL ZEND_INIT_STRING_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zval *tmp = EX_VAR(opline->result.var); - - SAVE_OPLINE(); - ZVAL_EMPTY_STRING(tmp); - /*CHECK_EXCEPTION();*/ - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -506,7 +495,7 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_function *fbc = call->func; SAVE_OPLINE(); - EX(call) = call->prev_nested_call; + EX(call) = call->prev_execute_data; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name->val, fbc->common.function_name->val); @@ -630,11 +619,12 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_vm_stack_free_call_frame(call TSRMLS_CC); } else { call->prev_execute_data = execute_data; - i_init_func_execute_data(call, &fbc->op_array, return_value, EXPECTED(zend_execute_ex == execute_ex) ? VM_FRAME_NESTED_FUNCTION : VM_FRAME_TOP_FUNCTION TSRMLS_CC); + i_init_func_execute_data(call, &fbc->op_array, return_value, VM_FRAME_NESTED_FUNCTION TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + call->frame_kind = VM_FRAME_TOP_FUNCTION; zend_execute_ex(call TSRMLS_CC); } } @@ -682,11 +672,7 @@ fcall_end_change_scope: zend_object_store_ctor_failed(Z_OBJ(EG(This)) TSRMLS_CC); } } - if (!Z_DELREF(EG(This))) { - _zval_dtor_func_for_ptr(Z_COUNTED(EG(This)) ZEND_FILE_LINE_CC); - } else if (UNEXPECTED(!Z_GC_INFO(EG(This)))) { - gc_possible_root(Z_COUNTED(EG(This)) TSRMLS_CC); - } + OBJ_RELEASE(Z_OBJ(EG(This))); } Z_OBJ(EG(This)) = EX(object); EG(scope) = EX(scope); @@ -1142,13 +1128,6 @@ static int ZEND_FASTCALL ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR ZEND_VM_NEXT_OPCODE(); } -static int ZEND_FASTCALL ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - SAVE_OPLINE(); - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EX(scope)->name->val, EX(func)->op_array.function_name->val); - ZEND_VM_NEXT_OPCODE(); /* Never reached */ -} - static int ZEND_FASTCALL ZEND_EXT_STMT_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { SAVE_OPLINE(); @@ -1330,7 +1309,7 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER } OBJ_RELEASE(call->object); } - EX(call) = call->prev_nested_call; + EX(call) = call->prev_execute_data; zend_vm_stack_free_call_frame(call TSRMLS_CC); call = EX(call); } while (call); @@ -3023,10 +3002,11 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HA } call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value, EXPECTED(zend_execute_ex == execute_ex) ? VM_FRAME_NESTED_CODE : VM_FRAME_TOP_CODE TSRMLS_CC); + i_init_code_execute_data(call, new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + call->frame_kind = VM_FRAME_TOP_CODE; zend_execute_ex(call TSRMLS_CC); } @@ -9761,10 +9741,11 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HAND } call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value, EXPECTED(zend_execute_ex == execute_ex) ? VM_FRAME_NESTED_CODE : VM_FRAME_TOP_CODE TSRMLS_CC); + i_init_code_execute_data(call, new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + call->frame_kind = VM_FRAME_TOP_CODE; zend_execute_ex(call TSRMLS_CC); } @@ -10070,12 +10051,12 @@ static int ZEND_FASTCALL ZEND_COALESCE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); } else if (IS_TMP_VAR == IS_VAR && is_ref) { if (Z_OPT_REFCOUNTED_P(value)) Z_ADDREF_P(value); - zval_dtor(free_op1.var); + zval_ptr_dtor_nogc(free_op1.var); } ZEND_VM_JMP(opline->op2.jmp_addr); } - zval_dtor(free_op1.var); + zval_ptr_dtor_nogc(free_op1.var); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -16349,10 +16330,11 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND } call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value, EXPECTED(zend_execute_ex == execute_ex) ? VM_FRAME_NESTED_CODE : VM_FRAME_TOP_CODE TSRMLS_CC); + i_init_code_execute_data(call, new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + call->frame_kind = VM_FRAME_TOP_CODE; zend_execute_ex(call TSRMLS_CC); } @@ -33630,10 +33612,11 @@ static int ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL } call->prev_execute_data = execute_data; - i_init_code_execute_data(call, new_op_array, return_value, EXPECTED(zend_execute_ex == execute_ex) ? VM_FRAME_NESTED_CODE : VM_FRAME_TOP_CODE TSRMLS_CC); + i_init_code_execute_data(call, new_op_array, return_value, VM_FRAME_NESTED_CODE TSRMLS_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { ZEND_VM_ENTER(); } else { + call->frame_kind = VM_FRAME_TOP_CODE; zend_execute_ex(call TSRMLS_CC); } @@ -44626,31 +44609,31 @@ void zend_init_opcodes_handlers(void) ZEND_BOOL_SPEC_CV_HANDLER, ZEND_BOOL_SPEC_CV_HANDLER, ZEND_BOOL_SPEC_CV_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, - ZEND_INIT_STRING_SPEC_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -46851,31 +46834,31 @@ void zend_init_opcodes_handlers(void) ZEND_DECLARE_FUNCTION_SPEC_HANDLER, ZEND_DECLARE_FUNCTION_SPEC_HANDLER, ZEND_DECLARE_FUNCTION_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, - ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 23b49e3d71c..d31eb141414 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -75,7 +75,7 @@ const char *zend_vm_opcodes_map[170] = { "ZEND_BRK", "ZEND_CONT", "ZEND_BOOL", - "ZEND_INIT_STRING", + NULL, "ZEND_ADD_CHAR", "ZEND_ADD_STRING", "ZEND_ADD_VAR", @@ -164,7 +164,7 @@ const char *zend_vm_opcodes_map[170] = { "ZEND_DECLARE_CLASS", "ZEND_DECLARE_INHERITED_CLASS", "ZEND_DECLARE_FUNCTION", - "ZEND_RAISE_ABSTRACT_ERROR", + NULL, "ZEND_DECLARE_CONST", "ZEND_ADD_INTERFACE", "ZEND_DECLARE_INHERITED_CLASS_DELAYED", diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index c1ecebb2f38..43aea9ee950 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -75,7 +75,6 @@ ZEND_API const char *zend_get_opcode_name(zend_uchar opcode); #define ZEND_BRK 50 #define ZEND_CONT 51 #define ZEND_BOOL 52 -#define ZEND_INIT_STRING 53 #define ZEND_ADD_CHAR 54 #define ZEND_ADD_STRING 55 #define ZEND_ADD_VAR 56 @@ -155,7 +154,6 @@ ZEND_API const char *zend_get_opcode_name(zend_uchar opcode); #define ZEND_DECLARE_CLASS 139 #define ZEND_DECLARE_INHERITED_CLASS 140 #define ZEND_DECLARE_FUNCTION 141 -#define ZEND_RAISE_ABSTRACT_ERROR 142 #define ZEND_DECLARE_CONST 143 #define ZEND_ADD_INTERFACE 144 #define ZEND_DECLARE_INHERITED_CLASS_DELAYED 145 diff --git a/ext/ext_skel b/ext/ext_skel index e6b01fd4fc6..c0c398d15ec 100755 --- a/ext/ext_skel +++ b/ext/ext_skel @@ -156,12 +156,12 @@ if test "\$PHP_$EXTNAME" != "no"; then dnl PHP_CHECK_LIBRARY(\$LIBNAME,\$LIBSYMBOL, dnl [ - dnl PHP_ADD_LIBRARY_WITH_PATH(\$LIBNAME, \$${EXTNAME}_DIR/lib, ${EXTNAME}_SHARED_LIBADD) + dnl PHP_ADD_LIBRARY_WITH_PATH(\$LIBNAME, \$${EXTNAME}_DIR/\$PHP_LIBDIR, ${EXTNAME}_SHARED_LIBADD) dnl AC_DEFINE(HAVE_${EXTNAME}LIB,1,[ ]) dnl ],[ dnl AC_MSG_ERROR([wrong $extname lib version or lib not found]) dnl ],[ - dnl -L\$${EXTNAME}_DIR/lib -lm + dnl -L\$${EXTNAME}_DIR/\$PHP_LIBDIR -lm dnl ]) dnl dnl PHP_SUBST(${EXTNAME}_SHARED_LIBADD) diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 73a65485a53..869bd3ccba7 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -1054,25 +1054,6 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, VAR_UNSET(opline->op1); COPY_NODE(opline->op1, src->op1); MAKE_NOP(src); - } else if ((opline->opcode == ZEND_ADD_STRING || - opline->opcode == ZEND_ADD_CHAR) && - ZEND_OP1_TYPE(opline) == IS_TMP_VAR && - VAR_SOURCE(opline->op1) && - VAR_SOURCE(opline->op1)->opcode == ZEND_INIT_STRING) { - /* convert T = INIT_STRING(), T = ADD_STRING(T, X) to T = QM_ASSIGN(X) */ - /* CHECKME: Remove ZEND_ADD_VAR optimization, since some conversions - - namely, BOOL(false)->string - don't allocate memory but use empty_string - and ADD_CHAR fails */ - zend_op *src = VAR_SOURCE(opline->op1); - VAR_UNSET(opline->op1); - COPY_NODE(opline->op1, opline->op2); - if (opline->opcode == ZEND_ADD_CHAR) { - char c = (char)Z_LVAL(ZEND_OP2_LITERAL(opline)); - ZVAL_STRINGL(&ZEND_OP1_LITERAL(opline), &c, 1); - } - SET_UNUSED(opline->op2); - MAKE_NOP(src); - opline->opcode = ZEND_QM_ASSIGN; } else if ((opline->opcode == ZEND_ADD_STRING || opline->opcode == ZEND_ADD_CHAR || opline->opcode == ZEND_ADD_VAR || @@ -1094,23 +1075,6 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array, opline->opcode = ZEND_CONCAT; literal_dtor(&ZEND_OP2_LITERAL(src)); /* will take care of empty_string too */ MAKE_NOP(src); -//??? This optimization can't work anymore because ADD_VAR returns IS_TMP_VAR -//??? and ZEND_CAST returns IS_VAR. -//??? BTW: it wan't used for long time, because we don't use INIT_STRING -#if 0 - } else if (opline->opcode == ZEND_ADD_VAR && - ZEND_OP1_TYPE(opline) == IS_TMP_VAR && - VAR_SOURCE(opline->op1) && - VAR_SOURCE(opline->op1)->opcode == ZEND_INIT_STRING) { - /* convert T = INIT_STRING(), T = ADD_VAR(T, X) to T = CAST(STRING, X) */ - zend_op *src = VAR_SOURCE(opline->op1); - VAR_UNSET(opline->op1); - COPY_NODE(opline->op1, opline->op2); - SET_UNUSED(opline->op2); - MAKE_NOP(src); - opline->opcode = ZEND_CAST; - opline->extended_value = IS_STRING; -#endif } else if ((opline->opcode == ZEND_ADD_STRING || opline->opcode == ZEND_ADD_CHAR || opline->opcode == ZEND_ADD_VAR || diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 36611b812b8..e952ad90252 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -5126,7 +5126,7 @@ PHP_FUNCTION(php_strip_whitespace) char *filename; size_t filename_len; zend_lex_state original_lex_state; - zend_file_handle file_handle = {0}; + zend_file_handle file_handle = {{0}}; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p", &filename, &filename_len) == FAILURE) { RETURN_FALSE; diff --git a/ext/standard/browscap.c b/ext/standard/browscap.c index a591a67d442..a76fb136a3a 100644 --- a/ext/standard/browscap.c +++ b/ext/standard/browscap.c @@ -221,7 +221,7 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb static int browscap_read_file(char *filename, browser_data *browdata, int persistent TSRMLS_DC) /* {{{ */ { - zend_file_handle fh = {0}; + zend_file_handle fh = {{0}}; if (filename == NULL || filename[0] == '\0') { return FAILURE; @@ -379,15 +379,13 @@ static int browser_reg_compare(zval *browser TSRMLS_DC, int num_args, va_list ar number of characters changed in the user agent being checked versus the previous match found and the current match. */ if (Z_TYPE_P(found_browser_entry) == IS_ARRAY) { - int i, prev_len = 0, curr_len = 0, ua_len; - zval *current_match; + size_t i, prev_len = 0, curr_len = 0; + zval *current_match = zend_hash_str_find(Z_ARRVAL_P(browser), "browser_name_pattern", sizeof("browser_name_pattern")-1); - if ((current_match = zend_hash_str_find(Z_ARRVAL_P(browser), "browser_name_pattern", sizeof("browser_name_pattern")-1)) == NULL) { + if (!current_match) { return 0; } - ua_len = lookup_browser_length; - for (i = 0; i < Z_STRLEN_P(previous_match); i++) { switch (Z_STRVAL_P(previous_match)[i]) { case '?': diff --git a/ext/standard/cyr_convert.c b/ext/standard/cyr_convert.c index ea5cc193870..1718b757298 100644 --- a/ext/standard/cyr_convert.c +++ b/ext/standard/cyr_convert.c @@ -201,11 +201,11 @@ _cyr_mac = { * d - x-cp866 * m - x-mac-cyrillic *****************************************************************************/ -static char * php_convert_cyr_string(unsigned char *str, int length, char from, char to TSRMLS_DC) +static char * php_convert_cyr_string(unsigned char *str, size_t length, char from, char to TSRMLS_DC) { const unsigned char *from_table, *to_table; unsigned char tmp; - int i; + size_t i; from_table = NULL; to_table = NULL; @@ -258,8 +258,7 @@ static char * php_convert_cyr_string(unsigned char *str, int length, char from, if (!str) return (char *)str; - for( i = 0; ival, str->len, fr_cs[0], to_cs[0] TSRMLS_CC); + php_convert_cyr_string((unsigned char *) str->val, str->len, fr_cs[0], to_cs[0] TSRMLS_CC); RETVAL_NEW_STR(str); } /* }}} */ diff --git a/ext/standard/dns.c b/ext/standard/dns.c index a000ad9638a..13a1ab75df1 100644 --- a/ext/standard/dns.c +++ b/ext/standard/dns.c @@ -535,7 +535,7 @@ static u_char *php_parserr(u_char *cp, u_char *end, querybuf *answer, int type_t } if (n) { memcpy(tp->val + l2 , cp + l1 + 1, n); - add_next_index_stringl(&entries, cp + l1 + 1, n); + add_next_index_stringl(&entries, (char *) cp + l1 + 1, n); } l1 = l1 + n + 1; l2 = l2 + n; diff --git a/ext/standard/iptc.c b/ext/standard/iptc.c index 692d856757b..75bbdd22ce8 100644 --- a/ext/standard/iptc.c +++ b/ext/standard/iptc.c @@ -300,8 +300,8 @@ PHP_FUNCTION(iptcparse) { int inx = 0, len; unsigned int tagsfound = 0; - unsigned char *buffer, recnum, dataset, key[ 16 ]; - char *str; + unsigned char *buffer, recnum, dataset; + char *str, key[16]; size_t str_len; zval values, *element; diff --git a/ext/standard/md5.c b/ext/standard/md5.c index dc241180ed8..e5359c2bcfb 100644 --- a/ext/standard/md5.c +++ b/ext/standard/md5.c @@ -61,7 +61,7 @@ PHP_NAMED_FUNCTION(php_if_md5) PHP_MD5Update(&context, arg->val, arg->len); PHP_MD5Final(digest, &context); if (raw_output) { - RETURN_STRINGL(digest, 16); + RETURN_STRINGL((char *) digest, 16); } else { make_digest_ex(md5str, digest, 16); RETVAL_STRING(md5str); @@ -112,7 +112,7 @@ PHP_NAMED_FUNCTION(php_if_md5_file) PHP_MD5Final(digest, &context); if (raw_output) { - RETURN_STRINGL(digest, 16); + RETURN_STRINGL((char *) digest, 16); } else { make_digest_ex(md5str, digest, 16); RETVAL_STRING(md5str); diff --git a/ext/standard/sha1.c b/ext/standard/sha1.c index cd8b82f5e1e..249828fb3d6 100644 --- a/ext/standard/sha1.c +++ b/ext/standard/sha1.c @@ -46,10 +46,10 @@ PHP_FUNCTION(sha1) sha1str[0] = '\0'; PHP_SHA1Init(&context); - PHP_SHA1Update(&context, arg->val, arg->len); + PHP_SHA1Update(&context, (unsigned char *) arg->val, arg->len); PHP_SHA1Final(digest, &context); if (raw_output) { - RETURN_STRINGL(digest, 20); + RETURN_STRINGL((char *) digest, 20); } else { make_digest_ex(sha1str, digest, 20); RETVAL_STRING(sha1str); @@ -71,7 +71,7 @@ PHP_FUNCTION(sha1_file) unsigned char buf[1024]; unsigned char digest[20]; PHP_SHA1_CTX context; - int n; + size_t n; php_stream *stream; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|b", &arg, &arg_len, &raw_output) == FAILURE) { @@ -85,7 +85,7 @@ PHP_FUNCTION(sha1_file) PHP_SHA1Init(&context); - while ((n = php_stream_read(stream, buf, sizeof(buf))) > 0) { + while ((n = php_stream_read(stream, (char *) buf, sizeof(buf))) > 0) { PHP_SHA1Update(&context, buf, n); } @@ -93,12 +93,8 @@ PHP_FUNCTION(sha1_file) php_stream_close(stream); - if (n<0) { - RETURN_FALSE; - } - if (raw_output) { - RETURN_STRINGL(digest, 20); + RETURN_STRINGL((char *) digest, 20); } else { make_digest_ex(sha1str, digest, 20); RETVAL_STRING(sha1str); diff --git a/ext/standard/string.c b/ext/standard/string.c index dcd6f09a9c9..4a37f7a5b30 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -3983,7 +3983,7 @@ static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS, int convert_newlines) while (1) { char_count=0; - while ((!max_chars || max_chars > 0 && char_count < max_chars) && begin > 0) { + while ((!max_chars || (max_chars > 0 && char_count < max_chars)) && begin > 0) { char_count++; begin--; if (begin <= 0 || _isnewline(heb_str[begin])) { diff --git a/ext/standard/tests/streams/proc_open_bug51800.phpt b/ext/standard/tests/streams/proc_open_bug51800.phpt new file mode 100644 index 00000000000..53cafd85551 --- /dev/null +++ b/ext/standard/tests/streams/proc_open_bug51800.phpt @@ -0,0 +1,95 @@ +--TEST-- +Bug #51800 proc_open on Windows hangs forever +--SKIPIF-- + +--XFAIL-- +pipes have to be read/written simultaneously +--FILE-- + array("pipe", "rb"), // stdin + 1 => array("pipe", "wb"), // stdout + 2 => array("pipe", "wb") // stderr + ); + +/* create the proc file */ +$r = file_put_contents($callee, ' $status, + "stdout" => $stdout, + "stderr" => $stderr, +), strlen($stdout), strlen($stderr)); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +array(3) { + ["status"]=> + int(0) + ["stdout"]=> + string(10000) "a%s" + ["stderr"]=> + string(10000) "b%s" +} +int(10000) +int(10000) +===DONE=== + diff --git a/ext/standard/tests/streams/proc_open_bug51800_right.phpt b/ext/standard/tests/streams/proc_open_bug51800_right.phpt new file mode 100644 index 00000000000..b14fed2e5df --- /dev/null +++ b/ext/standard/tests/streams/proc_open_bug51800_right.phpt @@ -0,0 +1,78 @@ +--TEST-- +Bug #51800 proc_open on Windows hangs forever, the right way to do it +--FILE-- + array("pipe", "rb"), // stdin + 1 => array("pipe", "wb"), // stdout + 2 => array("pipe", "wb") // stderr + ); + +/* create the proc file */ +$r = file_put_contents($callee, ' $status, + "stdout" => $stdout, + "stderr" => $stderr, +), strlen($stdout), strlen($stderr)); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +array(3) { + ["status"]=> + int(0) + ["stdout"]=> + string(10000) "a%s" + ["stderr"]=> + string(10000) "b%s" +} +int(10000) +int(10000) +===DONE=== + diff --git a/ext/standard/tests/streams/proc_open_bug51800_right2.phpt b/ext/standard/tests/streams/proc_open_bug51800_right2.phpt new file mode 100644 index 00000000000..1e742745c1e --- /dev/null +++ b/ext/standard/tests/streams/proc_open_bug51800_right2.phpt @@ -0,0 +1,84 @@ +--TEST-- +Bug #51800 proc_open on Windows hangs forever, the right way to do it with more data +--FILE-- + array("pipe", "rb"), // stdin + 1 => array("pipe", "wb"), // stdout + 2 => array("pipe", "wb") // stderr + ); + +/* create the proc file */ +$r = file_put_contents($callee, ' $status, + "stdout" => $stdout, + "stderr" => $stderr, +), strlen($stdout), strlen($stderr)); + +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +array(3) { + ["status"]=> + int(0) + ["stdout"]=> + string(1000000) "a%s" + ["stderr"]=> + string(1000000) "b%s" +} +int(1000000) +int(1000000) +===DONE=== + diff --git a/ext/standard/tests/streams/proc_open_bug60120.phpt b/ext/standard/tests/streams/proc_open_bug60120.phpt new file mode 100644 index 00000000000..8768257a2ea --- /dev/null +++ b/ext/standard/tests/streams/proc_open_bug60120.phpt @@ -0,0 +1,71 @@ +--TEST-- +Bug #60120 proc_open hangs with stdin/out with 2048+ bytes +--FILE-- + true, 'binary_pipes' => true, 'bypass_shell' => false)); +$process = proc_open($cmd, $descriptors, $pipes, getcwd(), array(), $options); + +foreach ($pipes as $pipe) { + stream_set_blocking($pipe, false); +} +$writePipes = array($pipes[0]); +$stdinLen = strlen($stdin); +$stdinOffset = 0; + +unset($pipes[0]); + +while ($pipes || $writePipes) { + $r = $pipes; + $w = $writePipes; + $e = null; + $n = stream_select($r, $w, $e, 60); + + if (false === $n) { + break; + } elseif ($n === 0) { + proc_terminate($process); + + } + if ($w) { + $written = fwrite($writePipes[0], (binary)substr($stdin, $stdinOffset), 8192); + if (false !== $written) { + $stdinOffset += $written; + } + if ($stdinOffset >= $stdinLen) { + fclose($writePipes[0]); + $writePipes = null; + } + } + + foreach ($r as $pipe) { + $type = array_search($pipe, $pipes); + $data = fread($pipe, 8192); + var_dump($data); + if (false === $data || feof($pipe)) { + fclose($pipe); + unset($pipes[$type]); + } + } +} + + +?> +===DONE=== +--EXPECTF-- +string(2049) "%s" +string(2049) "%s" +string(0) "" +string(0) "" +===DONE=== + diff --git a/ext/standard/tests/streams/proc_open_bug64438.phpt b/ext/standard/tests/streams/proc_open_bug64438.phpt new file mode 100644 index 00000000000..b3857d09d42 --- /dev/null +++ b/ext/standard/tests/streams/proc_open_bug64438.phpt @@ -0,0 +1,70 @@ +--TEST-- +Bug #64438 proc_open hangs with stdin/out with 4097+ bytes +--FILE-- + true, 'binary_pipes' => true, 'bypass_shell' => false)); +$process = proc_open($cmd, $descriptors, $pipes, getcwd(), array(), $options); + +foreach ($pipes as $pipe) { + stream_set_blocking($pipe, false); +} +$writePipes = array($pipes[0]); +$stdinLen = strlen($stdin); +$stdinOffset = 0; + +unset($pipes[0]); + +while ($pipes || $writePipes) { + $r = $pipes; + $w = $writePipes; + $e = null; + $n = stream_select($r, $w, $e, 60); + + if (false === $n) { + break; + } elseif ($n === 0) { + proc_terminate($process); + + } + if ($w) { + $written = fwrite($writePipes[0], (binary)substr($stdin, $stdinOffset), 8192); + if (false !== $written) { + $stdinOffset += $written; + } + if ($stdinOffset >= $stdinLen) { + fclose($writePipes[0]); + $writePipes = null; + } + } + + foreach ($r as $pipe) { + $type = array_search($pipe, $pipes); + $data = fread($pipe, 8192); + var_dump($data); + if (false === $data || feof($pipe)) { + fclose($pipe); + unset($pipes[$type]); + } + } +} + +?> +===DONE=== +--EXPECTF-- +string(4097) "%s" +string(4097) "%s" +string(0) "" +string(0) "" +===DONE=== + diff --git a/ext/standard/tests/strings/setlocale_variation2.phpt b/ext/standard/tests/strings/setlocale_variation2.phpt index 10ae22fe0c6..5ebdfe8d507 100644 --- a/ext/standard/tests/strings/setlocale_variation2.phpt +++ b/ext/standard/tests/strings/setlocale_variation2.phpt @@ -20,9 +20,9 @@ echo "*** Testing setlocale() : usage variations ***\n"; function good_locale($locale) { /** - * Note: no_NO is a bogus locale and should not be used, see https://bugzilla.redhat.com/show_bug.cgi?id=532487 + * Note: no_NO is a bogus locale and should not be used, see https://bugzilla.redhat.com/971416 **/ - return $locale !== 'tt_RU@iqtelif.UTF-8' && substr($locale, 0, 5) !== "no_NO"; + return $locale !== 'tt_RU@iqtelif.UTF-8' && $locale !== 'no_NO.ISO-8859-1'; } /* Prototype : array list_system_locales( void ) diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index 2b8dcc478e1..28328c3cd5e 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -348,6 +348,34 @@ static size_t php_stdiop_read(php_stream *stream, char *buf, size_t count TSRMLS assert(data != NULL); if (data->fd >= 0) { +#ifdef PHP_WIN32 + php_stdio_stream_data *self = (php_stdio_stream_data*)stream->abstract; + + if (self->is_pipe || self->is_process_pipe) { + HANDLE ph = (HANDLE)_get_osfhandle(data->fd); + int retry = 0; + DWORD avail_read = 0; + + do { + /* Look ahead to get the available data amount to read. Do the same + as read() does, however not blocking forever. In case it failed, + no data will be read (better than block). */ + if (!PeekNamedPipe(ph, NULL, 0, NULL, &avail_read, NULL)) { + break; + } + /* If there's nothing to read, wait in 100ms periods. */ + if (0 == avail_read) { + usleep(100000); + } + } while (0 == avail_read && retry++ < 320); + + /* Reduce the required data amount to what is available, otherwise read() + will block.*/ + if (avail_read < count) { + count = avail_read; + } + } +#endif ret = read(data->fd, buf, PLAIN_WRAP_BUF_SIZE(count)); if (ret == (size_t)-1 && errno == EINTR) { diff --git a/sapi/fpm/fpm/fpm_sockets.c b/sapi/fpm/fpm/fpm_sockets.c index e056565ea41..da14d63d8c3 100644 --- a/sapi/fpm/fpm/fpm_sockets.c +++ b/sapi/fpm/fpm/fpm_sockets.c @@ -39,29 +39,6 @@ struct listening_socket_s { static struct fpm_array_s sockets_list; -static int fpm_sockets_resolve_af_inet(char *node, char *service, struct sockaddr_in *addr) /* {{{ */ -{ - struct addrinfo *res; - struct addrinfo hints; - int ret; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - ret = getaddrinfo(node, service, &hints, &res); - - if (ret != 0) { - zlog(ZLOG_ERROR, "can't resolve hostname '%s%s%s': getaddrinfo said: %s%s%s\n", - node, service ? ":" : "", service ? service : "", - gai_strerror(ret), ret == EAI_SYSTEM ? ", system error: " : "", ret == EAI_SYSTEM ? strerror(errno) : ""); - return -1; - } - - *addr = *(struct sockaddr_in *) res->ai_addr; - freeaddrinfo(res); - return 0; -} -/* }}} */ - enum { FPM_GET_USE_SOCKET = 1, FPM_STORE_SOCKET = 2, FPM_STORE_USE_SOCKET = 3 }; static void fpm_sockets_cleanup(int which, void *arg) /* {{{ */ @@ -98,14 +75,23 @@ static void fpm_sockets_cleanup(int which, void *arg) /* {{{ */ } /* }}} */ +static void *fpm_get_in_addr(struct sockaddr *sa) /* {{{ */ +{ + if (sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} +/* }}} */ + static int fpm_sockets_hash_op(int sock, struct sockaddr *sa, char *key, int type, int op) /* {{{ */ { if (key == NULL) { switch (type) { case FPM_AF_INET : { - struct sockaddr_in *sa_in = (struct sockaddr_in *) sa; - key = alloca(sizeof("xxx.xxx.xxx.xxx:ppppp")); - sprintf(key, "%u.%u.%u.%u:%u", IPQUAD(&sa_in->sin_addr), (unsigned int) ntohs(sa_in->sin_port)); + key = alloca(INET6_ADDRSTRLEN); + inet_ntop(sa->sa_family, fpm_get_in_addr(sa), key, sizeof key); break; } @@ -254,11 +240,14 @@ enum fpm_address_domain fpm_sockets_domain_from_address(char *address) /* {{{ */ static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp) /* {{{ */ { - struct sockaddr_in sa_in; + struct addrinfo hints, *servinfo, *p; char *dup_address = strdup(wp->config->listen_address); - char *port_str = strchr(dup_address, ':'); + char *port_str = strrchr(dup_address, ':'); char *addr = NULL; + int addr_len; int port = 0; + int sock; + int status; if (port_str) { /* this is host:port pair */ *port_str++ = '\0'; @@ -274,23 +263,35 @@ static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp) /* return -1; } - memset(&sa_in, 0, sizeof(sa_in)); - - if (addr) { - sa_in.sin_addr.s_addr = inet_addr(addr); - if (sa_in.sin_addr.s_addr == INADDR_NONE) { /* do resolve */ - if (0 > fpm_sockets_resolve_af_inet(addr, NULL, &sa_in)) { - return -1; - } - zlog(ZLOG_NOTICE, "address '%s' resolved as %u.%u.%u.%u", addr, IPQUAD(&sa_in.sin_addr)); + // strip brackets from address for getaddrinfo + if (addr != NULL) { + addr_len = strlen(addr); + if (addr[0] == '[' && addr[addr_len - 1] == ']') { + addr[addr_len - 1] = '\0'; + addr++; } - } else { - sa_in.sin_addr.s_addr = htonl(INADDR_ANY); } - sa_in.sin_family = AF_INET; - sa_in.sin_port = htons(port); + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if ((status = getaddrinfo(addr, port_str, &hints, &servinfo)) != 0) { + zlog(ZLOG_ERROR, "getaddrinfo: %s\n", gai_strerror(status)); + return -1; + } + free(dup_address); - return fpm_sockets_get_listening_socket(wp, (struct sockaddr *) &sa_in, sizeof(struct sockaddr_in)); + + for (p = servinfo; p != NULL; p = p->ai_next) { + if ((sock = fpm_sockets_get_listening_socket(wp, p->ai_addr, p->ai_addrlen)) != -1) { + break; + } + } + + freeaddrinfo(servinfo); + + return sock; } /* }}} */ diff --git a/sapi/fpm/fpm/fpm_sockets.h b/sapi/fpm/fpm/fpm_sockets.h index 121c016a7b8..446c78e410a 100644 --- a/sapi/fpm/fpm/fpm_sockets.h +++ b/sapi/fpm/fpm/fpm_sockets.h @@ -45,10 +45,4 @@ static inline int fd_set_blocked(int fd, int blocked) /* {{{ */ } /* }}} */ -#define IPQUAD(sin_addr) \ - (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[0], \ - (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[1], \ - (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[2], \ - (unsigned int) ((unsigned char *) &(sin_addr)->s_addr)[3] - #endif diff --git a/sapi/fpm/php-fpm.conf.in b/sapi/fpm/php-fpm.conf.in index a355df2a574..106689f0a72 100644 --- a/sapi/fpm/php-fpm.conf.in +++ b/sapi/fpm/php-fpm.conf.in @@ -152,6 +152,8 @@ group = @php_fpm_group@ ; Valid syntaxes are: ; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on ; a specific port; +; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on +; a specific port; ; 'port' - to listen on a TCP socket to all addresses on a ; specific port; ; '/path/to/unix/socket' - to listen on a unix socket. diff --git a/sapi/fpm/tests/003.phpt b/sapi/fpm/tests/003.phpt new file mode 100644 index 00000000000..389cb2401ef --- /dev/null +++ b/sapi/fpm/tests/003.phpt @@ -0,0 +1,53 @@ +--TEST-- +FPM: Test IPv6 support +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +string(%d) "[%d-%s-%d %d:%d:%d] NOTICE: fpm is running, pid %d +" +string(%d) "[%d-%s-%d %d:%d:%d] NOTICE: ready to handle connections +" +Done +--CLEAN-- +