diff options
author | twosee <twose@qq.com> | 2019-03-16 13:21:48 +0800 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-03-18 10:02:31 +0100 |
commit | bd6eabd6591ae5a7c9ad75dfbe7cc575fa907eac (patch) | |
tree | 759a869024940ae83abb608584b4eb0cabc6357a /Zend | |
parent | ab07bc1fff27c19b390e0f57ceb4a0523085fdfa (diff) | |
download | php-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.
Diffstat (limited to 'Zend')
-rw-r--r-- | Zend/tests/object_gc_in_shutdown.phpt | 14 | ||||
-rw-r--r-- | Zend/zend_globals.h | 5 | ||||
-rw-r--r-- | Zend/zend_objects_API.c | 5 |
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 { |