static int32_t qb_transfer_variables_to_generator(qb_interpreter_context *cxt) { USE_TSRM zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr); zval *ret, *ret_key; // reusing previous key and value if(generator->value) { ret = generator->value; } else { ALLOC_INIT_ZVAL(ret); generator->value = ret; } if(generator->key) { ret_key = generator->key; } else { ALLOC_INIT_ZVAL(ret_key); generator->key = ret_key; } if(cxt->function->return_variable->address) { if(!qb_transfer_value_to_zval(cxt->function->local_storage, cxt->function->return_variable->address, ret)) { uint32_t line_id = qb_get_zend_line_id(TSRMLS_C); qb_append_exception_variable_name(cxt->function->return_variable TSRMLS_CC); qb_set_exception_line_id(line_id TSRMLS_CC); return FALSE; } } if(cxt->function->return_key_variable->address) { if(!qb_transfer_value_to_zval(cxt->function->local_storage, cxt->function->return_key_variable->address, ret_key)) { uint32_t line_id = qb_get_zend_line_id(TSRMLS_C); qb_append_exception_variable_name(cxt->function->return_key_variable TSRMLS_CC); qb_set_exception_line_id(line_id TSRMLS_CC); return FALSE; } } if(cxt->function->sent_variable->address) { #if PHP_MINOR_VERSION > 5 || PHP_RELEASE_VERSION > 7 static zval _dummy_value, *dummy_value = &_dummy_value; if(generator->send_target) { zval_ptr_dtor(generator->send_target); } generator->send_target = (zval **) &cxt->send_target; // Zend will call Z_DELREF_PP() on what generator->send_target points to // put a dummy value there so it doesn't crash *generator->send_target = dummy_value; #else if(!generator->send_target) { cxt->send_target = emalloc(sizeof(temp_variable)); memset(cxt->send_target, 0, sizeof(temp_variable)); generator->send_target = cxt->send_target; } #endif } return TRUE; }
static int32_t qb_transfer_arguments_from_php(qb_interpreter_context *cxt) { USE_TSRM int32_t result = TRUE; #if !ZEND_ENGINE_2_2 && !ZEND_ENGINE_2_1 void **p = EG(current_execute_data)->prev_execute_data->function_state.arguments; #else void **p = EG(argument_stack).top_element-1-1; #endif uint32_t received_argument_count = (uint32_t) (uintptr_t) *p; uint32_t i; for(i = 0; i < cxt->function->argument_count; i++) { qb_variable *qvar = cxt->function->variables[i]; uint32_t transfer_flags = 0; if(qvar->flags & QB_VARIABLE_BY_REF) { // avoid allocating new memory and copying contents if changes will be copied back anyway transfer_flags = QB_TRANSFER_CAN_BORROW_MEMORY | QB_TRANSFER_CAN_AUTOVIVIFICATE; } else if(IS_READ_ONLY(qvar->address)) { // or if no changes will be made transfer_flags = QB_TRANSFER_CAN_BORROW_MEMORY; } if(i < received_argument_count) { zval **p_zarg = (zval**) p - received_argument_count + i; zval *zarg = *p_zarg; if(!qb_transfer_value_from_zval(cxt->function->local_storage, qvar->address, zarg, transfer_flags)) { uint32_t line_id = qb_get_zend_line_id(TSRMLS_C); qb_append_exception_variable_name(qvar TSRMLS_CC); qb_set_exception_line_id(line_id TSRMLS_CC); result = FALSE; } qvar->value = zarg; } else { if(qvar->default_value) { zval *zarg = qvar->default_value; if(!qb_transfer_value_from_zval(cxt->function->local_storage, qvar->address, zarg, transfer_flags)) { uint32_t line_id = qb_get_zend_line_id(TSRMLS_C); qb_append_exception_variable_name(qvar TSRMLS_CC); qb_set_exception_line_id(line_id TSRMLS_CC); result = FALSE; } } else { const char *class_name = (EG(active_op_array)->scope) ? EG(active_op_array)->scope->name : NULL; zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data; uint32_t caller_line_id = 0; if(ptr && ptr->op_array) { uint32_t caller_file_id = qb_get_source_file_id(ptr->op_array->filename TSRMLS_CC); uint32_t caller_line_number = ptr->opline->lineno; caller_line_id = LINE_ID(caller_file_id, caller_line_number); } qb_report_missing_argument_exception(cxt->function->line_id, class_name, cxt->function->name, i, caller_line_id); } } } return result; }
static int32_t qb_transfer_value_from_import_source(qb_interpreter_context *cxt, qb_variable *ivar, qb_import_scope *scope) { int32_t result = TRUE; if(!(ivar->flags & QB_VARIABLE_IMPORTED)) { USE_TSRM zval *zvalue = NULL, **p_zvalue = NULL; switch(scope->type) { case QB_IMPORT_SCOPE_GLOBAL: case QB_IMPORT_SCOPE_LEXICAL: { // copy value from symbol table zend_hash_quick_find(scope->symbol_table, ivar->name, ivar->name_length + 1, ivar->hash_value, (void **) &p_zvalue); } break; case QB_IMPORT_SCOPE_CLASS: { if(ivar->flags & QB_VARIABLE_CLASS_CONSTANT) { // static:: constants are treated like variables zend_class_entry *ce = scope->class_entry; zval **p_value; zend_hash_quick_find(&ce->constants_table, ivar->name, ivar->name_length + 1, ivar->hash_value, (void **) &p_value); } else { zend_class_entry *ce = scope->class_entry; p_zvalue = Z_CLASS_GET_PROP(ce, ivar->name, ivar->name_length); } } break; case QB_IMPORT_SCOPE_OBJECT: { // copy value from class instance zval *name = qb_string_to_zval(ivar->name, ivar->name_length TSRMLS_CC); zval *container = scope->object; p_zvalue = Z_OBJ_GET_PROP_PTR_PTR(container, name); if(!p_zvalue) { if(Z_OBJ_HT_P(container)->read_property) { zvalue = Z_OBJ_READ_PROP(container, name); } } } break; default: { } break; } if(p_zvalue) { zvalue = *p_zvalue; } if(qb_transfer_value_from_zval(scope->storage, ivar->address, (zvalue) ? zvalue : &zval_used_for_init, QB_TRANSFER_CAN_BORROW_MEMORY | QB_TRANSFER_CAN_AUTOVIVIFICATE)) { ivar->flags |= QB_VARIABLE_IMPORTED; ivar->value_pointer = p_zvalue; ivar->value = zvalue; if(!p_zvalue && zvalue) { // we got the zval from a getter function // need to up the reference count Z_ADDREF_P(zvalue); } } else { uint32_t line_id = qb_get_zend_line_id(TSRMLS_C); qb_append_exception_variable_name(ivar TSRMLS_CC); qb_set_exception_line_id(line_id TSRMLS_CC); result = FALSE; } } return result; }
static int32_t qb_transfer_arguments_to_php(qb_interpreter_context *cxt) { USE_TSRM #if !ZEND_ENGINE_2_2 && !ZEND_ENGINE_2_1 void **p = EG(current_execute_data)->prev_execute_data->function_state.arguments; #else void **p = EG(argument_stack).top_element-1-1; #endif uint32_t received_argument_count = (uint32_t) (uintptr_t) *p; uint32_t i; // copy changes to by-ref arguments for(i = 0; i < cxt->function->argument_count; i++) { qb_variable *qvar = cxt->function->variables[i]; if(qvar->flags & QB_VARIABLE_BY_REF) { if(i < received_argument_count) { zval **p_zarg = (zval**) p - received_argument_count + i; zval *zarg = *p_zarg; if(!qb_transfer_value_to_zval(cxt->function->local_storage, qvar->address, zarg)) { uint32_t line_id = qb_get_zend_line_id(TSRMLS_C); qb_append_exception_variable_name(qvar TSRMLS_CC); qb_set_exception_line_id(line_id TSRMLS_CC); return FALSE; } } } qvar->value = NULL; } if(EG(return_value_ptr_ptr)) { // copy value into return variable zval *ret, **p_ret = EG(return_value_ptr_ptr); ALLOC_INIT_ZVAL(ret); *p_ret = ret; if(cxt->function->return_variable->address) { if(!qb_transfer_value_to_zval(cxt->function->local_storage, cxt->function->return_variable->address, ret)) { uint32_t line_id = qb_get_zend_line_id(TSRMLS_C); qb_append_exception_variable_name(cxt->function->return_variable TSRMLS_CC); qb_set_exception_line_id(line_id TSRMLS_CC); return FALSE; } } } return TRUE; }
static int32_t qb_transfer_arguments_from_caller(qb_interpreter_context *cxt) { uint32_t received_argument_count = cxt->caller_context->argument_count; uint32_t i; for(i = 0; i < cxt->function->argument_count; i++) { qb_variable *qvar = cxt->function->variables[i]; if(i < received_argument_count) { uint32_t argument_index = cxt->caller_context->argument_indices[i]; qb_variable *caller_qvar = cxt->caller_context->function->variables[argument_index]; qb_storage *caller_storage = cxt->caller_context->function->local_storage; uint32_t transfer_flags = 0; if((qvar->flags & QB_VARIABLE_BY_REF) || IS_READ_ONLY(qvar->address)) { transfer_flags = QB_TRANSFER_CAN_BORROW_MEMORY; } if(!qb_transfer_value_from_storage_location(cxt->function->local_storage, qvar->address, caller_storage, caller_qvar->address, transfer_flags)) { USE_TSRM qb_append_exception_variable_name(qvar TSRMLS_CC); qb_set_exception_line_id(cxt->caller_context->line_id TSRMLS_CC); return FALSE; } } else { if(qvar->default_value) { zval *zarg = qvar->default_value; uint32_t transfer_flags = 0; if(IS_READ_ONLY(qvar->address)) { transfer_flags = QB_TRANSFER_CAN_BORROW_MEMORY; } if(!qb_transfer_value_from_zval(cxt->function->local_storage, qvar->address, zarg, transfer_flags)) { USE_TSRM qb_append_exception_variable_name(qvar TSRMLS_CC); qb_set_exception_line_id(cxt->caller_context->line_id TSRMLS_CC); return FALSE; } } else { USE_TSRM const char *class_name = (EG(active_op_array)->scope) ? EG(active_op_array)->scope->name : NULL; qb_report_missing_argument_exception(cxt->function->line_id, class_name, cxt->function->name, i, cxt->caller_context->line_id); } } } return TRUE; }
static int32_t qb_transfer_arguments_to_caller(qb_interpreter_context *cxt) { uint32_t received_argument_count = cxt->caller_context->argument_count; uint32_t retval_index = cxt->caller_context->result_index; uint32_t i; for(i = 0; i < cxt->function->argument_count; i++) { qb_variable *qvar = cxt->function->variables[i]; if(i < received_argument_count) { uint32_t argument_index = cxt->caller_context->argument_indices[i]; qb_variable *caller_qvar = cxt->caller_context->function->variables[argument_index]; qb_storage *caller_storage = cxt->caller_context->function->local_storage; if(qvar->flags & QB_VARIABLE_BY_REF) { if(!qb_transfer_value_to_storage_location(cxt->function->local_storage, qvar->address, caller_storage, caller_qvar->address)) { USE_TSRM qb_append_exception_variable_name(qvar TSRMLS_CC); qb_set_exception_line_id(cxt->caller_context->line_id TSRMLS_CC); return FALSE; } } } } if(retval_index != INVALID_INDEX) { if(cxt->function->return_variable->address) { qb_variable *qvar = cxt->function->return_variable; qb_variable *caller_qvar = cxt->caller_context->function->variables[retval_index]; qb_storage *caller_storage = cxt->caller_context->function->local_storage; if(!qb_transfer_value_to_storage_location(cxt->function->local_storage, qvar->address, caller_storage, caller_qvar->address)) { USE_TSRM qb_append_exception_variable_name(qvar TSRMLS_CC); qb_set_exception_line_id(cxt->caller_context->line_id TSRMLS_CC); return FALSE; } } } return TRUE; }
static int32_t qb_transfer_value_to_import_source(qb_interpreter_context *cxt, qb_variable *ivar, qb_import_scope *scope) { int32_t result = TRUE; if(ivar->flags & QB_VARIABLE_IMPORTED) { USE_TSRM zval *zvalue = ivar->value, **p_zvalue = ivar->value_pointer; if(!IS_READ_ONLY(ivar->address)) { if(zvalue) { // separate the zval first, since we're modifying it SEPARATE_ZVAL_IF_NOT_REF(&zvalue); } else { ALLOC_INIT_ZVAL(zvalue); } if(!qb_transfer_value_to_zval(scope->storage, ivar->address, zvalue)) { uint32_t line_id = qb_get_zend_line_id(TSRMLS_C); qb_append_exception_variable_name(ivar TSRMLS_CC); qb_set_exception_line_id(line_id TSRMLS_CC); result = FALSE; } if(p_zvalue) { *p_zvalue = zvalue; } else { if(ivar->flags & QB_VARIABLE_GLOBAL) { zend_hash_quick_update(&EG(symbol_table), ivar->name, ivar->name_length + 1, ivar->hash_value, (void **) &zvalue, sizeof(zval *), NULL); } else if(ivar->flags & QB_VARIABLE_CLASS_INSTANCE) { zval *container = scope->object; zval *name = qb_string_to_zval(ivar->name, ivar->name_length TSRMLS_CC); Z_OBJ_WRITE_PROP(container, name, zvalue); } } } if(!p_zvalue && zvalue) { // if p_zvalue isn't null, then something else has put a refcount // on the zval (and we didn't increment it earlier) zval_ptr_dtor(&zvalue); } ivar->value_pointer = NULL; ivar->value = NULL; ivar->flags &= ~QB_VARIABLE_IMPORTED; } return result; }
static int32_t qb_transfer_value_to_import_source(qb_interpreter_context *cxt, qb_variable *ivar, qb_import_scope *scope) { int32_t result = TRUE; if(ivar->flags & QB_VARIABLE_IMPORTED) { USE_TSRM if(!READ_ONLY(ivar->address)) { zval *zvalue; if(ivar->value_pointer) { zvalue = *ivar->value_pointer; } else { zvalue = ivar->value; // separate the zval first, since we're modifying it SEPARATE_ZVAL_TO_MAKE_IS_REF(&zvalue); } if(!zvalue) { ALLOC_INIT_ZVAL(zvalue); if(ivar->value_pointer) { *ivar->value_pointer = zvalue; } } if(!qb_transfer_value_to_zval(scope->storage, ivar->address, zvalue)) { uint32_t line_id = qb_get_zend_line_id(TSRMLS_C); qb_set_exception_line_id(line_id TSRMLS_CC); result = FALSE; } if(!ivar->value_pointer) { if(ivar->flags & QB_VARIABLE_GLOBAL) { zend_hash_quick_update(&EG(symbol_table), ivar->name, ivar->name_length + 1, ivar->hash_value, (void **) &zvalue, sizeof(zval *), NULL); } else if(ivar->flags & QB_VARIABLE_CLASS_INSTANCE) { zval *container = scope->zend_object; zval *name = qb_string_to_zval(ivar->name, ivar->name_length TSRMLS_CC); Z_OBJ_WRITE_PROP(container, name, zvalue); zval_ptr_dtor(&zvalue); } } ivar->value_pointer = NULL; ivar->value = NULL; } ivar->flags &= ~QB_VARIABLE_IMPORTED; }