From 8e9e2e44465d6fad00f7b1bb1c50c8519dc6c475 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Wed, 22 Feb 2023 19:39:10 +0100 Subject: [PATCH] Fix segfault when using ReflectionFiber (fixes #10439) --- ext/reflection/php_reflection.c | 16 ++++- ext/reflection/php_reflection.stub.php | 4 +- ext/reflection/php_reflection_arginfo.h | 8 ++- .../tests/ReflectionFiber_notrace_1.phpt | 31 ++++++++++ .../tests/ReflectionFiber_notrace_2.phpt | 61 +++++++++++++++++++ 5 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 ext/reflection/tests/ReflectionFiber_notrace_1.phpt create mode 100644 ext/reflection/tests/ReflectionFiber_notrace_2.phpt diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index f4fc588a3101d..9a9685e7292e7 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -7017,7 +7017,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) @@ -7035,7 +7041,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 750eceed66402..592ccf57c27cc 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -756,9 +756,9 @@ public function __construct(Fiber $fiber) {} 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 6242ac1c31e22..3292c5c7e94ad 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: ab0dd21b2fc7ff18c39275e1ec82211c7058c32a */ + * Stub hash: 164878e6c43f0e4c8bb7a7ae1e5c9650c240d775 */ 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) @@ -586,9 +586,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 0000000000000..28e5da39f59d1 --- /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 0000000000000..85cb4ebd20a71 --- /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) { + } + } +}