summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
Diffstat (limited to 'Zend')
-rw-r--r--Zend/acinclude.m42
-rw-r--r--Zend/tests/bug51394.phpt6
-rw-r--r--Zend/tests/bug60909_1.phpt24
-rw-r--r--Zend/tests/bug60909_2.phpt20
-rwxr-xr-xZend/tests/bug61761.phpt3
-rw-r--r--Zend/tests/bug61767.phpt34
-rw-r--r--Zend/tests/bug62358.phpt32
-rw-r--r--Zend/tests/bug62763.phpt23
-rw-r--r--Zend/tests/bug62892.phpt21
-rw-r--r--Zend/tests/bug62907.phpt22
-rw-r--r--Zend/tests/bug62956.phpt20
-rw-r--r--Zend/tests/bug63111.phpt36
-rw-r--r--Zend/tests/bug63173.phpt12
-rw-r--r--Zend/zend.c32
-rw-r--r--Zend/zend_API.c33
-rw-r--r--Zend/zend_API.h5
-rw-r--r--Zend/zend_alloc.c6
-rw-r--r--Zend/zend_closures.c2
-rw-r--r--Zend/zend_compile.c39
-rw-r--r--Zend/zend_compile.h2
-rw-r--r--Zend/zend_exceptions.c4
-rw-r--r--Zend/zend_object_handlers.c1
-rw-r--r--Zend/zend_opcode.c15
-rw-r--r--Zend/zend_operators.c3
-rw-r--r--Zend/zend_stream.c2
-rw-r--r--Zend/zend_vm_def.h4
-rw-r--r--Zend/zend_vm_execute.h16
-rw-r--r--Zend/zend_vm_execute.skl2
-rw-r--r--Zend/zend_vm_gen.php7
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