summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortwosee <twose@qq.com>2019-03-16 13:21:48 +0800
committerNikita Popov <nikita.ppv@gmail.com>2019-03-18 10:02:31 +0100
commitbd6eabd6591ae5a7c9ad75dfbe7cc575fa907eac (patch)
tree759a869024940ae83abb608584b4eb0cabc6357a
parentab07bc1fff27c19b390e0f57ceb4a0523085fdfa (diff)
downloadphp-git-bd6eabd6591ae5a7c9ad75dfbe7cc575fa907eac.tar.gz
Don't disable object slot reuse while running shutdown functions
We only need to do this once we're running destructors. The current approach interferes with some event loop code that runs everything inside a shutdown function.
-rw-r--r--Zend/tests/object_gc_in_shutdown.phpt14
-rw-r--r--Zend/zend_globals.h5
-rw-r--r--Zend/zend_objects_API.c5
3 files changed, 20 insertions, 4 deletions
diff --git a/Zend/tests/object_gc_in_shutdown.phpt b/Zend/tests/object_gc_in_shutdown.phpt
new file mode 100644
index 0000000000..d55c08dfb1
--- /dev/null
+++ b/Zend/tests/object_gc_in_shutdown.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Bug object gc not working in shutdown
+--FILE--
+<?php
+ini_set('memory_limit', '2M');
+register_shutdown_function(function () {
+ for ($n = 1000 * 1000; $n--;) {
+ new stdClass;
+ }
+ echo "OK\n";
+});
+?>
+--EXPECT--
+OK
diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h
index 802c7be889..dae93d90b9 100644
--- a/Zend/zend_globals.h
+++ b/Zend/zend_globals.h
@@ -230,8 +230,9 @@ struct _zend_executor_globals {
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};
-#define EG_FLAGS_INITIAL 0x00
-#define EG_FLAGS_IN_SHUTDOWN 0x01
+#define EG_FLAGS_INITIAL (0)
+#define EG_FLAGS_IN_SHUTDOWN (1<<0)
+#define EG_FLAGS_OBJECT_STORE_NO_REUSE (1<<1)
struct _zend_ini_scanner_globals {
zend_file_handle *yy_in;
diff --git a/Zend/zend_objects_API.c b/Zend/zend_objects_API.c
index 2cb496da40..3e3c8a8005 100644
--- a/Zend/zend_objects_API.c
+++ b/Zend/zend_objects_API.c
@@ -43,6 +43,7 @@ ZEND_API void zend_objects_store_destroy(zend_objects_store *objects)
ZEND_API void zend_objects_store_call_destructors(zend_objects_store *objects)
{
+ EG(flags) |= EG_FLAGS_OBJECT_STORE_NO_REUSE;
if (objects->top > 1) {
uint32_t i;
for (i = 1; i < objects->top; i++) {
@@ -133,10 +134,10 @@ ZEND_API void zend_objects_store_put(zend_object *object)
{
int handle;
- /* When in shutdown sequesnce - do not reuse previously freed handles, to make sure
+ /* When in shutdown sequence - do not reuse previously freed handles, to make sure
* the dtors for newly created objects are called in zend_objects_store_call_destructors() loop
*/
- if (!(EG(flags) & EG_FLAGS_IN_SHUTDOWN) && EG(objects_store).free_list_head != -1) {
+ if (EG(objects_store).free_list_head != -1 && EXPECTED(!(EG(flags) & EG_FLAGS_OBJECT_STORE_NO_REUSE))) {
handle = EG(objects_store).free_list_head;
EG(objects_store).free_list_head = GET_OBJ_BUCKET_NUMBER(EG(objects_store).object_buckets[handle]);
} else {