diff options
author | Joe Watkins <krakjoe@php.net> | 2018-05-10 14:58:10 +0200 |
---|---|---|
committer | Joe Watkins <krakjoe@php.net> | 2019-03-12 00:35:35 +0100 |
commit | 6529d7acd9912a609924633a43e6562799566225 (patch) | |
tree | 09302816c8bba39c318c52ba5ef19999e089a8f0 | |
parent | a526a6b4c1542f560fd9ac6bb8dbf7f5ad5efeba (diff) | |
download | php-git-6529d7acd9912a609924633a43e6562799566225.tar.gz |
zend_weakrefs
-rw-r--r-- | Zend/tests/weakrefs/weakrefs_001.phpt | 39 | ||||
-rw-r--r-- | Zend/tests/weakrefs/weakrefs_002.phpt | 19 | ||||
-rw-r--r-- | Zend/tests/weakrefs/weakrefs_003.phpt | 43 | ||||
-rw-r--r-- | Zend/tests/weakrefs/weakrefs_004.phpt | 8 | ||||
-rw-r--r-- | Zend/tests/weakrefs/weakrefs_005.phpt | 12 | ||||
-rw-r--r-- | Zend/zend_default_classes.c | 3 | ||||
-rw-r--r-- | Zend/zend_execute_API.c | 5 | ||||
-rw-r--r-- | Zend/zend_globals.h | 2 | ||||
-rw-r--r-- | Zend/zend_objects.c | 6 | ||||
-rw-r--r-- | Zend/zend_types.h | 3 | ||||
-rw-r--r-- | Zend/zend_weakrefs.c | 213 | ||||
-rw-r--r-- | Zend/zend_weakrefs.h | 36 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | ext/com_dotnet/com_handlers.c | 2 | ||||
-rw-r--r-- | ext/com_dotnet/com_saproxy.c | 2 | ||||
-rw-r--r-- | win32/build/config.w32 | 2 |
16 files changed, 393 insertions, 4 deletions
diff --git a/Zend/tests/weakrefs/weakrefs_001.phpt b/Zend/tests/weakrefs/weakrefs_001.phpt new file mode 100644 index 0000000000..8db0fb2d80 --- /dev/null +++ b/Zend/tests/weakrefs/weakrefs_001.phpt @@ -0,0 +1,39 @@ +--TEST-- +WeakReference +--FILE-- +<?php +$std = new stdClass; + +debug_zval_dump($std); + +$wr = WeakReference::create($std); +$wr2 = WeakReference::create($std); + +debug_zval_dump($std); + +var_dump($wr, $wr2); + +debug_zval_dump($wr->get()); +debug_zval_dump($wr2->get()); + +unset($std); + +debug_zval_dump($wr->get()); +debug_zval_dump($wr2->get()); +?> +--EXPECT-- +object(stdClass)#1 (0) refcount(2){ +} +object(stdClass)#1 (0) refcount(2){ +} +object(WeakReference)#2 (0) { +} +object(WeakReference)#2 (0) { +} +object(stdClass)#1 (0) refcount(2){ +} +object(stdClass)#1 (0) refcount(2){ +} +NULL +NULL + diff --git a/Zend/tests/weakrefs/weakrefs_002.phpt b/Zend/tests/weakrefs/weakrefs_002.phpt new file mode 100644 index 0000000000..a2e277f98d --- /dev/null +++ b/Zend/tests/weakrefs/weakrefs_002.phpt @@ -0,0 +1,19 @@ +--TEST-- +WeakReference serials +--FILE-- +<?php +$wr = WeakReference::create(new stdClass); + +try { + serialize($wr); +} catch (Exception $ex) { + var_dump($ex->getMessage()); +} + +$wrs = 'O:13:"WeakReference":0:{}'; + +var_dump(@unserialize($wrs)); +?> +--EXPECT-- +string(47) "Serialization of 'WeakReference' is not allowed" +bool(false) diff --git a/Zend/tests/weakrefs/weakrefs_003.phpt b/Zend/tests/weakrefs/weakrefs_003.phpt new file mode 100644 index 0000000000..e7d8e281c5 --- /dev/null +++ b/Zend/tests/weakrefs/weakrefs_003.phpt @@ -0,0 +1,43 @@ +--TEST-- +WeakReference object handlers +--FILE-- +<?php +$wr = WeakReference::create(new stdClass); + +try { + $wr->disallow; +} catch (Error $ex) { + var_dump($ex->getMessage()); +} + +try { + $wr->disallow = "writes"; +} catch (Error $ex) { + var_dump($ex->getMessage()); +} + +try { + isset($wr->disallow); +} catch (Error $ex) { + var_dump($ex->getMessage()); +} + +try { + unset($wr->disallow); +} catch (Error $ex) { + var_dump($ex->getMessage()); +} + +try { + $disallow = &$wr->disallowed; +} catch (Error $ex) { + var_dump($ex->getMessage()); +} +?> +--EXPECT-- +string(47) "WeakReference objects do not support properties" +string(47) "WeakReference objects do not support properties" +string(47) "WeakReference objects do not support properties" +string(47) "WeakReference objects do not support properties" +string(56) "WeakReference objects do not support property references" + diff --git a/Zend/tests/weakrefs/weakrefs_004.phpt b/Zend/tests/weakrefs/weakrefs_004.phpt new file mode 100644 index 0000000000..35fb3c5b3a --- /dev/null +++ b/Zend/tests/weakrefs/weakrefs_004.phpt @@ -0,0 +1,8 @@ +--TEST-- +WeakReference no inheritance +--FILE-- +<?php +class Test extends WeakReference {} +?> +--EXPECTF-- +Fatal error: Class Test may not inherit from final class (WeakReference) in %s on line %d diff --git a/Zend/tests/weakrefs/weakrefs_005.phpt b/Zend/tests/weakrefs/weakrefs_005.phpt new file mode 100644 index 0000000000..a9ba45b760 --- /dev/null +++ b/Zend/tests/weakrefs/weakrefs_005.phpt @@ -0,0 +1,12 @@ +--TEST-- +WeakReference no __construct +--FILE-- +<?php +new WeakReference(); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Direct instantiation of 'WeakReference' is not allowed, use WeakReference::create instead in %s:2 +Stack trace: +#0 %s(2): WeakReference->__construct() +#1 {main} + thrown in %s on line 2 diff --git a/Zend/zend_default_classes.c b/Zend/zend_default_classes.c index e5ef403c4e..2c42763f0c 100644 --- a/Zend/zend_default_classes.c +++ b/Zend/zend_default_classes.c @@ -24,7 +24,7 @@ #include "zend_exceptions.h" #include "zend_closures.h" #include "zend_generators.h" - +#include "zend_weakrefs.h" ZEND_API void zend_register_default_classes(void) { @@ -33,4 +33,5 @@ ZEND_API void zend_register_default_classes(void) zend_register_iterator_wrapper(); zend_register_closure_ce(); zend_register_generator_ce(); + zend_register_weakref_ce(); } diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 048e0af967..dc8172360b 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -33,6 +33,7 @@ #include "zend_generators.h" #include "zend_vm.h" #include "zend_float.h" +#include "zend_weakrefs.h" #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #endif @@ -183,6 +184,8 @@ void init_executor(void) /* {{{ */ EG(persistent_functions_count) = EG(function_table)->nNumUsed; EG(persistent_classes_count) = EG(class_table)->nNumUsed; + zend_weakrefs_init(); + EG(active) = 1; } /* }}} */ @@ -277,6 +280,8 @@ void shutdown_executor(void) /* {{{ */ zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); + zend_weakrefs_shutdown(); + /* All resources and objects are destroyed. */ /* No PHP callback functions may be called after this point. */ EG(active) = 0; diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index c60a07e9ee..2f46da0c2d 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -227,6 +227,8 @@ struct _zend_executor_globals { zend_bool each_deprecation_thrown; + HashTable weakrefs; + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index 80efb8c895..e3efb26ddc 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -24,6 +24,7 @@ #include "zend_API.h" #include "zend_interfaces.h" #include "zend_exceptions.h" +#include "zend_weakrefs.h" static zend_always_inline void _zend_object_std_init(zend_object *object, zend_class_entry *ce) { @@ -70,6 +71,7 @@ ZEND_API void zend_object_std_dtor(zend_object *object) p++; } while (p != end); } + if (UNEXPECTED(object->ce->ce_flags & ZEND_ACC_USE_GUARDS)) { if (EXPECTED(Z_TYPE_P(p) == IS_STRING)) { zval_ptr_dtor_str(p); @@ -82,6 +84,10 @@ ZEND_API void zend_object_std_dtor(zend_object *object) FREE_HASHTABLE(guards); } } + + if (UNEXPECTED(GC_FLAGS(object) & IS_OBJ_WEAKLY_REFERENCED)) { + zend_weakrefs_notify(object); + } } ZEND_API void zend_objects_destroy_object(zend_object *object) diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 4d33e3ae9d..f14f769ba6 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -585,6 +585,7 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { #define IS_ARRAY_PERSISTENT GC_PERSISTENT /* object flags (zval.value->gc.u.flags) */ +#define IS_OBJ_WEAKLY_REFERENCED GC_PERSISTENT #define IS_OBJ_DESTRUCTOR_CALLED (1<<8) #define IS_OBJ_FREE_CALLED (1<<9) @@ -995,7 +996,7 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { #if ZEND_RC_DEBUG extern ZEND_API zend_bool zend_rc_debug; # define ZEND_RC_MOD_CHECK(p) do { \ - if (zend_rc_debug) { \ + if (zend_rc_debug && zval_gc_type((p)->u.type_info) != IS_OBJECT) { \ ZEND_ASSERT(!(zval_gc_flags((p)->u.type_info) & GC_IMMUTABLE)); \ ZEND_ASSERT((zval_gc_flags((p)->u.type_info) & (GC_PERSISTENT|GC_PERSISTENT_LOCAL)) != GC_PERSISTENT); \ } \ diff --git a/Zend/zend_weakrefs.c b/Zend/zend_weakrefs.c new file mode 100644 index 0000000000..b4eaf437c8 --- /dev/null +++ b/Zend/zend_weakrefs.c @@ -0,0 +1,213 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: krakjoe@php.net | + +----------------------------------------------------------------------+ +*/ + +#include "zend.h" +#include "zend_interfaces.h" +#include "zend_objects_API.h" +#include "zend_weakrefs.h" + +typedef struct _zend_weakref { + zend_object *referent; + zend_object std; +} zend_weakref; + +zend_class_entry *zend_ce_weakref; +static zend_object_handlers zend_weakref_handlers; + +#define zend_weakref_from(o) ((zend_weakref*)(((char*) o) - XtOffsetOf(zend_weakref, std))) +#define zend_weakref_fetch(z) zend_weakref_from(Z_OBJ_P(z)) + +static void zend_weakref_unref(zval *zv) { + zend_weakref *wr = (zend_weakref*) Z_PTR_P(zv); + + GC_DEL_FLAGS(wr->referent, IS_OBJ_WEAKLY_REFERENCED); + + wr->referent = NULL; +} + +void zend_weakrefs_init() { + zend_hash_init(&EG(weakrefs), 8, NULL, zend_weakref_unref, 0); +} + +void zend_weakrefs_notify(zend_object *object) { + zend_hash_index_del(&EG(weakrefs), (zend_ulong) object); +} + +void zend_weakrefs_shutdown() { + zend_hash_destroy(&EG(weakrefs)); +} + +static zend_object* zend_weakref_new(zend_class_entry *ce) { + zend_weakref *wr = zend_object_alloc(sizeof(zend_weakref), zend_ce_weakref); + + zend_object_std_init(&wr->std, zend_ce_weakref); + + wr->std.handlers = &zend_weakref_handlers; + + return &wr->std; +} + +static zend_always_inline zend_bool zend_weakref_find(zval *referent, zval *return_value) { + zend_weakref *wr = zend_hash_index_find_ptr(&EG(weakrefs), (zend_ulong) Z_OBJ_P(referent)); + + if (!wr) { + return 0; + } + + GC_ADDREF(&wr->std); + ZVAL_OBJ(return_value, &wr->std); + + return 1; +} + +static zend_always_inline void zend_weakref_create(zval *referent, zval *return_value) { + zend_weakref *wr; + + object_init_ex(return_value, zend_ce_weakref); + + wr = zend_weakref_fetch(return_value); + + wr->referent = Z_OBJ_P(referent); + + zend_hash_index_add_ptr(&EG(weakrefs), (zend_ulong) wr->referent, wr); + + GC_ADD_FLAGS(wr->referent, IS_OBJ_WEAKLY_REFERENCED); +} + +static zend_always_inline void zend_weakref_get(zval *weakref, zval *return_value) { + zend_weakref *wr = zend_weakref_fetch(weakref); + + if (wr->referent) { + ZVAL_OBJ(return_value, wr->referent); + Z_ADDREF_P(return_value); + } +} + +static void zend_weakref_free(zend_object *zo) { + zend_weakref *wr = zend_weakref_from(zo); + + if (wr->referent) { + zend_hash_index_del( + &EG(weakrefs), (zend_ulong) wr->referent); + } + + zend_object_std_dtor(&wr->std); +} + +#define zend_weakref_unsupported(thing) \ + zend_throw_error(NULL, "WeakReference objects do not support " thing); + +static zval* zend_weakref_no_write(zval *object, zval *member, zval *value, void **rtc) { + zend_weakref_unsupported("properties"); + + return &EG(uninitialized_zval); +} + +static zval* zend_weakref_no_read(zval *object, zval *member, int type, void **rtc, zval *rv) { + if (!EG(exception)) { + zend_weakref_unsupported("properties"); + } + + return &EG(uninitialized_zval); +} + +static zval *zend_weakref_no_read_ptr(zval *object, zval *member, int type, void **rtc) { + zend_weakref_unsupported("property references"); + return NULL; +} + +static int zend_weakref_no_isset(zval *object, zval *member, int hse, void **rtc) { + if (hse != 2) { + zend_weakref_unsupported("properties"); + } + return 0; +} + +static void zend_weakref_no_unset(zval *object, zval *member, void **rtc) { + zend_weakref_unsupported("properties"); +} + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(zend_weakref_create_arginfo, 0, 1, WeakReference, 0) + ZEND_ARG_TYPE_INFO(0, referent, IS_OBJECT, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(zend_weakref_get_arginfo, 0, 0, IS_OBJECT, 1) +ZEND_END_ARG_INFO() + +ZEND_COLD ZEND_METHOD(WeakReference, __construct) +{ + zend_throw_error(NULL, + "Direct instantiation of 'WeakReference' is not allowed, " + "use WeakReference::create instead"); +} + +ZEND_METHOD(WeakReference, create) +{ + zval *referent; + + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1,1) + Z_PARAM_OBJECT(referent) + ZEND_PARSE_PARAMETERS_END(); + + if (zend_weakref_find(referent, return_value)) { + return; + } + + zend_weakref_create(referent, return_value); +} + +ZEND_METHOD(WeakReference, get) +{ + ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 0) + ZEND_PARSE_PARAMETERS_END(); + + zend_weakref_get(getThis(), return_value); +} + +static const zend_function_entry zend_weakref_methods[] = { + ZEND_ME(WeakReference, __construct, NULL, ZEND_ACC_PUBLIC) + ZEND_ME(WeakReference, create, zend_weakref_create_arginfo, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + ZEND_ME(WeakReference, get, zend_weakref_get_arginfo, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + +void zend_register_weakref_ce(void) /* {{{ */ +{ + zend_class_entry ce; + + INIT_CLASS_ENTRY(ce, "WeakReference", zend_weakref_methods); + zend_ce_weakref = zend_register_internal_class(&ce); + zend_ce_weakref->ce_flags |= ZEND_ACC_FINAL; + + zend_ce_weakref->create_object = zend_weakref_new; + zend_ce_weakref->serialize = zend_class_serialize_deny; + zend_ce_weakref->unserialize = zend_class_unserialize_deny; + + memcpy(&zend_weakref_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + zend_weakref_handlers.offset = XtOffsetOf(zend_weakref, std); + + zend_weakref_handlers.free_obj = zend_weakref_free; + zend_weakref_handlers.read_property = zend_weakref_no_read; + zend_weakref_handlers.write_property = zend_weakref_no_write; + zend_weakref_handlers.has_property = zend_weakref_no_isset; + zend_weakref_handlers.unset_property = zend_weakref_no_unset; + zend_weakref_handlers.get_property_ptr_ptr = zend_weakref_no_read_ptr; + zend_weakref_handlers.clone_obj = NULL; +} +/* }}} */ + diff --git a/Zend/zend_weakrefs.h b/Zend/zend_weakrefs.h new file mode 100644 index 0000000000..9d2d56fc1f --- /dev/null +++ b/Zend/zend_weakrefs.h @@ -0,0 +1,36 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: krakjoe@php.net | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_WEAKREFS_H +#define ZEND_WEAKREFS_H + +BEGIN_EXTERN_C() + +ZEND_API zend_class_entry *zend_ce_weakref; + +void zend_register_weakref_ce(void); + +void zend_weakrefs_init(); +void zend_weakrefs_shutdown(); + +ZEND_API void zend_weakrefs_notify(zend_object *object); + +END_EXTERN_C() + +#endif + diff --git a/configure.ac b/configure.ac index a94b88b3c9..633388cdff 100644 --- a/configure.ac +++ b/configure.ac @@ -1558,7 +1558,7 @@ PHP_ADD_SOURCES(Zend, \ zend_list.c zend_builtin_functions.c \ zend_ini.c zend_sort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_gc.c \ - zend_closures.c zend_float.c zend_string.c zend_signal.c zend_generators.c \ + zend_closures.c zend_weakrefs.c zend_float.c zend_string.c zend_signal.c zend_generators.c \ zend_virtual_cwd.c zend_ast.c zend_objects.c zend_object_handlers.c zend_objects_API.c \ zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c, \ -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) diff --git a/ext/com_dotnet/com_handlers.c b/ext/com_dotnet/com_handlers.c index cd37718430..0a4693fec5 100644 --- a/ext/com_dotnet/com_handlers.c +++ b/ext/com_dotnet/com_handlers.c @@ -615,6 +615,8 @@ void php_com_object_free_storage(zend_object *object) zend_hash_destroy(obj->id_of_name_cache); FREE_HASHTABLE(obj->id_of_name_cache); } + + zend_object_std_dtor(object); } zend_object* php_com_object_clone(zval *object) diff --git a/ext/com_dotnet/com_saproxy.c b/ext/com_dotnet/com_saproxy.c index 170f2018e2..7eec446a3f 100644 --- a/ext/com_dotnet/com_saproxy.c +++ b/ext/com_dotnet/com_saproxy.c @@ -374,6 +374,8 @@ static void saproxy_free_storage(zend_object *object) //??? } //??? } + zend_object_std_dtor(object); + zval_ptr_dtor(proxy->zobj); efree(proxy->indices); } diff --git a/win32/build/config.w32 b/win32/build/config.w32 index 10478b41fa..38d1fa2295 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -234,7 +234,7 @@ ADD_SOURCES("Zend", "zend_language_parser.c zend_language_scanner.c \ zend_ini.c zend_sort.c zend_multibyte.c zend_ts_hash.c \ zend_stream.c zend_iterators.c zend_interfaces.c zend_objects.c \ zend_object_handlers.c zend_objects_API.c \ - zend_default_classes.c zend_execute.c zend_strtod.c zend_gc.c zend_closures.c \ + zend_default_classes.c zend_execute.c zend_strtod.c zend_gc.c zend_closures.c zend_weakrefs.c \ zend_float.c zend_string.c zend_generators.c zend_virtual_cwd.c zend_ast.c \ zend_inheritance.c zend_smart_str.c zend_cpuinfo.c"); |