diff options
Diffstat (limited to 'Zend/zend.c')
-rw-r--r-- | Zend/zend.c | 200 |
1 files changed, 135 insertions, 65 deletions
diff --git a/Zend/zend.c b/Zend/zend.c index 23cf94fcb2..18ec232262 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -12,13 +12,11 @@ | obtain it through the world-wide-web, please send a note to | | license@zend.com so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Authors: Andi Gutmans <andi@zend.com> | - | Zeev Suraski <zeev@zend.com> | + | Authors: Andi Gutmans <andi@php.net> | + | Zeev Suraski <zeev@php.net> | +----------------------------------------------------------------------+ */ -/* $Id$ */ - #include "zend.h" #include "zend_extensions.h" #include "zend_modules.h" @@ -33,6 +31,7 @@ #include "zend_virtual_cwd.h" #include "zend_smart_str.h" #include "zend_smart_string.h" +#include "zend_cpuinfo.h" #ifdef ZTS ZEND_API int compiler_globals_id; @@ -75,13 +74,18 @@ ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint3 void (*zend_printf_to_smart_string)(smart_string *buf, const char *format, va_list ap); void (*zend_printf_to_smart_str)(smart_str *buf, const char *format, va_list ap); ZEND_API char *(*zend_getenv)(char *name, size_t name_len); -ZEND_API zend_string *(*zend_resolve_path)(const char *filename, int filename_len); +ZEND_API zend_string *(*zend_resolve_path)(const char *filename, size_t filename_len); +ZEND_API int (*zend_post_startup_cb)(void) = NULL; void (*zend_on_timeout)(int seconds); static void (*zend_message_dispatcher_p)(zend_long message, const void *data); static zval *(*zend_get_configuration_directive_p)(zend_string *name); +#if ZEND_RC_DEBUG +ZEND_API zend_bool zend_rc_debug = 0; +#endif + static ZEND_INI_MH(OnUpdateErrorReporting) /* {{{ */ { if (!new_value) { @@ -95,16 +99,26 @@ static ZEND_INI_MH(OnUpdateErrorReporting) /* {{{ */ static ZEND_INI_MH(OnUpdateGCEnabled) /* {{{ */ { - OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); + zend_bool val; - if (GC_G(gc_enabled)) { - gc_init(); - } + val = zend_ini_parse_bool(new_value); + gc_enable(val); return SUCCESS; } /* }}} */ +static ZEND_INI_DISP(zend_gc_enabled_displayer_cb) /* {{{ */ +{ + if (gc_enabled()) { + ZEND_PUTS("On"); + } else { + ZEND_PUTS("Off"); + } +} +/* }}} */ + + static ZEND_INI_MH(OnUpdateScriptEncoding) /* {{{ */ { if (!CG(multibyte)) { @@ -130,7 +144,7 @@ static ZEND_INI_MH(OnUpdateAssertions) /* {{{ */ p = (zend_long *) (base+(size_t) mh_arg1); - val = zend_atol(ZSTR_VAL(new_value), (int)ZSTR_LEN(new_value)); + val = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); if (stage != ZEND_INI_STAGE_STARTUP && stage != ZEND_INI_STAGE_SHUTDOWN && @@ -148,7 +162,7 @@ static ZEND_INI_MH(OnUpdateAssertions) /* {{{ */ ZEND_INI_BEGIN() ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) STD_ZEND_INI_ENTRY("zend.assertions", "1", ZEND_INI_ALL, OnUpdateAssertions, assertions, zend_executor_globals, executor_globals) - STD_ZEND_INI_BOOLEAN("zend.enable_gc", "1", ZEND_INI_ALL, OnUpdateGCEnabled, gc_enabled, zend_gc_globals, gc_globals) + ZEND_INI_ENTRY3_EX("zend.enable_gc", "1", ZEND_INI_ALL, OnUpdateGCEnabled, NULL, NULL, NULL, zend_gc_enabled_displayer_cb) STD_ZEND_INI_BOOLEAN("zend.multibyte", "0", ZEND_INI_PERDIR, OnUpdateBool, multibyte, zend_compiler_globals, compiler_globals) ZEND_INI_ENTRY("zend.script_encoding", NULL, ZEND_INI_ALL, OnUpdateScriptEncoding) STD_ZEND_INI_BOOLEAN("zend.detect_unicode", "1", ZEND_INI_ALL, OnUpdateBool, detect_unicode, zend_compiler_globals, compiler_globals) @@ -197,6 +211,18 @@ ZEND_API size_t zend_spprintf(char **message, size_t max_len, const char *format } /* }}} */ +ZEND_API size_t zend_spprintf_unchecked(char **message, size_t max_len, const char *format, ...) /* {{{ */ +{ + va_list arg; + size_t len; + + va_start(arg, format); + len = zend_vspprintf(message, max_len, format, arg); + va_end(arg); + return len; +} +/* }}} */ + ZEND_API zend_string *zend_vstrpprintf(size_t max_len, const char *format, va_list ap) /* {{{ */ { smart_str buf = {0}; @@ -228,6 +254,18 @@ ZEND_API zend_string *zend_strpprintf(size_t max_len, const char *format, ...) / } /* }}} */ +ZEND_API zend_string *zend_strpprintf_unchecked(size_t max_len, const char *format, ...) /* {{{ */ +{ + va_list arg; + zend_string *str; + + va_start(arg, format); + str = zend_vstrpprintf(max_len, format, arg); + va_end(arg); + return str; +} +/* }}} */ + static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent); static void print_hash(smart_str *buf, HashTable *ht, int indent, zend_bool is_object) /* {{{ */ @@ -309,7 +347,7 @@ ZEND_API int zend_make_printable_zval(zval *expr, zval *expr_copy) /* {{{ */ if (Z_TYPE_P(expr) == IS_STRING) { return 0; } else { - ZVAL_STR(expr_copy, _zval_get_string_func(expr)); + ZVAL_STR(expr_copy, zval_get_string_func(expr)); return 1; } } @@ -317,14 +355,15 @@ ZEND_API int zend_make_printable_zval(zval *expr, zval *expr_copy) /* {{{ */ ZEND_API size_t zend_print_zval(zval *expr, int indent) /* {{{ */ { - zend_string *str = zval_get_string(expr); + zend_string *tmp_str; + zend_string *str = zval_get_tmp_string(expr, &tmp_str); size_t len = ZSTR_LEN(str); if (len != 0) { zend_write(ZSTR_VAL(str), len); } - zend_string_release(str); + zend_tmp_string_release(tmp_str); return len; } /* }}} */ @@ -334,16 +373,17 @@ ZEND_API void zend_print_flat_zval_r(zval *expr) /* {{{ */ switch (Z_TYPE_P(expr)) { case IS_ARRAY: ZEND_PUTS("Array ("); - if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr)) && - ++Z_ARRVAL_P(expr)->u.v.nApplyCount>1) { - ZEND_PUTS(" *RECURSION*"); - Z_ARRVAL_P(expr)->u.v.nApplyCount--; - return; + if (!(GC_FLAGS(Z_ARRVAL_P(expr)) & GC_IMMUTABLE)) { + if (GC_IS_RECURSIVE(Z_ARRVAL_P(expr))) { + ZEND_PUTS(" *RECURSION*"); + return; + } + GC_PROTECT_RECURSION(Z_ARRVAL_P(expr)); } print_flat_hash(Z_ARRVAL_P(expr)); ZEND_PUTS(")"); - if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr))) { - Z_ARRVAL_P(expr)->u.v.nApplyCount--; + if (!(GC_FLAGS(Z_ARRVAL_P(expr)) & GC_IMMUTABLE)) { + GC_UNPROTECT_RECURSION(Z_ARRVAL_P(expr)); } break; case IS_OBJECT: @@ -351,9 +391,9 @@ ZEND_API void zend_print_flat_zval_r(zval *expr) /* {{{ */ HashTable *properties = NULL; zend_string *class_name = Z_OBJ_HANDLER_P(expr, get_class_name)(Z_OBJ_P(expr)); zend_printf("%s Object (", ZSTR_VAL(class_name)); - zend_string_release(class_name); + zend_string_release_ex(class_name, 0); - if (Z_OBJ_APPLY_COUNT_P(expr) > 0) { + if (GC_IS_RECURSIVE(Z_OBJ_P(expr))) { ZEND_PUTS(" *RECURSION*"); return; } @@ -362,9 +402,9 @@ ZEND_API void zend_print_flat_zval_r(zval *expr) /* {{{ */ properties = Z_OBJPROP_P(expr); } if (properties) { - Z_OBJ_INC_APPLY_COUNT_P(expr); + GC_PROTECT_RECURSION(Z_OBJ_P(expr)); print_flat_hash(properties); - Z_OBJ_DEC_APPLY_COUNT_P(expr); + GC_UNPROTECT_RECURSION(Z_OBJ_P(expr)); } ZEND_PUTS(")"); break; @@ -373,7 +413,7 @@ ZEND_API void zend_print_flat_zval_r(zval *expr) /* {{{ */ zend_print_flat_zval_r(Z_REFVAL_P(expr)); break; default: - zend_print_variable(expr); + zend_print_zval(expr, 0); break; } } @@ -384,15 +424,16 @@ static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /* switch (Z_TYPE_P(expr)) { case IS_ARRAY: smart_str_appends(buf, "Array\n"); - if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr)) && - ++Z_ARRVAL_P(expr)->u.v.nApplyCount>1) { - smart_str_appends(buf, " *RECURSION*"); - Z_ARRVAL_P(expr)->u.v.nApplyCount--; - return; + if (!(GC_FLAGS(Z_ARRVAL_P(expr)) & GC_IMMUTABLE)) { + if (GC_IS_RECURSIVE(Z_ARRVAL_P(expr))) { + smart_str_appends(buf, " *RECURSION*"); + return; + } + GC_PROTECT_RECURSION(Z_ARRVAL_P(expr)); } print_hash(buf, Z_ARRVAL_P(expr), indent, 0); - if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr))) { - Z_ARRVAL_P(expr)->u.v.nApplyCount--; + if (!(GC_FLAGS(Z_ARRVAL_P(expr)) & GC_IMMUTABLE)) { + GC_UNPROTECT_RECURSION(Z_ARRVAL_P(expr)); } break; case IS_OBJECT: @@ -402,10 +443,10 @@ static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /* zend_string *class_name = Z_OBJ_HANDLER_P(expr, get_class_name)(Z_OBJ_P(expr)); smart_str_appends(buf, ZSTR_VAL(class_name)); - zend_string_release(class_name); + zend_string_release_ex(class_name, 0); smart_str_appends(buf, " Object\n"); - if (Z_OBJ_APPLY_COUNT_P(expr) > 0) { + if (GC_IS_RECURSIVE(Z_OBJ_P(expr))) { smart_str_appends(buf, " *RECURSION*"); return; } @@ -413,9 +454,9 @@ static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /* break; } - Z_OBJ_INC_APPLY_COUNT_P(expr); + GC_PROTECT_RECURSION(Z_OBJ_P(expr)); print_hash(buf, properties, indent, 1); - Z_OBJ_DEC_APPLY_COUNT_P(expr); + GC_UNPROTECT_RECURSION(Z_OBJ_P(expr)); if (is_temp) { zend_hash_destroy(properties); @@ -429,11 +470,14 @@ static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /* case IS_REFERENCE: zend_print_zval_r_to_buf(buf, Z_REFVAL_P(expr), indent); break; + case IS_STRING: + smart_str_append(buf, Z_STR_P(expr)); + break; default: { - zend_string *str = zval_get_string(expr); + zend_string *str = zval_get_string_func(expr); smart_str_append(buf, str); - zend_string_release(str); + zend_string_release_ex(str, 0); } break; } @@ -453,7 +497,7 @@ ZEND_API void zend_print_zval_r(zval *expr, int indent) /* {{{ */ { zend_string *str = zend_print_zval_r_to_str(expr, indent); zend_write(ZSTR_VAL(str), ZSTR_LEN(str)); - zend_string_release(str); + zend_string_release_ex(str, 0); } /* }}} */ @@ -498,19 +542,10 @@ static void zend_init_exception_op(void) /* {{{ */ { memset(EG(exception_op), 0, sizeof(EG(exception_op))); EG(exception_op)[0].opcode = ZEND_HANDLE_EXCEPTION; - EG(exception_op)[0].op1_type = IS_UNUSED; - EG(exception_op)[0].op2_type = IS_UNUSED; - EG(exception_op)[0].result_type = IS_UNUSED; ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)); EG(exception_op)[1].opcode = ZEND_HANDLE_EXCEPTION; - EG(exception_op)[1].op1_type = IS_UNUSED; - EG(exception_op)[1].op2_type = IS_UNUSED; - EG(exception_op)[1].result_type = IS_UNUSED; ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)+1); EG(exception_op)[2].opcode = ZEND_HANDLE_EXCEPTION; - EG(exception_op)[2].op1_type = IS_UNUSED; - EG(exception_op)[2].op2_type = IS_UNUSED; - EG(exception_op)[2].result_type = IS_UNUSED; ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)+2); } /* }}} */ @@ -519,9 +554,6 @@ static void zend_init_call_trampoline_op(void) /* {{{ */ { memset(&EG(call_trampoline_op), 0, sizeof(EG(call_trampoline_op))); EG(call_trampoline_op).opcode = ZEND_CALL_TRAMPOLINE; - EG(call_trampoline_op).op1_type = IS_UNUSED; - EG(call_trampoline_op).op2_type = IS_UNUSED; - EG(call_trampoline_op).result_type = IS_UNUSED; ZEND_VM_SET_OPCODE_HANDLER(&EG(call_trampoline_op)); } /* }}} */ @@ -536,9 +568,34 @@ static void auto_global_dtor(zval *zv) /* {{{ */ static void function_copy_ctor(zval *zv) /* {{{ */ { zend_function *old_func = Z_FUNC_P(zv); - Z_FUNC_P(zv) = pemalloc(sizeof(zend_internal_function), 1); - memcpy(Z_FUNC_P(zv), old_func, sizeof(zend_internal_function)); - function_add_ref(Z_FUNC_P(zv)); + zend_function *func = pemalloc(sizeof(zend_internal_function), 1); + + Z_FUNC_P(zv) = func; + memcpy(func, old_func, sizeof(zend_internal_function)); + function_add_ref(func); + if ((old_func->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) + && old_func->common.arg_info) { + uint32_t i; + uint32_t num_args = old_func->common.num_args + 1; + zend_arg_info *arg_info = old_func->common.arg_info - 1; + zend_arg_info *new_arg_info; + + if (old_func->common.fn_flags & ZEND_ACC_VARIADIC) { + num_args++; + } + new_arg_info = pemalloc(sizeof(zend_arg_info) * num_args, 1); + memcpy(new_arg_info, arg_info, sizeof(zend_arg_info) * num_args); + for (i = 0 ; i < num_args; i++) { + if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) { + zend_string *name = zend_string_dup(ZEND_TYPE_NAME(arg_info[i].type), 1); + + new_arg_info[i].type = + ZEND_TYPE_ENCODE_CLASS( + name, ZEND_TYPE_ALLOW_NULL(arg_info[i].type)); + } + } + func->common.arg_info = new_arg_info + 1; + } } /* }}} */ @@ -681,8 +738,6 @@ static void php_scanner_globals_ctor(zend_php_scanner_globals *scanner_globals_p } /* }}} */ -void zend_init_opcodes_handlers(void); - static void module_destructor_zval(zval *zv) /* {{{ */ { zend_module_entry *module = (zend_module_entry*)Z_PTR_P(zv); @@ -696,8 +751,9 @@ static zend_bool php_auto_globals_create_globals(zend_string *name) /* {{{ */ { zval globals; + /* IS_ARRAY, but with ref-counter 1 and not IS_TYPE_REFCOUNTED */ ZVAL_ARR(&globals, &EG(symbol_table)); - Z_TYPE_INFO_P(&globals) = IS_ARRAY; + Z_TYPE_FLAGS_P(&globals) = 0; ZVAL_NEW_REF(&globals, &globals); zend_hash_update(&EG(symbol_table), name, &globals); return 0; @@ -717,6 +773,8 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions) / extern zend_php_scanner_globals language_scanner_globals; #endif + zend_cpu_startup(); + #ifdef ZEND_WIN32 php_win32_cp_set_by_id(65001); #endif @@ -780,7 +838,7 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions) / /* Set up the default garbage collection implementation. */ gc_collect_cycles = zend_gc_collect_cycles; - zend_init_opcodes_handlers(); + zend_vm_init(); /* set up version */ zend_version_info = strdup(ZEND_CORE_VERSION_INFO); @@ -831,7 +889,7 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions) / zend_interned_strings_init(); zend_startup_builtin_functions(); zend_register_standard_constants(); - zend_register_auto_global(zend_string_init("GLOBALS", sizeof("GLOBALS") - 1, 1), 1, php_auto_globals_create_globals); + zend_register_auto_global(zend_string_init_interned("GLOBALS", sizeof("GLOBALS") - 1, 1), 1, php_auto_globals_create_globals); #ifndef ZTS zend_init_rsrc_plist(); @@ -866,7 +924,7 @@ void zend_register_standard_ini_entries(void) /* {{{ */ /* Unlink the global (r/o) copies of the class, function and constant tables, * and use a fresh r/w copy for the startup thread */ -void zend_post_startup(void) /* {{{ */ +int zend_post_startup(void) /* {{{ */ { #ifdef ZTS zend_encoding **script_encoding_list; @@ -896,11 +954,24 @@ void zend_post_startup(void) /* {{{ */ global_persistent_list = &EG(persistent_list); zend_copy_ini_directives(); #endif + + if (zend_post_startup_cb) { + int (*cb)(void) = zend_post_startup_cb; + + zend_post_startup_cb = NULL; + if (cb() != SUCCESS) { + return FAILURE; + } + } + + return SUCCESS; } /* }}} */ void zend_shutdown(void) /* {{{ */ { + zend_vm_dtor(); + zend_destroy_rsrc_list(&EG(persistent_list)); zend_destroy_modules(); @@ -962,6 +1033,7 @@ ZEND_API ZEND_COLD void _zend_bailout(const char *filename, uint32_t lineno) /* zend_output_debug_string(1, "%s(%d) : Bailed out without a bailout address!", filename, lineno); exit(-1); } + gc_protect(1); CG(unclean_shutdown) = 1; CG(active_class_entry) = NULL; CG(in_compilation) = 0; @@ -1271,7 +1343,7 @@ static ZEND_COLD void zend_error_va_list(int type, const char *format, va_list a orig_fake_scope = EG(fake_scope); EG(fake_scope) = NULL; - if (call_user_function_ex(CG(function_table), NULL, &orig_user_error_handler, &retval, 5, params, 1, NULL) == SUCCESS) { + if (call_user_function(CG(function_table), NULL, &orig_user_error_handler, &retval, 5, params) == SUCCESS) { if (Z_TYPE(retval) != IS_UNDEF) { if (Z_TYPE(retval) == IS_FALSE) { zend_error_cb(type, error_filename, error_lineno, format, args); @@ -1293,10 +1365,8 @@ static ZEND_COLD void zend_error_va_list(int type, const char *format, va_list a } zval_ptr_dtor(¶ms[4]); - zval_ptr_dtor(¶ms[3]); zval_ptr_dtor(¶ms[2]); zval_ptr_dtor(¶ms[1]); - zval_ptr_dtor(¶ms[0]); if (Z_TYPE(EG(user_error_handler)) == IS_UNDEF) { ZVAL_COPY_VALUE(&EG(user_error_handler), &orig_user_error_handler); @@ -1461,7 +1531,7 @@ ZEND_API void zend_try_exception_handler() /* {{{ */ ZVAL_OBJ(¶ms[0], old_exception); ZVAL_COPY_VALUE(&orig_user_exception_handler, &EG(user_exception_handler)); - if (call_user_function_ex(CG(function_table), NULL, &orig_user_exception_handler, &retval2, 1, params, 1, NULL) == SUCCESS) { + if (call_user_function(CG(function_table), NULL, &orig_user_exception_handler, &retval2, 1, params) == SUCCESS) { zval_ptr_dtor(&retval2); if (EG(exception)) { OBJ_RELEASE(EG(exception)); |