in prod/native/extension/code/InternalFunctionInstrumentation.cpp [173:227]
void callPostHook(AutoZval &hook, zval *return_value, zend_object *exception, zend_execute_data *execute_data) {
zend_fcall_info fci = empty_fcall_info;
zend_fcall_info_cache fcc = empty_fcall_info_cache;
if (zend_fcall_info_init(const_cast<zval *>(hook.get()), 0, &fci, &fcc, nullptr, nullptr) == ZEND_RESULT_CODE::FAILURE) {
throw std::runtime_error("Unable to initialize posthook fcall");
}
std::array<AutoZval, 8> parameters;
getScopeNameOrThis(parameters[0].get(), EG(current_execute_data));
getCallArguments(parameters[1].get(), EG(current_execute_data));
getFunctionReturnValue(parameters[2].get(), return_value);
getCurrentException(parameters[3].get(), exception);
getFunctionDeclaringScope(parameters[4].get(), EG(current_execute_data));
getFunctionName(parameters[5].get(), EG(current_execute_data));
getFunctionDeclarationFileName(parameters[6].get(), EG(current_execute_data));
getFunctionDeclarationLineNo(parameters[7].get(), EG(current_execute_data));
AutoZval hookRv;
fci.param_count = parameters.size();
fci.params = parameters[0].get();
fci.named_params = nullptr;
fci.retval = hookRv.get();
if (zend_call_function(&fci, &fcc) != SUCCESS) {
throw std::runtime_error("Unable to call posthook function");
}
if (Z_TYPE_P(hookRv.get()) == IS_UNDEF) {
return;
}
if (!return_value) {
return;
}
// thre is no way to distinguish if posthook returned NULL, becuase in PHP functions are always returning NULL, even if there is no return keyword
// in that case we can only try to overwrite return value for posthooks with return value type specified explicitly
if (!(fcc.function_handler->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || (ZEND_TYPE_PURE_MASK(fcc.function_handler->common.arg_info[-1].type) & MAY_BE_VOID)) {
ELOGF_TRACE(EAPM_GL(logger_), INSTRUMENTATION, "callPostHook hook doesn't explicitly specify return type other than void");
return;
}
if (execute_data->func->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
// uncomment if want to block possibility of adding rv to instrumented void-rv function
// if ((ZEND_TYPE_PURE_MASK(execute_data->func->common.arg_info[-1].type) & MAY_BE_VOID)) {
// return;
// }
bool sameType = ZEND_TYPE_CONTAINS_CODE(execute_data->func->common.arg_info[-1].type, Z_TYPE_P(hookRv.get()));
ELOGF_DEBUG(EAPM_GL(logger_), INSTRUMENTATION, "callPostHook hasRvType: %d, isVoid: %d sameType: %d, hookRvType: %d", execute_data->func->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE, static_cast<bool>(ZEND_TYPE_PURE_MASK(execute_data->func->common.arg_info[-1].type) & MAY_BE_VOID), sameType, hookRv.getType());
}
zval_ptr_dtor(return_value);
ZVAL_COPY(return_value, hookRv.get());
}