summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Watkins <krakjoe@php.net>2018-05-10 14:58:10 +0200
committerJoe Watkins <krakjoe@php.net>2019-03-12 00:35:35 +0100
commit6529d7acd9912a609924633a43e6562799566225 (patch)
tree09302816c8bba39c318c52ba5ef19999e089a8f0
parenta526a6b4c1542f560fd9ac6bb8dbf7f5ad5efeba (diff)
downloadphp-git-6529d7acd9912a609924633a43e6562799566225.tar.gz
zend_weakrefs
-rw-r--r--Zend/tests/weakrefs/weakrefs_001.phpt39
-rw-r--r--Zend/tests/weakrefs/weakrefs_002.phpt19
-rw-r--r--Zend/tests/weakrefs/weakrefs_003.phpt43
-rw-r--r--Zend/tests/weakrefs/weakrefs_004.phpt8
-rw-r--r--Zend/tests/weakrefs/weakrefs_005.phpt12
-rw-r--r--Zend/zend_default_classes.c3
-rw-r--r--Zend/zend_execute_API.c5
-rw-r--r--Zend/zend_globals.h2
-rw-r--r--Zend/zend_objects.c6
-rw-r--r--Zend/zend_types.h3
-rw-r--r--Zend/zend_weakrefs.c213
-rw-r--r--Zend/zend_weakrefs.h36
-rw-r--r--configure.ac2
-rw-r--r--ext/com_dotnet/com_handlers.c2
-rw-r--r--ext/com_dotnet/com_saproxy.c2
-rw-r--r--win32/build/config.w322
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");