summaryrefslogtreecommitdiff
path: root/Zend/zend.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend.c')
-rw-r--r--Zend/zend.c200
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(&params[4]);
- zval_ptr_dtor(&params[3]);
zval_ptr_dtor(&params[2]);
zval_ptr_dtor(&params[1]);
- zval_ptr_dtor(&params[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(&params[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));