diff --git a/Zend/tests/pipe_operator/oss_fuzz_427814452.phpt b/Zend/tests/pipe_operator/oss_fuzz_427814452.phpt new file mode 100644 index 0000000000000..2ecfbab6348f7 --- /dev/null +++ b/Zend/tests/pipe_operator/oss_fuzz_427814452.phpt @@ -0,0 +1,26 @@ +--TEST-- +OSS-Fuzz #427814452 +--FILE-- + assert(...); +} catch (\AssertionError $e) { + echo $e::class, ": '", $e->getMessage(), "'\n"; +} +try { + 0 |> "assert"(...); +} catch (\AssertionError $e) { + echo $e::class, ": '", $e->getMessage(), "'\n"; +} +try { + false |> ("a"."ssert")(...); +} catch (\AssertionError $e) { + echo $e::class, ": '", $e->getMessage(), "'\n"; +} + +?> +--EXPECT-- +AssertionError: '' +AssertionError: '' +AssertionError: '' diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index f3f6d1b75aec1..b9c1f9e223a8a 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -6426,6 +6426,20 @@ static bool can_match_use_jumptable(zend_ast_list *arms) { return 1; } +static bool zend_is_deopt_pipe_name(zend_ast *ast) +{ + if (ast->kind != ZEND_AST_ZVAL || Z_TYPE_P(zend_ast_get_zval(ast)) != IS_STRING) { + return false; + } + + /* Assert compilation adds a message operand, but this is incompatible with the + * pipe optimization that uses a temporary znode for the reference elimination. + * Therefore, disable the optimization for assert. + * Note that "assert" as a name is always treated as fully qualified. */ + zend_string *str = zend_ast_get_str(ast); + return zend_string_equals_literal_ci(str, "assert"); +} + static void zend_compile_pipe(znode *result, zend_ast *ast) { zend_ast *operand_ast = ast->child[0]; @@ -6453,7 +6467,8 @@ static void zend_compile_pipe(znode *result, zend_ast *ast) /* Turn $foo |> bar(...) into bar($foo). */ if (callable_ast->kind == ZEND_AST_CALL - && callable_ast->child[1]->kind == ZEND_AST_CALLABLE_CONVERT) { + && callable_ast->child[1]->kind == ZEND_AST_CALLABLE_CONVERT + && !zend_is_deopt_pipe_name(callable_ast->child[0])) { fcall_ast = zend_ast_create(ZEND_AST_CALL, callable_ast->child[0], arg_list_ast); /* Turn $foo |> bar::baz(...) into bar::baz($foo). */