diff --git a/Zend/tests/lazy_objects/gh16504.phpt b/Zend/tests/lazy_objects/gh16504.phpt new file mode 100644 index 0000000000000..f7077e3407f89 --- /dev/null +++ b/Zend/tests/lazy_objects/gh16504.phpt @@ -0,0 +1,46 @@ +--TEST-- +GH-16504: Segmentation fault when failing to clone +--FILE-- +newLazyProxy(function () {}); +try { + clone $proxy; +} catch ( Error $e ) { + echo $e; +} + +echo "\n\nGhost:\n"; +$ghost = $reflection->newLazyGhost(function () {}); +try { + clone $ghost; +} catch ( Error $e ) { + echo $e; +} + +?> +--EXPECTF-- +Proxy: +Error: Undefined constant "FOO" in %s:%d +Stack trace: +#0 {main} + +Next Error: Undefined constant "FOO" in %s:%d +Stack trace: +#0 {main} + +Ghost: +Error: Undefined constant "FOO" in %s:%d +Stack trace: +#0 {main} + +Next Error: Undefined constant "FOO" in %s:%d +Stack trace: +#0 {main} diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index 94be396f580f8..f3bdf41dd7f79 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -712,7 +712,12 @@ zend_object *zend_lazy_object_clone(zend_object *old_obj) /* Clone handler must always return an object. It is discarded later due * to the exception. */ zval zv; - object_init_ex(&zv, old_obj->ce); + if (object_init_ex(&zv, old_obj->ce) == FAILURE) { + // Since the return is just going to be discarded, and we couldn't + // create a new instance of the cloned class, just return the + // current instance + return old_obj; + } GC_ADD_FLAGS(Z_OBJ(zv), IS_OBJ_DESTRUCTOR_CALLED); return Z_OBJ(zv); }