Fix generator memory leaks when interrupted during argument evaluation (#9756)

This commit is contained in:
Arnaud Le Blanc 2022-11-04 15:55:55 +01:00 committed by GitHub
parent 75970077b0
commit 5d1f3e047c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 537 additions and 3 deletions

View file

@ -95,6 +95,20 @@ ZEND_API zend_execute_data* zend_generator_freeze_call_stack(zend_execute_data *
}
/* }}} */
static zend_execute_data* zend_generator_revert_call_stack(zend_execute_data *call)
{
zend_execute_data *prev = NULL;
do {
zend_execute_data *next = call->prev_execute_data;
call->prev_execute_data = prev;
prev = call;
call = next;
} while (call);
return prev;
}
static void zend_generator_cleanup_unfinished_execution(
zend_generator *generator, zend_execute_data *execute_data, uint32_t catch_op_num) /* {{{ */
{
@ -370,6 +384,15 @@ static HashTable *zend_generator_get_gc(zend_object *object, zval **table, int *
zend_get_gc_buffer_add_zval(gc_buffer, &extra_named_params);
}
if (UNEXPECTED(generator->frozen_call_stack)) {
/* The frozen stack is linked in reverse order */
zend_execute_data *call = zend_generator_revert_call_stack(generator->frozen_call_stack);
/* -1 required because we want the last run opcode, not the next to-be-run one. */
uint32_t op_num = execute_data->opline - op_array->opcodes - 1;
zend_unfinished_calls_gc(execute_data, call, op_num, gc_buffer);
zend_generator_revert_call_stack(call);
}
if (execute_data->opline != op_array->opcodes) {
uint32_t i, op_num = execute_data->opline - op_array->opcodes - 1;
for (i = 0; i < op_array->last_live_range; i++) {
@ -604,7 +627,7 @@ ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator
static zend_result zend_generator_get_next_delegated_value(zend_generator *generator) /* {{{ */
{
--generator->execute_data->opline;
zval *value;
if (Z_TYPE(generator->values) == IS_ARRAY) {
HashTable *ht = Z_ARR(generator->values);
@ -670,7 +693,7 @@ static zend_result zend_generator_get_next_delegated_value(zend_generator *gener
ZVAL_LONG(&generator->key, iter->index);
}
}
++generator->execute_data->opline;
return SUCCESS;
@ -726,7 +749,7 @@ try_again:
generator->execute_data->prev_execute_data = &orig_generator->execute_fake;
orig_generator->execute_fake.prev_execute_data = original_execute_data;
}
/* Ensure this is run after executor_data swap to have a proper stack trace */
if (UNEXPECTED(!Z_ISUNDEF(generator->values))) {
if (EXPECTED(zend_generator_get_next_delegated_value(generator) == SUCCESS)) {