Skip to content

Commit

Permalink
Fix unknown function call on PHP8.2+
Browse files Browse the repository at this point in the history
8.2 triggers an exception if we call unknown function
If then we try to make another call, it will trigger a fatal error.

Let's check if such function exists and avoid exceptions/fatals.
  • Loading branch information
Mikhail Galanin committed Aug 11, 2023
1 parent cfca2b1 commit 438cc25
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 12 deletions.
47 changes: 40 additions & 7 deletions blitz.c
Original file line number Diff line number Diff line change
Expand Up @@ -3293,6 +3293,40 @@ static inline int blitz_exec_predefined_method(blitz_tpl *tpl, blitz_node *node,
}
/* }}} */

/*
call_user_function()/zend_call_function() raises an exception if the function/method not found
We may not want this - if we haven't found function, we may try method (and vice-versa)
That's why we will check if the call is legit first.
*/
static zend_result blitz_call_user_function(zval *zobject, zval *function_name, zval *retval_ptr, uint32_t param_count, zval params[])
{
zend_fcall_info_cache function_info_cache = {0};
zend_object *object = NULL;
if (zobject) {
ZEND_ASSERT(Z_TYPE_P(zobject) == IS_OBJECT);
object = Z_OBJ_P(zobject);
}

char *error = NULL;
if (!zend_is_callable_ex(function_name, object, 0, NULL, &function_info_cache, &error)) {
efree(error);
return FAILURE;
}

zend_fcall_info fci;

fci.size = sizeof(fci);
fci.object = object;
ZVAL_COPY_VALUE(&fci.function_name, function_name);
fci.retval = retval_ptr;
fci.param_count = param_count;
fci.params = params;
fci.named_params = NULL;

return zend_call_function(&fci, &function_info_cache);
}

/* {{{ int blitz_exec_user_method() */
static inline int blitz_exec_user_method(blitz_tpl *tpl, blitz_node *node, zval *iteration_params, zval *obj, smart_str *result, unsigned long *result_alloc_len)
{
Expand Down Expand Up @@ -3397,12 +3431,11 @@ static inline int blitz_exec_user_method(blitz_tpl *tpl, blitz_node *node, zval
Otherwise, call object method and then PHP if PHP cals are enabled.
*/

function_table = &Z_OBJCE_P(obj)->function_table;
if (node->namespace_code == BLITZ_NODE_THIS_NAMESPACE) {
method_res = call_user_function(function_table, obj, &zmethod, &retval, node->n_args, pargs);
method_res = blitz_call_user_function(obj, &zmethod, &retval, node->n_args, pargs);
} else if (node->namespace_code) {
if (BLITZ_G(enable_php_callbacks)) {
method_res = call_user_function(NULL, NULL, &zmethod, &retval, node->n_args, pargs);
method_res = blitz_call_user_function(NULL, &zmethod, &retval, node->n_args, pargs);
} else {
blitz_error(tpl, E_WARNING,
"PHP callbacks are disabled by blitz.enable_php_callbacks, %s call was ignored, line %lu, pos %lu",
Expand All @@ -3413,14 +3446,14 @@ static inline int blitz_exec_user_method(blitz_tpl *tpl, blitz_node *node, zval
}
} else {
if (BLITZ_G(php_callbacks_first) && BLITZ_G(enable_php_callbacks)) {
method_res = call_user_function(NULL, NULL, &zmethod, &retval, node->n_args, pargs);
method_res = blitz_call_user_function(NULL, &zmethod, &retval, node->n_args, pargs);
if (method_res == FAILURE) {
method_res = call_user_function(function_table, obj, &zmethod, &retval, node->n_args, pargs);
method_res = blitz_call_user_function(obj, &zmethod, &retval, node->n_args, pargs);
}
} else {
method_res = call_user_function(function_table, obj, &zmethod, &retval, node->n_args, pargs);
method_res = blitz_call_user_function(obj, &zmethod, &retval, node->n_args, pargs);
if (method_res == FAILURE && BLITZ_G(enable_php_callbacks)) {
method_res = call_user_function(NULL, NULL, &zmethod, &retval, node->n_args, pargs);
method_res = blitz_call_user_function(NULL, &zmethod, &retval, node->n_args, pargs);
}
}
}
Expand Down
20 changes: 15 additions & 5 deletions tests/return_non_string_php8.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ returning non-strings from user methods
<?php
if (PHP_VERSION_ID < 80000) die("SKIP: The test is for PHP v8.0+");
?>
--INI--
; disable warning "Array to string conversion"
error_reporting=E_ALL & ~E_WARNING;
--FILE---
<?php
include('common.inc');
Expand All @@ -16,6 +19,8 @@ function myErrorHandler($errno, $errstr, $errfile, $errline) {
$global_errors .= "\n";
}
$global_errors .= $errstr;

return true;
}
set_error_handler("myErrorHandler");

Expand All @@ -27,11 +32,16 @@ class Tpl extends Blitz
}


// number
$T = new Tpl();
$T->load("{{get_number()}}");
$body = $T->parse();
echo "$body\n";
try {
// number
$T = new Tpl();
$T->load("{{get_number()}}");
$body = $T->parse();
echo "$body\n";
} catch (\Throwable $t) {
$class = get_class($t);
echo "Exception caught: {$class} {$t->getMessage()}\n";
}


// array
Expand Down

0 comments on commit 438cc25

Please sign in to comment.