Skip to content

Instantly share code, notes, and snippets.

@krakjoe

krakjoe/ex.c Secret

Last active February 22, 2019 08:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krakjoe/2293861e1bffa507220a8616940a84e5 to your computer and use it in GitHub Desktop.
Save krakjoe/2293861e1bffa507220a8616940a84e5 to your computer and use it in GitHub Desktop.
overloading functions with opcode handler
static int zend_overload_begin(zend_execute_data *execute_data) {
zend_function *target;
zend_function *overload;
if (!EX(call) ||
!EX(call)->func ||
!EX(call)->func->common.function_name ||
(EX(call)->func->common.fn_flags & ZEND_ACC_CLOSURE)) {
return ZEND_USER_OPCODE_DISPATCH;
}
target = EX(call)->func;
if ((overload = zend_overload_fetch(target))) {
zval closure;
zval *argv = ZEND_CALL_ARG(EX(call), 1);
zend_vm_stack_free_call_frame(EX(call));
if (EX(func) && EX(func)->type == ZEND_USER_FUNCTION) {
if (RUN_TIME_CACHE(&EX(func)->op_array)) {
memset(
RUN_TIME_CACHE(&EX(func)->op_array),
0,
EX(func)->op_array.cache_size);
}
}
EX(call) = zend_vm_stack_push_call_frame(
ZEND_CALL_NESTED,
overload,
overload->common.num_args,
overload->common.scope,
Z_TYPE(EX(This)) == IS_OBJECT ? Z_OBJ(EX(This)) : NULL);
zend_create_closure(&closure,
target,
target->common.scope, target->common.scope,
Z_TYPE(EX(This)) == IS_OBJECT ? &EX(This) : NULL);
{
uint32_t it = 0, end = ZEND_CALL_NUM_ARGS(EX(call));
zval *stack = ecalloc(end - 1, sizeof(zval)),
*sptr = stack,
*nptr = ZEND_CALL_ARG(EX(call), 1);
memcpy(stack, argv, (end-1) * sizeof(zval));
while (it < end) {
if (it == 0) {
*nptr = closure;
} else {
*nptr = *sptr;
sptr++;
}
nptr++;
it++;
}
efree(stack);
}
}
return ZEND_USER_OPCODE_DISPATCH;
}

If zend_overload_fetch returns the overload, it would be invoked with the original function as the first argument.

This may or may not work in 7.4 depending on what dmitry does next.

This would have to be set as either fcall_begin handler in zend extension or opcode handler for DO_FCALL/DO_FCALL_BY_NAME.

This is only possible if the engine supports hotswapping, which it may or may not.

fetch should alloc and probably zero run time cache of overload ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment