diff --git a/NEWS b/NEWS index 437fc103a29..d3eba2ed845 100644 --- a/NEWS +++ b/NEWS @@ -100,6 +100,8 @@ PHP NEWS method). (ilutov) . Fix GH-10259 (ReflectionClass::getStaticProperties doesn't need null return type). (kocsismate) + . Fix Segfault when using ReflectionFiber suspended by an internal function. + (danog) - Sockets: . Added SO_ATTACH_REUSEPORT_CBPF socket option, to give tighter control diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 11726ec1470..47f889dc0f4 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -7041,7 +7041,13 @@ ZEND_METHOD(ReflectionFiber, getExecutingLine) prev_execute_data = fiber->execute_data->prev_execute_data; } - RETURN_LONG(prev_execute_data->opline->lineno); + while (prev_execute_data && (!prev_execute_data->func || !ZEND_USER_CODE(prev_execute_data->func->common.type))) { + prev_execute_data = prev_execute_data->prev_execute_data; + } + if (prev_execute_data && prev_execute_data->func && ZEND_USER_CODE(prev_execute_data->func->common.type)) { + RETURN_LONG(prev_execute_data->opline->lineno); + } + RETURN_NULL(); } ZEND_METHOD(ReflectionFiber, getExecutingFile) @@ -7059,7 +7065,13 @@ ZEND_METHOD(ReflectionFiber, getExecutingFile) prev_execute_data = fiber->execute_data->prev_execute_data; } - RETURN_STR_COPY(prev_execute_data->func->op_array.filename); + while (prev_execute_data && (!prev_execute_data->func || !ZEND_USER_CODE(prev_execute_data->func->common.type))) { + prev_execute_data = prev_execute_data->prev_execute_data; + } + if (prev_execute_data && prev_execute_data->func && ZEND_USER_CODE(prev_execute_data->func->common.type)) { + RETURN_STR_COPY(prev_execute_data->func->op_array.filename); + } + RETURN_NULL(); } ZEND_METHOD(ReflectionFiber, getCallable) diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index 25eeb73af88..3ecb5f78765 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -874,9 +874,9 @@ final class ReflectionFiber public function getFiber(): Fiber {} - public function getExecutingFile(): string {} + public function getExecutingFile(): ?string {} - public function getExecutingLine(): int {} + public function getExecutingLine(): ?int {} public function getCallable(): callable {} diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index 78f64f20a20..708dbbeeb5d 100644 --- a/ext/reflection/php_reflection_arginfo.h +++ b/ext/reflection/php_reflection_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 0b548ff454b1a3deb531092355c456f5dd62d97c */ + * Stub hash: f640c1b592a7e9e7a8e92195df579bfaaa3da6dc */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0) ZEND_ARG_TYPE_INFO(0, modifiers, IS_LONG, 0) @@ -592,9 +592,11 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ReflectionFiber_getFiber, 0, 0, Fiber, 0) ZEND_END_ARG_INFO() -#define arginfo_class_ReflectionFiber_getExecutingFile arginfo_class_ReflectionFunction___toString +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionFiber_getExecutingFile, 0, 0, IS_STRING, 1) +ZEND_END_ARG_INFO() -#define arginfo_class_ReflectionFiber_getExecutingLine arginfo_class_ReflectionAttribute_getTarget +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionFiber_getExecutingLine, 0, 0, IS_LONG, 1) +ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionFiber_getCallable, 0, 0, IS_CALLABLE, 0) ZEND_END_ARG_INFO() diff --git a/ext/reflection/tests/ReflectionFiber_notrace_1.phpt b/ext/reflection/tests/ReflectionFiber_notrace_1.phpt new file mode 100644 index 00000000000..28e5da39f59 --- /dev/null +++ b/ext/reflection/tests/ReflectionFiber_notrace_1.phpt @@ -0,0 +1,31 @@ +--TEST-- +ReflectionFiber should not segfault when inspecting fibers with no stack frames before suspend +--FILE-- +start(); + +$reflection = new ReflectionFiber($f); + +var_dump($reflection->getExecutingFile()); +var_dump($reflection->getExecutingLine()); +var_dump($reflection->getTrace()); + +?> +--EXPECTF-- +NULL +NULL +array(1) { + [0]=> + array(4) { + ["function"]=> + string(7) "suspend" + ["class"]=> + string(5) "Fiber" + ["type"]=> + string(2) "::" + ["args"]=> + array(0) { + } + } +} diff --git a/ext/reflection/tests/ReflectionFiber_notrace_2.phpt b/ext/reflection/tests/ReflectionFiber_notrace_2.phpt new file mode 100644 index 00000000000..85cb4ebd20a --- /dev/null +++ b/ext/reflection/tests/ReflectionFiber_notrace_2.phpt @@ -0,0 +1,61 @@ +--TEST-- +ReflectionFiber should not segfault when inspecting fibers where the previous stack frame is a native function +--FILE-- + call_user_func(["Fiber", "suspend"])); +$f->start(); + +$reflection = new \ReflectionFiber($f); + +var_dump($reflection->getExecutingFile()); +var_dump($reflection->getExecutingLine()); +var_dump($reflection->getTrace()); + +?> +--EXPECTF-- +string(%d) "%sReflectionFiber_notrace_2.php" +int(5) +array(3) { + [0]=> + array(4) { + ["function"]=> + string(7) "suspend" + ["class"]=> + string(5) "Fiber" + ["type"]=> + string(2) "::" + ["args"]=> + array(0) { + } + } + [1]=> + array(4) { + ["file"]=> + string(%d) "%sReflectionFiber_notrace_2.php" + ["line"]=> + int(5) + ["function"]=> + string(14) "call_user_func" + ["args"]=> + array(1) { + [0]=> + array(2) { + [0]=> + string(5) "Fiber" + [1]=> + string(7) "suspend" + } + } + } + [2]=> + array(2) { + ["function"]=> + string(14) "test\{closure}" + ["args"]=> + array(0) { + } + } +}