Skip to content

Instantly share code, notes, and snippets.

@tpunt

tpunt/func.c Secret

Last active December 27, 2016 14:07
Show Gist options
  • Save tpunt/b1e81faf925ed474c29191ccf7bd7200 to your computer and use it in GitHub Desktop.
Save tpunt/b1e81faf925ed474c29191ccf7bd7200 to your computer and use it in GitHub Desktop.
Stack Interruption
zend_execute_data *paused_stack;
PHP_FUNCTION(interrupt_stack)
{
size_t stack_size = 0;
zend_execute_data *call_frame = execute_data->prev_execute_data; // get interrupt_stack() call site
++call_frame->opline; // skips the interrupt_stack() function call from the call site
for (; call_frame; call_frame = call_frame->prev_execute_data) {
stack_size += ZEND_CALL_FRAME_SLOT + ZEND_CALL_NUM_ARGS(call_frame);
}
paused_stack = (zend_execute_data *) emalloc(sizeof(zval) * stack_size);
call_frame = execute_data->prev_execute_data;
size_t saved_size = 0;
zend_execute_data *prev_frame = NULL;
while (call_frame) {
size_t frame_size = ZEND_CALL_FRAME_SLOT + ZEND_CALL_NUM_ARGS(call_frame);
zend_execute_data *tmp_frame;
saved_size += frame_size;
tmp_frame = (zend_execute_data *)((zval *)paused_stack + stack_size - saved_size);
memcpy(tmp_frame, call_frame, sizeof(zval) * frame_size);
tmp_frame->prev_execute_data = prev_frame;
// try fast-forwarding the oplines to the last opcode
// for (; call_frame->opline && call_frame->opline->opcode != ZEND_RETURN; ++call_frame->opline);
prev_frame = tmp_frame;
tmp_frame = call_frame->prev_execute_data;
zend_vm_stack_free_call_frame(call_frame);
call_frame = tmp_frame;
}
}
<?php
function test2()
{
interrupt_stack();
var_dump(2); // should not be output
}
function test()
{
test2();
var_dump(3); // should not be output
}
test();
var_dump(1); // should not be output
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment