]> granicus.if.org Git - php/commitdiff
Fixed bug #76427 (Segfault in zend_objects_store_put)
authorXinchen Hui <laruence@gmail.com>
Mon, 11 Jun 2018 13:00:09 +0000 (21:00 +0800)
committerXinchen Hui <laruence@gmail.com>
Mon, 11 Jun 2018 13:00:38 +0000 (21:00 +0800)
NEWS
Zend/tests/generators/bug76427.phpt [new file with mode: 0644]
Zend/zend_gc.c
Zend/zend_generators.c
Zend/zend_objects_API.c
Zend/zend_objects_API.h

diff --git a/NEWS b/NEWS
index 9400df0ce3e47d375dde61faec8563a91626fa4e..df45710d45e30cdad28e0a2ed5be16c282c8d474 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ PHP                                                                        NEWS
 ?? ??? ????, PHP 7.3.0alpha2
 
 - Core:
+  . Fixed bug #76427 (Segfault in zend_objects_store_put). (Laruence)
   . Fixed bug #76422 (ftruncate fails on files > 2GB). (Anatol)
 
 - EXIF:
diff --git a/Zend/tests/generators/bug76427.phpt b/Zend/tests/generators/bug76427.phpt
new file mode 100644 (file)
index 0000000..09ec61a
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+Bug #76427 (Segfault in zend_objects_store_put)
+--FILE--
+<?php
+$func = function () {
+       yield 2;
+};
+
+$a  = new stdclass();
+$b =  new stdclass();
+$a->b = $b;
+$b->a = $a;
+
+$func = $a->func = $func();
+
+unset($b);
+unset($a);
+unset($func);
+
+var_dump(gc_collect_cycles());
+
+?>
+--EXPECT--
+int(4)
index a6c3741d5607330599b65a5f5a0e642c87ebebb8..40402a5a7dae65186e4fb479afdd85b150069e72 100644 (file)
@@ -1401,8 +1401,8 @@ ZEND_API int zend_gc_collect_cycles(void)
                                                        GC_DELREF(obj);
                                                }
                                        }
-                                       SET_OBJ_BUCKET_NUMBER(EG(objects_store).object_buckets[obj->handle], EG(objects_store).free_list_head);
-                                       EG(objects_store).free_list_head = obj->handle;
+
+                                       ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST(obj->handle);
                                        current->ref = GC_MAKE_GARBAGE(((char*)obj) - obj->handlers->offset);
                                } else if (GC_TYPE(p) == IS_ARRAY) {
                                        zend_array *arr = (zend_array*)p;
index 90e5529f0045def248d4b4aa771f502a27f9ce0a..f4dd33b95cc302d65b13970e0b49e279a574bfbc 100644 (file)
@@ -145,7 +145,8 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
                }
 
                /* Free closure object */
-               if (EX_CALL_INFO() & ZEND_CALL_CLOSURE) {
+               if ((EX_CALL_INFO() & ZEND_CALL_CLOSURE) &&
+                       EXPECTED(GC_TYPE(ZEND_CLOSURE_OBJECT(EX(func))) == IS_OBJECT)) {
                        OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
                }
 
index 633abccabb22f51a6145f5b242645f6f06554dde..0be4651cd6e1bf8003c111f60ead9b290c94d42f 100644 (file)
@@ -150,10 +150,6 @@ ZEND_API void ZEND_FASTCALL zend_objects_store_put(zend_object *object)
        EG(objects_store).object_buckets[handle] = object;
 }
 
-#define ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST(handle)                                                                                                                    \
-            SET_OBJ_BUCKET_NUMBER(EG(objects_store).object_buckets[handle], EG(objects_store).free_list_head); \
-                       EG(objects_store).free_list_head = handle;
-
 ZEND_API void ZEND_FASTCALL zend_objects_store_del(zend_object *object) /* {{{ */
 {
        /*      Make sure we hold a reference count during the destructor call
index 6fac2b535e3201f5dffe1b30ae10e416dca3674f..08cefb8ba6926e677d8e60da28d29bccdc2ed461 100644 (file)
                (o) = (zend_object*)((((zend_uintptr_t)(n)) << 1) | OBJ_BUCKET_INVALID); \
        } while (0)
 
+#define ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST(h) do { \
+               SET_OBJ_BUCKET_NUMBER(EG(objects_store).object_buckets[(h)], EG(objects_store).free_list_head); \
+               EG(objects_store).free_list_head = (h); \
+       } while (0)
 
 #define OBJ_RELEASE(obj) zend_object_release(obj)