summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--Zend/tests/generators/bug76427.phpt24
-rw-r--r--Zend/zend_gc.c4
-rw-r--r--Zend/zend_generators.c3
-rw-r--r--Zend/zend_objects_API.c4
-rw-r--r--Zend/zend_objects_API.h4
6 files changed, 33 insertions, 7 deletions
diff --git a/NEWS b/NEWS
index 9400df0ce3..df45710d45 100644
--- 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
index 0000000000..09ec61a340
--- /dev/null
+++ b/Zend/tests/generators/bug76427.phpt
@@ -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)
diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c
index a6c3741d56..40402a5a7d 100644
--- a/Zend/zend_gc.c
+++ b/Zend/zend_gc.c
@@ -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;
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index 90e5529f00..f4dd33b95c 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -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)));
}
diff --git a/Zend/zend_objects_API.c b/Zend/zend_objects_API.c
index 633abccabb..0be4651cd6 100644
--- a/Zend/zend_objects_API.c
+++ b/Zend/zend_objects_API.c
@@ -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
diff --git a/Zend/zend_objects_API.h b/Zend/zend_objects_API.h
index 6fac2b535e..08cefb8ba6 100644
--- a/Zend/zend_objects_API.h
+++ b/Zend/zend_objects_API.h
@@ -37,6 +37,10 @@
(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)