diff options
author | Ondřej Surý <ondrej@sury.org> | 2013-03-22 08:32:53 +0100 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2013-03-22 08:32:53 +0100 |
commit | f21eff8954d5956842795ea5653a9a5b8d62caa3 (patch) | |
tree | adbe3c3feb67f383afe32b3974794eb1d5ec8cc8 /Zend | |
parent | 92984f18f6aee9c0f719febb9fc09a0c50262c2f (diff) | |
download | php-f21eff8954d5956842795ea5653a9a5b8d62caa3.tar.gz |
Imported Upstream version 5.5.0~beta1upstream/5.5.0_beta1
Diffstat (limited to 'Zend')
-rw-r--r-- | Zend/tests/bug55156.phpt | 3 | ||||
-rw-r--r-- | Zend/tests/bug61025.phpt | 27 | ||||
-rw-r--r-- | Zend/tests/bug62343.phpt | 13 | ||||
-rw-r--r-- | Zend/tests/bug63976.phpt | 20 | ||||
-rw-r--r-- | Zend/tests/bug64239_1.phpt | 22 | ||||
-rw-r--r-- | Zend/tests/bug64354.phpt | 24 | ||||
-rw-r--r-- | Zend/tests/bug64417.phpt | 39 | ||||
-rw-r--r-- | Zend/tests/generators/errors/serialize_unserialize_error.phpt | 2 | ||||
-rw-r--r-- | Zend/tests/generators/generator_with_nonscalar_keys.phpt | 52 | ||||
-rw-r--r-- | Zend/tests/ns_026.phpt | 2 | ||||
-rw-r--r-- | Zend/zend.h | 7 | ||||
-rw-r--r-- | Zend/zend_API.c | 73 | ||||
-rw-r--r-- | Zend/zend_API.h | 2 | ||||
-rw-r--r-- | Zend/zend_builtin_functions.c | 38 | ||||
-rw-r--r-- | Zend/zend_closures.c | 1 | ||||
-rw-r--r-- | Zend/zend_closures.h | 2 | ||||
-rw-r--r-- | Zend/zend_compile.c | 10 | ||||
-rw-r--r-- | Zend/zend_compile.h | 1 | ||||
-rw-r--r-- | Zend/zend_generators.c | 24 | ||||
-rw-r--r-- | Zend/zend_hash.c | 18 | ||||
-rw-r--r-- | Zend/zend_hash.h | 4 | ||||
-rw-r--r-- | Zend/zend_interfaces.c | 40 | ||||
-rw-r--r-- | Zend/zend_interfaces.h | 2 | ||||
-rw-r--r-- | Zend/zend_iterators.h | 7 | ||||
-rw-r--r-- | Zend/zend_types.h | 1 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 96 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 174 |
27 files changed, 451 insertions, 253 deletions
diff --git a/Zend/tests/bug55156.phpt b/Zend/tests/bug55156.phpt index 6c0ff768d..7d75ce3e9 100644 --- a/Zend/tests/bug55156.phpt +++ b/Zend/tests/bug55156.phpt @@ -1,5 +1,8 @@ --TEST-- Bug #55156 (ReflectionClass::getDocComment() returns comment even though the class has none) +--INI-- +opcache.save_comments=1 +opcache.load_comments=1 --FILE-- <?php diff --git a/Zend/tests/bug61025.phpt b/Zend/tests/bug61025.phpt new file mode 100644 index 000000000..0709c28fb --- /dev/null +++ b/Zend/tests/bug61025.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #61025 (__invoke() visibility not honored) +--FILE-- +<?php + +Interface InvokeAble { + static function __invoke(); +} + +class Bar { + private function __invoke() { + return __CLASS__; + } +} + +$b = new Bar; +echo $b(); + +echo $b->__invoke(); + +?> +--EXPECTF-- +Warning: The magic method __invoke() must have public visibility and cannot be static in %sbug61025.php on line %d + +Warning: The magic method __invoke() must have public visibility and cannot be static in %sbug61025.php on line %d +Bar +Fatal error: Call to private method Bar::__invoke() from context '' in %sbug61025.php on line %d diff --git a/Zend/tests/bug62343.phpt b/Zend/tests/bug62343.phpt new file mode 100644 index 000000000..b0208c4ac --- /dev/null +++ b/Zend/tests/bug62343.phpt @@ -0,0 +1,13 @@ +--TEST-- +Bug #62343 (Show class_alias In get_declared_classes()) +--FILE-- +<?php +class a { } +class_alias("a", "b"); +$c = get_declared_classes(); +var_dump(end($c)); +var_dump(prev($c)); +?> +--EXPECT-- +string(1) "b" +string(1) "a" diff --git a/Zend/tests/bug63976.phpt b/Zend/tests/bug63976.phpt new file mode 100644 index 000000000..0ac09d9b3 --- /dev/null +++ b/Zend/tests/bug63976.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #63976 (Parent class incorrectly using child constant in class property) +--FILE-- +<?php +if (1) { + class Foo { + const TABLE = "foo"; + public $table = self::TABLE; + } +} +if (1) { + class Bar extends Foo { + const TABLE = "bar"; + } +} +$bar = new Bar(); +var_dump($bar->table); +?> +--EXPECT-- +string(3) "foo" diff --git a/Zend/tests/bug64239_1.phpt b/Zend/tests/bug64239_1.phpt new file mode 100644 index 000000000..fe58cbd76 --- /dev/null +++ b/Zend/tests/bug64239_1.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #64239 (get_class_methods() changed behavior) +--FILE-- +<?php +class A { + public function test() { $this->backtrace(); } +} +class B { + use T2 { t2method as Bmethod; } +} +trait T2 { + public function t2method() { + } +} +var_dump(get_class_methods("B")); +--EXPECT-- +array(2) { + [0]=> + string(7) "bmethod" + [1]=> + string(8) "t2method" +} diff --git a/Zend/tests/bug64354.phpt b/Zend/tests/bug64354.phpt new file mode 100644 index 000000000..03a4b80b4 --- /dev/null +++ b/Zend/tests/bug64354.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug #64354 (Unserialize array of objects whose class can't be autoloaded fail) +--FILE-- +<?php +class B implements Serializable { + public function serialize() { + throw new Exception("serialize"); + return NULL; + } + + public function unserialize($data) { + } +} + +$data = array(new B); + +try { + serialize($data); +} catch (Exception $e) { + var_dump($e->getMessage()); +} +?> +--EXPECTF-- +string(9) "serialize" diff --git a/Zend/tests/bug64417.phpt b/Zend/tests/bug64417.phpt new file mode 100644 index 000000000..f3ef740b4 --- /dev/null +++ b/Zend/tests/bug64417.phpt @@ -0,0 +1,39 @@ +--TEST-- +Bug #64417 (BC break: ArrayAccess::&offsetGet() in a trait causes fatal error) +--FILE-- +<?php +trait aa { + private $container = array(); + public function offsetSet($offset, $value) { + if (is_null($offset)) { + $this->container[] = $value; + } else { + $this->container[$offset] = $value; + } + } + public function offsetExists($offset) { + return isset($this->container[$offset]); + } + public function offsetUnset($offset) { + unset($this->container[$offset]); + } + public function &offsetGet($offset) { + $result = null; + if (isset($this->container[$offset])) { + $result = &$this->container[$offset]; + } + return $result; + } +} + +class obj implements ArrayAccess { + use aa; +} + +$o = new obj; +$o['x'] = 1; +++$o['x']; +echo $o['x'], "\n"; +--EXPECT-- +2 + diff --git a/Zend/tests/generators/errors/serialize_unserialize_error.phpt b/Zend/tests/generators/errors/serialize_unserialize_error.phpt index a8470b0a6..aa2d4693f 100644 --- a/Zend/tests/generators/errors/serialize_unserialize_error.phpt +++ b/Zend/tests/generators/errors/serialize_unserialize_error.phpt @@ -38,8 +38,6 @@ Stack trace: #1 %s(%d): unserialize('O:9:"Generator"...') #2 {main} - -Notice: unserialize(): Error at offset 19 of 20 bytes in %s on line %d exception 'Exception' with message 'Unserialization of 'Generator' is not allowed' in %s:%d Stack trace: #0 %s(%d): unserialize('C:9:"Generator"...') diff --git a/Zend/tests/generators/generator_with_nonscalar_keys.phpt b/Zend/tests/generators/generator_with_nonscalar_keys.phpt new file mode 100644 index 000000000..5ae55a1be --- /dev/null +++ b/Zend/tests/generators/generator_with_nonscalar_keys.phpt @@ -0,0 +1,52 @@ +--TEST-- +Generators can return non-scalar keys +--FILE-- +<?php + +function gen() { + yield [1, 2, 3] => [4, 5, 6]; + yield (object) ['a' => 'b'] => (object) ['b' => 'a']; + yield 3.14 => 2.73; + yield false => true; + yield true => false; + yield null => null; +} + +foreach (gen() as $k => $v) { + var_dump($k, $v); +} + +?> +--EXPECT-- +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +array(3) { + [0]=> + int(4) + [1]=> + int(5) + [2]=> + int(6) +} +object(stdClass)#3 (1) { + ["a"]=> + string(1) "b" +} +object(stdClass)#4 (1) { + ["b"]=> + string(1) "a" +} +float(3.14) +float(2.73) +bool(false) +bool(true) +bool(true) +bool(false) +NULL +NULL diff --git a/Zend/tests/ns_026.phpt b/Zend/tests/ns_026.phpt index af2bf2ca5..45f88750e 100644 --- a/Zend/tests/ns_026.phpt +++ b/Zend/tests/ns_026.phpt @@ -1,5 +1,7 @@ --TEST-- 026: Name ambiguity (class name & namespace name) +--INI-- +opcache.optimization_level=0 --FILE-- <?php namespace Foo; diff --git a/Zend/zend.h b/Zend/zend.h index aed03d871..36554637e 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -299,7 +299,6 @@ void zend_error_noreturn(int type, const char *format, ...) __attribute__ ((nore /* * zval */ -typedef struct _zval_struct zval; typedef struct _zend_class_entry zend_class_entry; typedef struct _zend_guard { @@ -365,6 +364,10 @@ struct _zval_struct { #define Z_UNSET_ISREF(z) Z_UNSET_ISREF_P(&(z)) #define Z_SET_ISREF_TO(z, isref) Z_SET_ISREF_TO_P(&(z), isref) +#if ZEND_DEBUG +#define zend_always_inline inline +#define zend_never_inline +#else #if defined(__GNUC__) #if __GNUC__ >= 3 #define zend_always_inline inline __attribute__((always_inline)) @@ -373,7 +376,6 @@ struct _zval_struct { #define zend_always_inline inline #define zend_never_inline #endif - #elif defined(_MSC_VER) #define zend_always_inline __forceinline #define zend_never_inline @@ -381,6 +383,7 @@ struct _zval_struct { #define zend_always_inline inline #define zend_never_inline #endif +#endif /* ZEND_DEBUG */ #if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX) # define EXPECTED(condition) __builtin_expect(condition, 1) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 95c90ea75..1f400dea1 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1051,6 +1051,41 @@ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties, int destro } /* }}} */ +static int zval_update_class_constant(zval **pp, int is_static, int offset TSRMLS_DC) /* {{{ */ +{ + if ((Z_TYPE_PP(pp) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || + (Z_TYPE_PP(pp) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT_ARRAY) { + zend_class_entry **scope = EG(in_execution)?&EG(scope):&CG(active_class_entry); + + if ((*scope)->parent) { + zend_class_entry *ce = *scope; + HashPosition pos; + zend_property_info *prop_info; + + do { + for (zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos); + zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop_info, &pos) == SUCCESS; + zend_hash_move_forward_ex(&ce->properties_info, &pos)) { + if (is_static == ((prop_info->flags & ZEND_ACC_STATIC) != 0) && + offset == prop_info->offset) { + int ret; + zend_class_entry *old_scope = *scope; + *scope = prop_info->ce; + ret = zval_update_constant(pp, (void*)1 TSRMLS_CC); + *scope = old_scope; + return ret; + } + } + ce = ce->parent; + } while (ce); + + } + return zval_update_constant(pp, (void*)1 TSRMLS_CC); + } + return 0; +} +/* }}} */ + ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC) /* {{{ */ { if ((class_type->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) == 0 || (!CE_STATIC_MEMBERS(class_type) && class_type->default_static_members_count)) { @@ -1063,7 +1098,7 @@ ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC for (i = 0; i < class_type->default_properties_count; i++) { if (class_type->default_properties_table[i]) { - zval_update_constant(&class_type->default_properties_table[i], (void**)1 TSRMLS_CC); + zval_update_class_constant(&class_type->default_properties_table[i], 0, i TSRMLS_CC); } } @@ -1104,7 +1139,7 @@ ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC } for (i = 0; i < class_type->default_static_members_count; i++) { - zval_update_constant(&CE_STATIC_MEMBERS(class_type)[i], (void**)1 TSRMLS_CC); + zval_update_class_constant(&CE_STATIC_MEMBERS(class_type)[i], 1, i TSRMLS_CC); } *scope = old_scope; @@ -1502,6 +1537,40 @@ ZEND_API int add_get_index_stringl(zval *arg, ulong index, const char *str, uint } /* }}} */ +ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value) /* {{{ */ +{ + int result; + + switch (Z_TYPE_P(key)) { + case IS_STRING: + result = zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof(zval *), NULL); + break; + case IS_NULL: + result = zend_symtable_update(ht, "", 1, &value, sizeof(zval *), NULL); + break; + case IS_RESOURCE: + zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_LVAL_P(key), Z_LVAL_P(key)); + /* break missing intentionally */ + case IS_BOOL: + case IS_LONG: + result = zend_hash_index_update(ht, Z_LVAL_P(key), &value, sizeof(zval *), NULL); + break; + case IS_DOUBLE: + result = zend_hash_index_update(ht, zend_dval_to_lval(Z_DVAL_P(key)), &value, sizeof(zval *), NULL); + break; + default: + zend_error(E_WARNING, "Illegal offset type"); + result = FAILURE; + } + + if (result == SUCCESS) { + Z_ADDREF_P(value); + } + + return result; +} +/* }}} */ + ZEND_API int add_property_long_ex(zval *arg, const char *key, uint key_len, long n TSRMLS_DC) /* {{{ */ { zval *tmp; diff --git a/Zend/zend_API.h b/Zend/zend_API.h index fb642c147..c26141b18 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -426,6 +426,8 @@ ZEND_API int add_get_index_double(zval *arg, ulong idx, double d, void **dest); ZEND_API int add_get_index_string(zval *arg, ulong idx, const char *str, void **dest, int duplicate); ZEND_API int add_get_index_stringl(zval *arg, ulong idx, const char *str, uint length, void **dest, int duplicate); +ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value); + ZEND_API int add_property_long_ex(zval *arg, const char *key, uint key_len, long l TSRMLS_DC); ZEND_API int add_property_null_ex(zval *arg, const char *key, uint key_len TSRMLS_DC); ZEND_API int add_property_bool_ex(zval *arg, const char *key, uint key_len, int b TSRMLS_DC); diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 4d950a203..ee75f521f 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1025,6 +1025,13 @@ ZEND_FUNCTION(get_object_vars) } /* }}} */ +static int same_name(const char *key, const char *name, zend_uint name_len) +{ + char *lcname = zend_str_tolower_dup(name, name_len); + int ret = memcmp(lcname, key, name_len) == 0; + efree(lcname); + return ret; +} /* {{{ proto array get_class_methods(mixed class) Returns an array of method names for class or class instance. */ @@ -1072,14 +1079,26 @@ ZEND_FUNCTION(get_class_methods) uint len = strlen(mptr->common.function_name); /* Do not display old-style inherited constructors */ - if ((mptr->common.fn_flags & ZEND_ACC_CTOR) == 0 || - mptr->common.scope == ce || - zend_hash_get_current_key_ex(&ce->function_table, &key, &key_len, &num_index, 0, &pos) != HASH_KEY_IS_STRING || - zend_binary_strcasecmp(key, key_len-1, mptr->common.function_name, len) == 0) { - + if (zend_hash_get_current_key_ex(&ce->function_table, &key, &key_len, &num_index, 0, &pos) != HASH_KEY_IS_STRING) { MAKE_STD_ZVAL(method_name); ZVAL_STRINGL(method_name, mptr->common.function_name, len, 1); zend_hash_next_index_insert(return_value->value.ht, &method_name, sizeof(zval *), NULL); + } else if ((mptr->common.fn_flags & ZEND_ACC_CTOR) == 0 || + mptr->common.scope == ce || + zend_binary_strcasecmp(key, key_len-1, mptr->common.function_name, len) == 0) { + + if (mptr->type == ZEND_USER_FUNCTION && + *mptr->op_array.refcount > 1 && + (len != key_len - 1 || + !same_name(key, mptr->common.function_name, len))) { + MAKE_STD_ZVAL(method_name); + ZVAL_STRINGL(method_name, key, key_len - 1, 1); + zend_hash_next_index_insert(return_value->value.ht, &method_name, sizeof(zval *), NULL); + } else { + MAKE_STD_ZVAL(method_name); + ZVAL_STRINGL(method_name, mptr->common.function_name, len, 1); + zend_hash_next_index_insert(return_value->value.ht, &method_name, sizeof(zval *), NULL); + } } } zend_hash_move_forward_ex(&ce->function_table, &pos); @@ -1625,7 +1644,6 @@ ZEND_FUNCTION(restore_exception_handler) } /* }}} */ - static int copy_class_or_interface_name(zend_class_entry **pce TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) { zval *array = va_arg(args, zval *); @@ -1636,7 +1654,13 @@ static int copy_class_or_interface_name(zend_class_entry **pce TSRMLS_DC, int nu if ((hash_key->nKeyLength==0 || hash_key->arKey[0]!=0) && (comply_mask == (ce->ce_flags & mask))) { - add_next_index_stringl(array, ce->name, ce->name_length, 1); + if (ce->refcount > 1 && + (ce->name_length != hash_key->nKeyLength - 1 || + !same_name(hash_key->arKey, ce->name, ce->name_length))) { + add_next_index_stringl(array, hash_key->arKey, hash_key->nKeyLength - 1, 1); + } else { + add_next_index_stringl(array, ce->name, ce->name_length, 1); + } } return ZEND_HASH_APPLY_KEEP; } diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 0de928333..5faefbd22 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -291,7 +291,6 @@ static zend_object_value zend_closure_clone(zval *zobject TSRMLS_DC) /* {{{ */ } /* }}} */ - int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC) /* {{{ */ { zend_closure *closure; diff --git a/Zend/zend_closures.h b/Zend/zend_closures.h index c41cf4756..9d50641d2 100644 --- a/Zend/zend_closures.h +++ b/Zend/zend_closures.h @@ -24,8 +24,6 @@ BEGIN_EXTERN_C() -#define ZEND_INVOKE_FUNC_NAME "__invoke" - void zend_register_closure_ce(TSRMLS_D); extern ZEND_API zend_class_entry *zend_ce_closure; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index e45419d3f..6df3defb1 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1621,6 +1621,10 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static"); } + } else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) { + if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { + zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static"); + } } } else { char *class_lcname; @@ -1677,6 +1681,10 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static"); } CG(active_class_entry)->__tostring = (zend_function *) CG(active_op_array); + } else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) { + if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { + zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static"); + } } else if (!(fn_flags & ZEND_ACC_STATIC)) { CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC; } @@ -3823,7 +3831,7 @@ static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_ zend_uint other_flags = other_fn->common.scope->ce_flags; return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC) - && zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC) + && ((other_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) || zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC)) && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) == (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */ } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 8042dd54e..2295cffab 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -856,6 +856,7 @@ END_EXTERN_C() #define ZEND_CALLSTATIC_FUNC_NAME "__callstatic" #define ZEND_TOSTRING_FUNC_NAME "__tostring" #define ZEND_AUTOLOAD_FUNC_NAME "__autoload" +#define ZEND_INVOKE_FUNC_NAME "__invoke" /* The following constants may be combined in CG(compiler_options) * to change the default compiler behavior */ diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index c1dbee124..3f43552f1 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -755,31 +755,17 @@ static void zend_generator_iterator_get_data(zend_object_iterator *iterator, zva } /* }}} */ -static int zend_generator_iterator_get_key(zend_object_iterator *iterator, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */ +static void zend_generator_iterator_get_key(zend_object_iterator *iterator, zval *key TSRMLS_DC) /* {{{ */ { zend_generator *generator = (zend_generator *) iterator->data; zend_generator_ensure_initialized(generator TSRMLS_CC); - if (!generator->key) { - return HASH_KEY_NON_EXISTANT; - } - - if (Z_TYPE_P(generator->key) == IS_LONG) { - *int_key = Z_LVAL_P(generator->key); - return HASH_KEY_IS_LONG; - } - - if (Z_TYPE_P(generator->key) == IS_STRING) { - *str_key = estrndup(Z_STRVAL_P(generator->key), Z_STRLEN_P(generator->key)); - *str_key_len = Z_STRLEN_P(generator->key) + 1; - return HASH_KEY_IS_STRING; + if (generator->key) { + ZVAL_ZVAL(key, generator->key, 1, 0); + } else { + ZVAL_NULL(key); } - - /* Waiting for Etienne's patch to allow arbitrary zval keys. Until then - * error out on non-int and non-string keys. */ - zend_error_noreturn(E_ERROR, "Currently only int and string keys can be yielded"); - return HASH_KEY_NON_EXISTANT; /* Nerver reached */ } /* }}} */ diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 0609d707f..bca47b330 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1171,6 +1171,24 @@ ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, char **str_index, return HASH_KEY_NON_EXISTANT; } +ZEND_API void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos) { + Bucket *p; + + IS_CONSISTENT(ht); + + p = pos ? (*pos) : ht->pInternalPointer; + + if (!p) { + Z_TYPE_P(key) = IS_NULL; + } else if (p->nKeyLength) { + Z_TYPE_P(key) = IS_STRING; + Z_STRVAL_P(key) = IS_INTERNED(p->arKey) ? (char *) p->arKey : estrndup(p->arKey, p->nKeyLength - 1); + Z_STRLEN_P(key) = p->nKeyLength - 1; + } else { + Z_TYPE_P(key) = IS_LONG; + Z_LVAL_P(key) = p->h; + } +} ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos) { diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 88c3bfb42..a0c147f39 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -170,13 +170,13 @@ ZEND_API int zend_hash_quick_exists(const HashTable *ht, const char *arKey, uint ZEND_API int zend_hash_index_exists(const HashTable *ht, ulong h); ZEND_API ulong zend_hash_next_free_element(const HashTable *ht); - /* traversing */ #define zend_hash_has_more_elements_ex(ht, pos) \ (zend_hash_get_current_key_type_ex(ht, pos) == HASH_KEY_NON_EXISTANT ? FAILURE : SUCCESS) ZEND_API int zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos); ZEND_API int zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos); ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, char **str_index, uint *str_length, ulong *num_index, zend_bool duplicate, HashPosition *pos); +ZEND_API void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos); ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos); ZEND_API int zend_hash_get_current_data_ex(HashTable *ht, void **pData, HashPosition *pos); ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos); @@ -199,6 +199,8 @@ ZEND_API int zend_hash_set_pointer(HashTable *ht, const HashPointer *ptr); zend_hash_move_backwards_ex(ht, NULL) #define zend_hash_get_current_key(ht, str_index, num_index, duplicate) \ zend_hash_get_current_key_ex(ht, str_index, NULL, num_index, duplicate, NULL) +#define zend_hash_get_current_key_zval(ht, key) \ + zend_hash_get_current_key_zval_ex(ht, key, NULL) #define zend_hash_get_current_key_type(ht) \ zend_hash_get_current_key_type_ex(ht, NULL) #define zend_hash_get_current_data(ht, pData) \ diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index 384b66da4..16751549b 100644 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -195,7 +195,7 @@ static int zend_user_it_get_current_key_default(zend_object_iterator *_iter, cha /* }}} */ /* {{{ zend_user_it_get_current_key */ -ZEND_API int zend_user_it_get_current_key(zend_object_iterator *_iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) +ZEND_API void zend_user_it_get_current_key(zend_object_iterator *_iter, zval *key TSRMLS_DC) { zend_user_iterator *iter = (zend_user_iterator*)_iter; zval *object = (zval*)iter->it.data; @@ -203,42 +203,16 @@ ZEND_API int zend_user_it_get_current_key(zend_object_iterator *_iter, char **st zend_call_method_with_0_params(&object, iter->ce, &iter->ce->iterator_funcs.zf_key, "key", &retval); - if (!retval) { - *int_key = 0; - if (!EG(exception)) - { + if (retval) { + ZVAL_ZVAL(key, retval, 1, 1); + } else { + if (!EG(exception)) { zend_error(E_WARNING, "Nothing returned from %s::key()", iter->ce->name); } - return HASH_KEY_IS_LONG; - } - switch (Z_TYPE_P(retval)) { - default: - zend_error(E_WARNING, "Illegal type returned from %s::key()", iter->ce->name); - case IS_NULL: - *int_key = 0; - zval_ptr_dtor(&retval); - return HASH_KEY_IS_LONG; - case IS_STRING: - *str_key = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval)); - *str_key_len = Z_STRLEN_P(retval)+1; - zval_ptr_dtor(&retval); - return HASH_KEY_IS_STRING; - - case IS_DOUBLE: - *int_key = (long)Z_DVAL_P(retval); - zval_ptr_dtor(&retval); - return HASH_KEY_IS_LONG; - - case IS_RESOURCE: - case IS_BOOL: - case IS_LONG: - *int_key = (long)Z_LVAL_P(retval); - zval_ptr_dtor(&retval); - return HASH_KEY_IS_LONG; + ZVAL_LONG(key, 0); } } -/* }}} */ /* {{{ zend_user_it_move_forward */ ZEND_API void zend_user_it_move_forward(zend_object_iterator *_iter TSRMLS_DC) @@ -452,7 +426,7 @@ ZEND_API int zend_user_serialize(zval *object, unsigned char **buffer, zend_uint zval_ptr_dtor(&retval); } - if (result == FAILURE) { + if (result == FAILURE && !EG(exception)) { zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "%s::serialize() must return a string or NULL", ce->name); } return result; diff --git a/Zend/zend_interfaces.h b/Zend/zend_interfaces.h index 23547951e..ba4bc6ccb 100644 --- a/Zend/zend_interfaces.h +++ b/Zend/zend_interfaces.h @@ -51,7 +51,7 @@ ZEND_API zval* zend_call_method(zval **object_pp, zend_class_entry *obj_ce, zend ZEND_API void zend_user_it_rewind(zend_object_iterator *_iter TSRMLS_DC); ZEND_API int zend_user_it_valid(zend_object_iterator *_iter TSRMLS_DC); -ZEND_API int zend_user_it_get_current_key(zend_object_iterator *_iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC); +ZEND_API void zend_user_it_get_current_key(zend_object_iterator *_iter, zval *key TSRMLS_DC); ZEND_API void zend_user_it_get_current_data(zend_object_iterator *_iter, zval ***data TSRMLS_DC); ZEND_API void zend_user_it_move_forward(zend_object_iterator *_iter TSRMLS_DC); ZEND_API void zend_user_it_invalidate_current(zend_object_iterator *_iter TSRMLS_DC); diff --git a/Zend/zend_iterators.h b/Zend/zend_iterators.h index b484102b2..f74068a27 100644 --- a/Zend/zend_iterators.h +++ b/Zend/zend_iterators.h @@ -38,8 +38,11 @@ typedef struct _zend_object_iterator_funcs { /* fetch the item data for the current element */ void (*get_current_data)(zend_object_iterator *iter, zval ***data TSRMLS_DC); - /* fetch the key for the current element (return HASH_KEY_IS_STRING or HASH_KEY_IS_LONG) (optional, may be NULL) */ - int (*get_current_key)(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC); + /* fetch the key for the current element (optional, may be NULL). The key + * should be written into the provided zval* using the ZVAL_* macros. If + * this handler is not provided auto-incrementing integer keys will be + * used. */ + void (*get_current_key)(zend_object_iterator *iter, zval *key TSRMLS_DC); /* step forwards to next element */ void (*move_forward)(zend_object_iterator *iter TSRMLS_DC); diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 3e68add3d..9cdf31fb3 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -52,6 +52,7 @@ typedef unsigned long zend_uintptr_t; typedef unsigned int zend_object_handle; typedef struct _zend_object_handlers zend_object_handlers; +typedef struct _zval_struct zval; typedef struct _zend_object_value { zend_object_handle handle; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 578a319fd..206a2333f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2839,17 +2839,17 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) if (OP1_TYPE == IS_TMP_VAR) { FREE_OP1(); } - } else if (!IS_OP1_TMP_FREE()) { /* Not a temp var */ - if (*EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } + } else { if (OP1_TYPE == IS_CONST || - (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { + OP1_TYPE == IS_TMP_VAR || + PZVAL_IS_REF(retval_ptr)) { zval *ret; ALLOC_ZVAL(ret); INIT_PZVAL_COPY(ret, retval_ptr); - zval_copy_ctor(ret); + if (OP1_TYPE != IS_TMP_VAR) { + zval_copy_ctor(ret); + } *EG(return_value_ptr_ptr) = ret; } else if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) && retval_ptr == &EG(uninitialized_zval)) { @@ -2861,16 +2861,6 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) *EG(return_value_ptr_ptr) = retval_ptr; Z_ADDREF_P(retval_ptr); } - } else { - zval *ret; - - if (*EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } - - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - *EG(return_value_ptr_ptr) = ret; } FREE_OP1_IF_VAR(); ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); @@ -2886,10 +2876,6 @@ ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY) SAVE_OPLINE(); do { - if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } - if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) { /* Not supposed to happen, but we'll allow it */ zend_error(E_NOTICE, "Only variable references should be returned by reference"); @@ -4245,13 +4231,13 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) zend_free_op free_op1; zval *array = EX_T(opline->op1.var).fe.ptr; zval **value; - char *str_key; - uint str_key_len; - ulong int_key; HashTable *fe_ht; zend_object_iterator *iter = NULL; - int key_type = 0; - zend_bool use_key = (zend_bool)(opline->extended_value & ZEND_FE_FETCH_WITH_KEY); + + zval *key = NULL; + if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) { + key = &EX_T((opline+1)->result.var).tmp_var; + } SAVE_OPLINE(); @@ -4262,8 +4248,11 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); case ZEND_ITER_PLAIN_OBJECT: { - const char *class_name, *prop_name; zend_object *zobj = zend_objects_get_address(array TSRMLS_CC); + int key_type; + char *str_key; + zend_uint str_key_len; + zend_ulong int_key; fe_ht = Z_OBJPROP_P(array); zend_hash_set_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); @@ -4275,15 +4264,23 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); zend_hash_move_forward(fe_ht); - } while (key_type == HASH_KEY_NON_EXISTANT || - (key_type != HASH_KEY_IS_LONG && - zend_check_property_access(zobj, str_key, str_key_len-1 TSRMLS_CC) != SUCCESS)); - zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); - if (use_key && key_type != HASH_KEY_IS_LONG) { - zend_unmangle_property_name_ex(str_key, str_key_len-1, &class_name, &prop_name, &str_key_len); - str_key = estrndup(prop_name, str_key_len); - str_key_len++; + } while (key_type != HASH_KEY_IS_LONG && + zend_check_property_access(zobj, str_key, str_key_len - 1 TSRMLS_CC) != SUCCESS); + + if (key) { + if (key_type == HASH_KEY_IS_LONG) { + ZVAL_LONG(key, int_key); + } else { + const char *class_name, *prop_name; + int prop_name_len; + zend_unmangle_property_name_ex( + str_key, str_key_len - 1, &class_name, &prop_name, &prop_name_len + ); + ZVAL_STRINGL(key, prop_name, prop_name_len, 1); + } } + + zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); break; } @@ -4294,8 +4291,8 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) /* reached end of iteration */ ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); } - if (use_key) { - key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 1, NULL); + if (key) { + zend_hash_get_current_key_zval(fe_ht, key); } zend_hash_move_forward(fe_ht); zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); @@ -4330,16 +4327,15 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) /* failure in get_current_data */ ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); } - if (use_key) { + if (key) { if (iter->funcs->get_current_key) { - key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC); + iter->funcs->get_current_key(iter, key TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor(&array); HANDLE_EXCEPTION(); } } else { - key_type = HASH_KEY_IS_LONG; - int_key = iter->index; + ZVAL_LONG(key, iter->index); } } break; @@ -4355,26 +4351,6 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) AI_SET_PTR(&EX_T(opline->result.var), *value); } - if (use_key) { - zval *key = &EX_T((opline+1)->result.var).tmp_var; - - switch (key_type) { - case HASH_KEY_IS_STRING: - Z_STRVAL_P(key) = (char*)str_key; - Z_STRLEN_P(key) = str_key_len-1; - Z_TYPE_P(key) = IS_STRING; - break; - case HASH_KEY_IS_LONG: - Z_LVAL_P(key) = int_key; - Z_TYPE_P(key) = IS_LONG; - break; - default: - case HASH_KEY_NON_EXISTANT: - ZVAL_NULL(key); - break; - } - } - CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); ZEND_VM_NEXT_OPCODE(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 392569678..d65dfc41f 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2333,17 +2333,17 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG if (IS_CONST == IS_TMP_VAR) { } - } else if (!0) { /* Not a temp var */ - if (*EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } + } else { if (IS_CONST == IS_CONST || - (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { + IS_CONST == IS_TMP_VAR || + PZVAL_IS_REF(retval_ptr)) { zval *ret; ALLOC_ZVAL(ret); INIT_PZVAL_COPY(ret, retval_ptr); - zval_copy_ctor(ret); + if (IS_CONST != IS_TMP_VAR) { + zval_copy_ctor(ret); + } *EG(return_value_ptr_ptr) = ret; } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && retval_ptr == &EG(uninitialized_zval)) { @@ -2355,16 +2355,6 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG *EG(return_value_ptr_ptr) = retval_ptr; Z_ADDREF_P(retval_ptr); } - } else { - zval *ret; - - if (*EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } - - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - *EG(return_value_ptr_ptr) = ret; } return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -2380,10 +2370,6 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER(ZEND_OPCODE_HAND SAVE_OPLINE(); do { - if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } - if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) { /* Not supposed to happen, but we'll allow it */ zend_error(E_NOTICE, "Only variable references should be returned by reference"); @@ -7654,17 +7640,17 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (IS_TMP_VAR == IS_TMP_VAR) { zval_dtor(free_op1.var); } - } else if (!1) { /* Not a temp var */ - if (*EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } + } else { if (IS_TMP_VAR == IS_CONST || - (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { + IS_TMP_VAR == IS_TMP_VAR || + PZVAL_IS_REF(retval_ptr)) { zval *ret; ALLOC_ZVAL(ret); INIT_PZVAL_COPY(ret, retval_ptr); - zval_copy_ctor(ret); + if (IS_TMP_VAR != IS_TMP_VAR) { + zval_copy_ctor(ret); + } *EG(return_value_ptr_ptr) = ret; } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && retval_ptr == &EG(uninitialized_zval)) { @@ -7676,16 +7662,6 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) *EG(return_value_ptr_ptr) = retval_ptr; Z_ADDREF_P(retval_ptr); } - } else { - zval *ret; - - if (*EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } - - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - *EG(return_value_ptr_ptr) = ret; } return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -7701,10 +7677,6 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLE SAVE_OPLINE(); do { - if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } - if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) { /* Not supposed to happen, but we'll allow it */ zend_error(E_NOTICE, "Only variable references should be returned by reference"); @@ -12888,17 +12860,17 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (IS_VAR == IS_TMP_VAR) { if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; } - } else if (!0) { /* Not a temp var */ - if (*EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } + } else { if (IS_VAR == IS_CONST || - (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { + IS_VAR == IS_TMP_VAR || + PZVAL_IS_REF(retval_ptr)) { zval *ret; ALLOC_ZVAL(ret); INIT_PZVAL_COPY(ret, retval_ptr); - zval_copy_ctor(ret); + if (IS_VAR != IS_TMP_VAR) { + zval_copy_ctor(ret); + } *EG(return_value_ptr_ptr) = ret; } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && retval_ptr == &EG(uninitialized_zval)) { @@ -12910,16 +12882,6 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) *EG(return_value_ptr_ptr) = retval_ptr; Z_ADDREF_P(retval_ptr); } - } else { - zval *ret; - - if (*EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } - - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - *EG(return_value_ptr_ptr) = ret; } if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -12935,10 +12897,6 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLE SAVE_OPLINE(); do { - if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } - if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) { /* Not supposed to happen, but we'll allow it */ zend_error(E_NOTICE, "Only variable references should be returned by reference"); @@ -13588,13 +13546,13 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG zval *array = EX_T(opline->op1.var).fe.ptr; zval **value; - char *str_key; - uint str_key_len; - ulong int_key; HashTable *fe_ht; zend_object_iterator *iter = NULL; - int key_type = 0; - zend_bool use_key = (zend_bool)(opline->extended_value & ZEND_FE_FETCH_WITH_KEY); + + zval *key = NULL; + if (opline->extended_value & ZEND_FE_FETCH_WITH_KEY) { + key = &EX_T((opline+1)->result.var).tmp_var; + } SAVE_OPLINE(); @@ -13605,8 +13563,11 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); case ZEND_ITER_PLAIN_OBJECT: { - const char *class_name, *prop_name; zend_object *zobj = zend_objects_get_address(array TSRMLS_CC); + int key_type; + char *str_key; + zend_uint str_key_len; + zend_ulong int_key; fe_ht = Z_OBJPROP_P(array); zend_hash_set_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); @@ -13618,15 +13579,23 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); zend_hash_move_forward(fe_ht); - } while (key_type == HASH_KEY_NON_EXISTANT || - (key_type != HASH_KEY_IS_LONG && - zend_check_property_access(zobj, str_key, str_key_len-1 TSRMLS_CC) != SUCCESS)); - zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); - if (use_key && key_type != HASH_KEY_IS_LONG) { - zend_unmangle_property_name_ex(str_key, str_key_len-1, &class_name, &prop_name, &str_key_len); - str_key = estrndup(prop_name, str_key_len); - str_key_len++; + } while (key_type != HASH_KEY_IS_LONG && + zend_check_property_access(zobj, str_key, str_key_len - 1 TSRMLS_CC) != SUCCESS); + + if (key) { + if (key_type == HASH_KEY_IS_LONG) { + ZVAL_LONG(key, int_key); + } else { + const char *class_name, *prop_name; + int prop_name_len; + zend_unmangle_property_name_ex( + str_key, str_key_len - 1, &class_name, &prop_name, &prop_name_len + ); + ZVAL_STRINGL(key, prop_name, prop_name_len, 1); + } } + + zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); break; } @@ -13637,8 +13606,8 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG /* reached end of iteration */ ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); } - if (use_key) { - key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 1, NULL); + if (key) { + zend_hash_get_current_key_zval(fe_ht, key); } zend_hash_move_forward(fe_ht); zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); @@ -13673,16 +13642,15 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG /* failure in get_current_data */ ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); } - if (use_key) { + if (key) { if (iter->funcs->get_current_key) { - key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC); + iter->funcs->get_current_key(iter, key TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor(&array); HANDLE_EXCEPTION(); } } else { - key_type = HASH_KEY_IS_LONG; - int_key = iter->index; + ZVAL_LONG(key, iter->index); } } break; @@ -13698,26 +13666,6 @@ static int ZEND_FASTCALL ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG AI_SET_PTR(&EX_T(opline->result.var), *value); } - if (use_key) { - zval *key = &EX_T((opline+1)->result.var).tmp_var; - - switch (key_type) { - case HASH_KEY_IS_STRING: - Z_STRVAL_P(key) = (char*)str_key; - Z_STRLEN_P(key) = str_key_len-1; - Z_TYPE_P(key) = IS_STRING; - break; - case HASH_KEY_IS_LONG: - Z_LVAL_P(key) = int_key; - Z_TYPE_P(key) = IS_LONG; - break; - default: - case HASH_KEY_NON_EXISTANT: - ZVAL_NULL(key); - break; - } - } - CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); ZEND_VM_NEXT_OPCODE(); @@ -30534,17 +30482,17 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (IS_CV == IS_TMP_VAR) { } - } else if (!0) { /* Not a temp var */ - if (*EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } + } else { if (IS_CV == IS_CONST || - (PZVAL_IS_REF(retval_ptr) && Z_REFCOUNT_P(retval_ptr) > 0)) { + IS_CV == IS_TMP_VAR || + PZVAL_IS_REF(retval_ptr)) { zval *ret; ALLOC_ZVAL(ret); INIT_PZVAL_COPY(ret, retval_ptr); - zval_copy_ctor(ret); + if (IS_CV != IS_TMP_VAR) { + zval_copy_ctor(ret); + } *EG(return_value_ptr_ptr) = ret; } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && retval_ptr == &EG(uninitialized_zval)) { @@ -30556,16 +30504,6 @@ static int ZEND_FASTCALL ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) *EG(return_value_ptr_ptr) = retval_ptr; Z_ADDREF_P(retval_ptr); } - } else { - zval *ret; - - if (*EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } - - ALLOC_ZVAL(ret); - INIT_PZVAL_COPY(ret, retval_ptr); - *EG(return_value_ptr_ptr) = ret; } return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -30581,10 +30519,6 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER SAVE_OPLINE(); do { - if (EG(return_value_ptr_ptr) && *EG(return_value_ptr_ptr)) { - zval_ptr_dtor(EG(return_value_ptr_ptr)); - } - if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) { /* Not supposed to happen, but we'll allow it */ zend_error(E_NOTICE, "Only variable references should be returned by reference"); |