diff options
Diffstat (limited to 'Zend')
| -rw-r--r-- | Zend/acinclude.m4 | 2 | ||||
| -rw-r--r-- | Zend/tests/bug51394.phpt | 6 | ||||
| -rw-r--r-- | Zend/tests/bug60909_1.phpt | 24 | ||||
| -rw-r--r-- | Zend/tests/bug60909_2.phpt | 20 | ||||
| -rwxr-xr-x | Zend/tests/bug61761.phpt | 3 | ||||
| -rw-r--r-- | Zend/tests/bug61767.phpt | 34 | ||||
| -rw-r--r-- | Zend/tests/bug62358.phpt | 32 | ||||
| -rw-r--r-- | Zend/tests/bug62763.phpt | 23 | ||||
| -rw-r--r-- | Zend/tests/bug62892.phpt | 21 | ||||
| -rw-r--r-- | Zend/tests/bug62907.phpt | 22 | ||||
| -rw-r--r-- | Zend/tests/bug62956.phpt | 20 | ||||
| -rw-r--r-- | Zend/tests/bug63111.phpt | 36 | ||||
| -rw-r--r-- | Zend/tests/bug63173.phpt | 12 | ||||
| -rw-r--r-- | Zend/zend.c | 32 | ||||
| -rw-r--r-- | Zend/zend_API.c | 33 | ||||
| -rw-r--r-- | Zend/zend_API.h | 5 | ||||
| -rw-r--r-- | Zend/zend_alloc.c | 6 | ||||
| -rw-r--r-- | Zend/zend_closures.c | 2 | ||||
| -rw-r--r-- | Zend/zend_compile.c | 39 | ||||
| -rw-r--r-- | Zend/zend_compile.h | 2 | ||||
| -rw-r--r-- | Zend/zend_exceptions.c | 4 | ||||
| -rw-r--r-- | Zend/zend_object_handlers.c | 1 | ||||
| -rw-r--r-- | Zend/zend_opcode.c | 15 | ||||
| -rw-r--r-- | Zend/zend_operators.c | 3 | ||||
| -rw-r--r-- | Zend/zend_stream.c | 2 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 4 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 16 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.skl | 2 | ||||
| -rw-r--r-- | Zend/zend_vm_gen.php | 7 |
29 files changed, 385 insertions, 43 deletions
diff --git a/Zend/acinclude.m4 b/Zend/acinclude.m4 index 97d5d647b..a7358fa85 100644 --- a/Zend/acinclude.m4 +++ b/Zend/acinclude.m4 @@ -4,7 +4,7 @@ dnl This file contains local autoconf functions. AC_DEFUN([LIBZEND_BISON_CHECK],[ # we only support certain bison versions - bison_version_list="1.28 1.35 1.75 1.875 2.0 2.1 2.2 2.3 2.4 2.4.1 2.4.2 2.4.3 2.5" + bison_version_list="1.28 1.35 1.75 1.875 2.0 2.1 2.2 2.3 2.4 2.4.1 2.4.2 2.4.3 2.5 2.5.1" # for standalone build of Zend Engine test -z "$SED" && SED=sed diff --git a/Zend/tests/bug51394.phpt b/Zend/tests/bug51394.phpt index 537574c9d..406de13a9 100644 --- a/Zend/tests/bug51394.phpt +++ b/Zend/tests/bug51394.phpt @@ -13,4 +13,10 @@ function eh() set_error_handler("eh"); $a = $empty($b); --EXPECTF-- +Warning: Uncaught exception 'Exception' with message 'error!' in %sbug51394.php:4 +Stack trace: +#0 %sbug51394.php(9): eh(8, 'Undefined varia...', '%s', 9, Array) +#1 {main} + thrown in %sbug51394.php on line 4 + Fatal error: Function name must be a string in %sbug51394.php on line 9
\ No newline at end of file diff --git a/Zend/tests/bug60909_1.phpt b/Zend/tests/bug60909_1.phpt new file mode 100644 index 000000000..5150dfc02 --- /dev/null +++ b/Zend/tests/bug60909_1.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug #60909 (custom error handler throwing Exception + fatal error = no shutdown function). +--FILE-- +<?php +register_shutdown_function(function(){echo("\n\n!!!shutdown!!!\n\n");}); +set_error_handler(function($errno, $errstr, $errfile, $errline){ + echo "error($errstr)"; + throw new Exception("Foo"); +}); + +require 'notfound.php'; +--EXPECTF-- +error(require(notfound.php): failed to open stream: No such file or directory) +Warning: Uncaught exception 'Exception' with message 'Foo' in %sbug60909_1.php:5 +Stack trace: +#0 %sbug60909_1.php(8): {closure}(2, 'require(notfoun...', '%s', 8, Array) +#1 %sbug60909_1.php(8): require() +#2 {main} + thrown in %sbug60909_1.php on line 5 + +Fatal error: main(): Failed opening required 'notfound.php' (include_path='%s') in %sbug60909_1.php on line 8 + + +!!!shutdown!!! diff --git a/Zend/tests/bug60909_2.phpt b/Zend/tests/bug60909_2.phpt new file mode 100644 index 000000000..d08d9f90f --- /dev/null +++ b/Zend/tests/bug60909_2.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #60909 (custom error handler throwing Exception + fatal error = no shutdown function). +--FILE-- +<?php +register_shutdown_function(function(){echo("\n\n!!!shutdown!!!\n\n");}); +set_error_handler(function($errno, $errstr, $errfile, $errline){throw new Exception("Foo");}); + +class Bad { + public function __toString() { + throw new Exception('Oops, I cannot do this'); + } +} + +$bad = new Bad(); +echo "$bad"; +--EXPECTF-- +Fatal error: Method Bad::__toString() must not throw an exception in %sbug60909_2.php on line 0 + + +!!!shutdown!!! diff --git a/Zend/tests/bug61761.phpt b/Zend/tests/bug61761.phpt index 631f566ea..24c69ae79 100755 --- a/Zend/tests/bug61761.phpt +++ b/Zend/tests/bug61761.phpt @@ -14,5 +14,6 @@ class B extends A } ?> +==DONE== --EXPECTF-- -Strict Standards: Declaration of B::test() should be compatible with A::test($a) in %sbug61761.php on line %d +==DONE== diff --git a/Zend/tests/bug61767.phpt b/Zend/tests/bug61767.phpt new file mode 100644 index 000000000..5270872e5 --- /dev/null +++ b/Zend/tests/bug61767.phpt @@ -0,0 +1,34 @@ +--TEST-- +Bug #61767 (Shutdown functions not called in certain error situation) +--FILE-- +<?php +set_error_handler(function($code, $msg, $file = null, $line = null) { + echo "Error handler called ($msg)\n"; + throw new \ErrorException($msg, $code, 0, $file, $line); +}); + +register_shutdown_function(function(){ + echo "Shutting down\n"; + print_r(error_get_last()); +}); + +//$undefined = null; // defined variable does not cause problems +$undefined->foo(); +--EXPECTF-- +Error handler called (Undefined variable: undefined) + +Warning: Uncaught exception 'ErrorException' with message 'Undefined variable: undefined' in %sbug61767.php:13 +Stack trace: +#0 %sbug61767.php(13): {closure}(8, 'Undefined varia...', '%s', 13, Array) +#1 {main} + thrown in %sbug61767.php on line 13 + +Fatal error: Call to a member function foo() on a non-object in %sbug61767.php on line 13 +Shutting down +Array +( + [type] => 1 + [message] => Call to a member function foo() on a non-object + [file] => %sbug61767.php + [line] => 13 +) diff --git a/Zend/tests/bug62358.phpt b/Zend/tests/bug62358.phpt new file mode 100644 index 000000000..35d8b483d --- /dev/null +++ b/Zend/tests/bug62358.phpt @@ -0,0 +1,32 @@ +--TEST-- +Bug #62358 (Segfault when using traits a lot) +--SKIPIF-- +<?php +if (getenv("USE_ZEND_ALLOC") !== "0") { + die("skip Need Zend MM enabled"); +} +?> +--FILE-- +<?php + +trait T { + public function foo() { + echo "from T"; + } +} + +interface I { + public function foo(); +} + +abstract class A implements I{ + use T; +} + +class B extends A { + public function foo($var) { + } +} +?> +--EXPECTF-- +Strict Standards: Declaration of B::foo() should be compatible with A::foo() in %sbug62358.php on line %d diff --git a/Zend/tests/bug62763.phpt b/Zend/tests/bug62763.phpt new file mode 100644 index 000000000..50c27bdf3 --- /dev/null +++ b/Zend/tests/bug62763.phpt @@ -0,0 +1,23 @@ +--TEST-- +Bug #62763 (register_shutdown_function and extending class) +--FILE-- +<?php +class test1 { + public function __construct() { + register_shutdown_function(array($this, 'shutdown')); + } + public function shutdown() { + exit(__METHOD__); + } +} + +class test2 extends test1 { + public function __destruct() { + exit (__METHOD__); + } +} +new test1; +new test2; +?> +--EXPECT-- +test1::shutdowntest2::__destruct diff --git a/Zend/tests/bug62892.phpt b/Zend/tests/bug62892.phpt new file mode 100644 index 000000000..e6b0e60ff --- /dev/null +++ b/Zend/tests/bug62892.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug #62892 (ReflectionClass::getTraitAliases crashes on importing trait methods as private) +--FILE-- +<?php + +trait myTrait { + public function run() {} +} + +class myClass { + use myTrait { + MyTrait::run as private; + } +} +$class = new \ReflectionClass('myClass'); +var_dump($class->getTraitAliases()); + +?> +--EXPECTF-- +array(0) { +} diff --git a/Zend/tests/bug62907.phpt b/Zend/tests/bug62907.phpt new file mode 100644 index 000000000..53ab17cb3 --- /dev/null +++ b/Zend/tests/bug62907.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #62907 (Double free when use traits) +--FILE-- +<?php +function __autoload($name) { + if ($name == "B") { + eval ("abstract class B extends A { }"); + } else if ($name == "A") { + eval ("abstract class A { use T { T::__construct as __asconstruct; }}"); + } else if ($name == "T") { + eval ("trait T { public function __construct() { } }"); + } + return TRUE; +} + +class C extends B { + public function __construct() { + } +} +echo "okey"; +--EXPECT-- +okey diff --git a/Zend/tests/bug62956.phpt b/Zend/tests/bug62956.phpt new file mode 100644 index 000000000..c8694d5be --- /dev/null +++ b/Zend/tests/bug62956.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #62956: "incompatible" signatures for private methods should not cause E_STRICT +--FILE-- +<?php +class Base +{ + private function test() + {} +} + +class Extension extends Base +{ + private function test($arg) + {} +} + +?> +==DONE== +--EXPECT-- +==DONE== diff --git a/Zend/tests/bug63111.phpt b/Zend/tests/bug63111.phpt new file mode 100644 index 000000000..3f1906866 --- /dev/null +++ b/Zend/tests/bug63111.phpt @@ -0,0 +1,36 @@ +--TEST-- +Bug #63111 (is_callable() lies for abstract static method) +--FILE-- +<?php +abstract class Foo { + abstract static function bar(); +} +interface MyInterface { + static function bar(); +} +abstract class Bar { + static function foo() { + echo "ok\n"; + } +} +var_dump(is_callable(array("Foo", "bar"))); +var_dump(is_callable("Foo::bar")); +var_dump(is_callable(array("MyInterface", "bar"))); +var_dump(is_callable("MyInterface::bar")); +var_dump(is_callable(array("Bar", "foo"))); +var_dump(is_callable("Bar::foo")); +Bar::foo(); +Foo::bar(); +?> +--EXPECTF-- +Strict Standards: Static function Foo::bar() should not be abstract in %sbug63111.php on line 3 +bool(false) +bool(false) +bool(false) +bool(false) +bool(true) +bool(true) +ok + +Fatal error: Cannot call abstract method Foo::bar() in %sbug63111.php on line 20 + diff --git a/Zend/tests/bug63173.phpt b/Zend/tests/bug63173.phpt new file mode 100644 index 000000000..36ebf203d --- /dev/null +++ b/Zend/tests/bug63173.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug #63173: Crash when invoking invalid array callback +--FILE-- +<?php + +// the important part here are the indexes 1 and 2 +$callback = [1 => 0, 2 => 0]; +$callback(); + +?> +--EXPECTF-- +Fatal error: Array callback has to contain indices 0 and 1 in %s on line %d diff --git a/Zend/zend.c b/Zend/zend.c index 18c4f1160..9ab879a2a 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -258,6 +258,9 @@ ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_cop { TSRMLS_FETCH(); + if (zend_std_cast_object_tostring(expr, expr_copy, IS_STRING TSRMLS_CC) == SUCCESS) { + break; + } if (Z_OBJ_HANDLER_P(expr, cast_object)) { zval *val; @@ -270,12 +273,6 @@ ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_cop } zval_ptr_dtor(&val); } - /* Standard PHP objects */ - if (Z_OBJ_HT_P(expr) == &std_object_handlers || !Z_OBJ_HANDLER_P(expr, cast_object)) { - if (zend_std_cast_object_tostring(expr, expr_copy, IS_STRING TSRMLS_CC) == SUCCESS) { - break; - } - } if (!Z_OBJ_HANDLER_P(expr, cast_object) && Z_OBJ_HANDLER_P(expr, get)) { zval *z = Z_OBJ_HANDLER_P(expr, get)(expr TSRMLS_CC); @@ -1031,6 +1028,29 @@ ZEND_API void zend_error(int type, const char *format, ...) /* {{{ */ zend_stack context_stack; TSRMLS_FETCH(); + /* Report about uncaught exception in case of fatal errors */ + if (EG(exception)) { + switch (type) { + case E_CORE_ERROR: + case E_ERROR: + case E_RECOVERABLE_ERROR: + case E_PARSE: + case E_COMPILE_ERROR: + case E_USER_ERROR: + if (zend_is_executing(TSRMLS_C)) { + error_lineno = zend_get_executed_lineno(TSRMLS_C); + } + zend_exception_error(EG(exception), E_WARNING TSRMLS_CC); + EG(exception) = NULL; + if (zend_is_executing(TSRMLS_C) && EG(opline_ptr)) { + active_opline->lineno = error_lineno; + } + break; + default: + break; + } + } + /* Obtain relevant filename and lineno */ switch (type) { case E_CORE_ERROR: diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 98a33e544..45abcf61e 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2265,7 +2265,9 @@ void module_destructor(zend_module_entry *module) /* {{{ */ /* Deinitilaise module globals */ if (module->globals_size) { #ifdef ZTS - ts_free_id(*module->globals_id_ptr); + if (*module->globals_id_ptr) { + ts_free_id(*module->globals_id_ptr); + } #else if (module->globals_dtor) { module->globals_dtor(module->globals_ptr TSRMLS_CC); @@ -2531,6 +2533,9 @@ ZEND_API int zend_disable_function(char *function_name, uint function_name_lengt } /* }}} */ +#ifdef ZEND_WIN32 +#pragma optimize("", off) +#endif static zend_object_value display_disabled_class(zend_class_entry *class_type TSRMLS_DC) /* {{{ */ { zend_object_value retval; @@ -2539,6 +2544,9 @@ static zend_object_value display_disabled_class(zend_class_entry *class_type TSR zend_error(E_WARNING, "%s() has been disabled for security reasons", class_type->name); return retval; } +#ifdef ZEND_WIN32 +#pragma optimize("", on) +#endif /* }}} */ static const zend_function_entry disabled_class_new[] = { @@ -2547,16 +2555,15 @@ static const zend_function_entry disabled_class_new[] = { ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_DC) /* {{{ */ { - zend_class_entry disabled_class; + zend_class_entry **disabled_class; zend_str_tolower(class_name, class_name_length); - if (zend_hash_del(CG(class_table), class_name, class_name_length+1)==FAILURE) { + if (zend_hash_find(CG(class_table), class_name, class_name_length+1, (void **)&disabled_class)==FAILURE) { return FAILURE; } - INIT_OVERLOADED_CLASS_ENTRY_EX(disabled_class, class_name, class_name_length, disabled_class_new, NULL, NULL, NULL, NULL, NULL); - disabled_class.create_object = display_disabled_class; - disabled_class.name_length = class_name_length; - zend_register_internal_class(&disabled_class TSRMLS_CC); + INIT_CLASS_ENTRY_INIT_METHODS((**disabled_class), disabled_class_new, NULL, NULL, NULL, NULL, NULL); + (*disabled_class)->create_object = display_disabled_class; + zend_hash_clean(&((*disabled_class)->function_table)); return SUCCESS; } /* }}} */ @@ -2630,7 +2637,6 @@ static int zend_is_callable_check_class(const char *name, int name_len, zend_fca } /* }}} */ - static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fcall_info_cache *fcc, int strict_class, char **error TSRMLS_DC) /* {{{ */ { zend_class_entry *ce_org = fcc->calling_scope; @@ -2653,11 +2659,9 @@ static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fca /* Skip leading \ */ if (Z_STRVAL_P(callable)[0] == '\\') { mlen = Z_STRLEN_P(callable) - 1; - mname = Z_STRVAL_P(callable) + 1; lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + 1, mlen); } else { mlen = Z_STRLEN_P(callable); - mname = Z_STRVAL_P(callable); lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), mlen); } /* Check if function with given name exists. @@ -2809,7 +2813,14 @@ get_function_via_handler: if (retval) { if (fcc->calling_scope && !call_via_handler) { - if (!fcc->object_ptr && !(fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) { + if (!fcc->object_ptr && (fcc->function_handler->common.fn_flags & ZEND_ACC_ABSTRACT)) { + if (error) { + zend_spprintf(error, 0, "cannot call abstract method %s::%s()", fcc->calling_scope->name, fcc->function_handler->common.function_name); + retval = 0; + } else { + zend_error(E_ERROR, "Cannot call abstract method %s::%s()", fcc->calling_scope->name, fcc->function_handler->common.function_name); + } + } else if (!fcc->object_ptr && !(fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) { int severity; char *verb; if (fcc->function_handler->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { diff --git a/Zend/zend_API.h b/Zend/zend_API.h index f54db7f2e..d7fbc3c3a 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -175,6 +175,11 @@ typedef struct _zend_fcall_info_cache { class_container.name = zend_strndup(cl_name, _len); \ } \ class_container.name_length = _len; \ + INIT_CLASS_ENTRY_INIT_METHODS(class_container, functions, handle_fcall, handle_propget, handle_propset, handle_propunset, handle_propisset) \ + } + +#define INIT_CLASS_ENTRY_INIT_METHODS(class_container, functions, handle_fcall, handle_propget, handle_propset, handle_propunset, handle_propisset) \ + { \ class_container.constructor = NULL; \ class_container.destructor = NULL; \ class_container.clone = NULL; \ diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 66cd23c7c..0b0e8632c 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -664,7 +664,7 @@ static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_ static inline unsigned int zend_mm_high_bit(size_t _size) { -#if defined(__GNUC__) && defined(i386) +#if defined(__GNUC__) && (defined(__native_client__) || defined(i386)) unsigned int n; __asm__("bsrl %1,%0\n\t" : "=r" (n) : "rm" (_size)); @@ -690,7 +690,7 @@ static inline unsigned int zend_mm_high_bit(size_t _size) static inline unsigned int zend_mm_low_bit(size_t _size) { -#if defined(__GNUC__) && defined(i386) +#if defined(__GNUC__) && (defined(__native_client__) || defined(i386)) unsigned int n; __asm__("bsfl %1,%0\n\t" : "=r" (n) : "rm" (_size)); @@ -2454,7 +2454,7 @@ ZEND_API size_t _zend_mem_block_size(void *ptr TSRMLS_DC ZEND_FILE_LINE_DC ZEND_ return _zend_mm_block_size(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); } -#if defined(__GNUC__) && defined(i386) +#if defined(__GNUC__) && (defined(__native_client__) || defined(i386)) static inline size_t safe_address(size_t nmemb, size_t size, size_t offset) { diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 6f2ded375..c7527b4ff 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -78,7 +78,7 @@ ZEND_METHOD(Closure, __invoke) /* {{{ */ /* {{{ proto Closure Closure::bind(Closure $old, object $to [, mixed $scope = "static" ] ) Create a closure from another one and bind to another object and scope */ -ZEND_METHOD(Closure, bind) /* {{{ */ +ZEND_METHOD(Closure, bind) { zval *newthis, *zclosure, *scope_arg = NULL; zend_closure *closure; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 841e1b931..c39d8eaa1 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2935,6 +2935,11 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c return 1; } + /* If both methods are private do not enforce a signature */ + if ((fe->common.fn_flags & ZEND_ACC_PRIVATE) && (proto->common.fn_flags & ZEND_ACC_PRIVATE)) { + return 1; + } + /* check number of arguments */ if (proto->common.required_num_args < fe->common.required_num_args || proto->common.num_args > fe->common.num_args) { @@ -3801,9 +3806,12 @@ static int zend_traits_merge_functions_to_class(zend_function *fn TSRMLS_DC, int if (prototype) { do_inheritance_check_on_method(fn, prototype TSRMLS_CC); } + /* one more thing: make sure we properly implement an abstract method */ if (existing_fn && existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) { + prototype = fn->common.prototype; do_inheritance_check_on_method(fn, existing_fn TSRMLS_CC); + fn->common.prototype = prototype; } /* delete inherited fn if the function to be added is not abstract */ @@ -3831,9 +3839,9 @@ static int zend_traits_merge_functions_to_class(zend_function *fn TSRMLS_DC, int if (zend_hash_quick_update(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, &fn_copy, sizeof(zend_function), (void**)&fn_copy_p)==FAILURE) { zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because failure occurred during updating class method table", hash_key->arKey); } - + zend_add_magic_methods(ce, hash_key->arKey, hash_key->nKeyLength, fn_copy_p TSRMLS_CC); - + zend_function_dtor(fn); } else { zend_function_dtor(fn); @@ -3870,10 +3878,10 @@ static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args, && (zend_binary_strcasecmp(aliases[i]->trait_method->method_name, aliases[i]->trait_method->mname_len, fn->common.function_name, fnname_len) == 0)) { fn_copy = *fn; function_add_ref(&fn_copy); - /* this function_name is never destroyed, because its refcount - greater than 1 and classes are always destoyed before the - traits they use */ + /* this function_name is never destroyed, because ZEND_ACC_ALIAS + flag is set */ fn_copy.common.function_name = aliases[i]->alias; + fn_copy.common.fn_flags |= ZEND_ACC_ALIAS; /* if it is 0, no modifieres has been changed */ if (aliases[i]->modifiers) { @@ -3906,6 +3914,7 @@ static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args, /* is not in hashtable, thus, function is not to be excluded */ fn_copy = *fn; function_add_ref(&fn_copy); + fn_copy.common.fn_flags |= ZEND_ACC_ALIAS; /* apply aliases which are not qualified by a class name, or which have not * alias name, just setting visibility */ @@ -4025,9 +4034,9 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /* /** And, ensure that the referenced method is resolvable, too. */ lcname = zend_str_tolower_dup(cur_method_ref->method_name, - cur_method_ref->mname_len); + cur_method_ref->mname_len); method_exists = zend_hash_exists(&cur_method_ref->ce->function_table, - lcname, cur_method_ref->mname_len + 1); + lcname, cur_method_ref->mname_len + 1); efree(lcname); if (!method_exists) { @@ -5009,11 +5018,11 @@ void zend_do_begin_class_declaration(const znode *class_token, znode *class_name opline->op2_type = IS_CONST; if (doing_inheritance) { - /* Make sure a trait does not try to extend a class */ - if ((new_class_entry->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { - zend_error(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. Traits can only be composed from other traits with the 'use' keyword. Error", new_class_entry->name); - } - + /* Make sure a trait does not try to extend a class */ + if ((new_class_entry->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { + zend_error(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. Traits can only be composed from other traits with the 'use' keyword. Error", new_class_entry->name); + } + opline->extended_value = parent_class_name->u.op.var; opline->opcode = ZEND_DECLARE_INHERITED_CLASS; } else { @@ -6958,9 +6967,9 @@ void zend_do_use(znode *ns_name, znode *new_name, int is_global TSRMLS_DC) /* {{ lcname = zend_str_tolower_dup(Z_STRVAL_P(name), Z_STRLEN_P(name)); if (((Z_STRLEN_P(name) == sizeof("self")-1) && - !memcmp(lcname, "self", sizeof("self")-1)) || - ((Z_STRLEN_P(name) == sizeof("parent")-1) && - !memcmp(lcname, "parent", sizeof("parent")-1))) { + !memcmp(lcname, "self", sizeof("self")-1)) || + ((Z_STRLEN_P(name) == sizeof("parent")-1) && + !memcmp(lcname, "parent", sizeof("parent")-1))) { zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' is a special class name", Z_STRVAL_P(ns), Z_STRVAL_P(name), Z_STRVAL_P(name)); } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index f16412278..79ace0c3c 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -207,6 +207,8 @@ typedef struct _zend_try_catch_element { #define ZEND_ACC_RETURN_REFERENCE 0x4000000 #define ZEND_ACC_DONE_PASS_TWO 0x8000000 +#define ZEND_ACC_ALIAS 0x10000000 + char *zend_visibility_string(zend_uint fn_flags); diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 7bb7792a4..787e66bfe 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -29,8 +29,8 @@ #include "zend_vm.h" #include "zend_dtrace.h" -zend_class_entry *default_exception_ce; -zend_class_entry *error_exception_ce; +static zend_class_entry *default_exception_ce; +static zend_class_entry *error_exception_ce; static zend_object_handlers default_exception_handlers; ZEND_API void (*zend_throw_exception_hook)(zval *ex TSRMLS_DC); diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 60095f706..d82493aea 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1490,6 +1490,7 @@ ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int ty if (retval) { zval_ptr_dtor(&retval); } + EG(exception) = NULL; zend_error_noreturn(E_ERROR, "Method %s::__toString() must not throw an exception", ce->name); return FAILURE; } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 19fd71e76..4c6a784a8 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -267,6 +267,15 @@ void _destroy_zend_class_traits_info(zend_class_entry *ce) } } +static int zend_clear_trait_method_name(zend_op_array *op_array TSRMLS_DC) +{ + if (op_array->function_name && (op_array->fn_flags & ZEND_ACC_ALIAS) == 0) { + efree(op_array->function_name); + op_array->function_name = NULL; + } + return 0; +} + ZEND_API void destroy_zend_class(zend_class_entry **pce) { zend_class_entry *ce = *pce; @@ -298,6 +307,10 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce) } zend_hash_destroy(&ce->properties_info); str_efree(ce->name); + if ((ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { + TSRMLS_FETCH(); + zend_hash_apply(&ce->function_table, (apply_func_t)zend_clear_trait_method_name TSRMLS_CC); + } zend_hash_destroy(&ce->function_table); zend_hash_destroy(&ce->constants_table); if (ce->num_interfaces > 0 && ce->interfaces) { @@ -387,7 +400,7 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC) } efree(op_array->opcodes); - if (op_array->function_name) { + if (op_array->function_name && (op_array->fn_flags & ZEND_ACC_ALIAS) == 0) { efree((char*)op_array->function_name); } if (op_array->doc_comment) { diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index f9686251f..9b01e5fbc 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -1519,6 +1519,9 @@ ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* { ret = compare_function(result, op1, op_free TSRMLS_CC); zend_free_obj_get_result(op_free TSRMLS_CC); return ret; + } else if (Z_TYPE_P(op1) == IS_OBJECT) { + ZVAL_LONG(result, 1); + return SUCCESS; } } if (!converted) { diff --git a/Zend/zend_stream.c b/Zend/zend_stream.c index 27df9537a..30cc3a5ba 100644 --- a/Zend/zend_stream.c +++ b/Zend/zend_stream.c @@ -79,7 +79,7 @@ static size_t zend_stream_stdio_fsizer(void *handle TSRMLS_DC) /* {{{ */ static void zend_stream_unmap(zend_stream *stream TSRMLS_DC) { /* {{{ */ #if HAVE_MMAP if (stream->mmap.map) { - munmap(stream->mmap.map, stream->mmap.len); + munmap(stream->mmap.map, stream->mmap.len + ZEND_MMAP_AHEAD); } else #endif if (stream->mmap.buf) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f5567ea99..9d475a688 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2412,6 +2412,10 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) zend_hash_index_find(Z_ARRVAL_P(function_name), 0, (void **) &obj); zend_hash_index_find(Z_ARRVAL_P(function_name), 1, (void **) &method); + if (!obj || !method) { + zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1"); + } + if (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT) { zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object"); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 78f3d8496..4abe6503c 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1256,6 +1256,10 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE zend_hash_index_find(Z_ARRVAL_P(function_name), 0, (void **) &obj); zend_hash_index_find(Z_ARRVAL_P(function_name), 1, (void **) &method); + if (!obj || !method) { + zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1"); + } + if (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT) { zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object"); } @@ -1558,6 +1562,10 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H zend_hash_index_find(Z_ARRVAL_P(function_name), 0, (void **) &obj); zend_hash_index_find(Z_ARRVAL_P(function_name), 1, (void **) &method); + if (!obj || !method) { + zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1"); + } + if (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT) { zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object"); } @@ -1722,6 +1730,10 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H zend_hash_index_find(Z_ARRVAL_P(function_name), 0, (void **) &obj); zend_hash_index_find(Z_ARRVAL_P(function_name), 1, (void **) &method); + if (!obj || !method) { + zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1"); + } + if (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT) { zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object"); } @@ -1919,6 +1931,10 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA zend_hash_index_find(Z_ARRVAL_P(function_name), 0, (void **) &obj); zend_hash_index_find(Z_ARRVAL_P(function_name), 1, (void **) &method); + if (!obj || !method) { + zend_error_noreturn(E_ERROR, "Array callback has to contain indices 0 and 1"); + } + if (Z_TYPE_PP(obj) != IS_STRING && Z_TYPE_PP(obj) != IS_OBJECT) { zend_error_noreturn(E_ERROR, "First array member is not a valid class name or object"); } diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 426f68979..6d1b2e70e 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -5,8 +5,8 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC) DCL_OPLINE zend_execute_data *execute_data; zend_bool nested = 0; - zend_bool original_in_execution = EG(in_execution); {%HELPER_VARS%} + {%EXECUTION_STATUS%} {%INTERNAL_LABELS%} diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 3163000e4..fde1baf90 100644 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -927,6 +927,13 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name, skip_blanks($f, $m[1], $m[3]."\n"); } break; + case "EXECUTION_STATUS": + if ($kind != ZEND_VM_KIND_GOTO) { + out($f, $m[1] . "zend_bool original_in_execution = EG(in_execution);\n"); + } else { + out($f, $m[1] . "zend_bool original_in_execution = op_array? EG(in_execution) : 0;\n"); + } + break; case "INTERNAL_LABELS": if ($kind == ZEND_VM_KIND_GOTO) { // Emit array of labels of opcode handlers and code for |
