int uopz_class_constant_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */ if (EX(opline)->op1_type == IS_CONST) { zval *name = EX_CONSTANT(EX(opline)->op1); zend_string *key = Z_STR_P(name); zval *mock = NULL; zend_class_entry *poser = NULL; key = zend_string_tolower(key); if ((mock = zend_hash_find(&UOPZ(mocks), key))) { if (Z_TYPE_P(mock) == IS_OBJECT) { poser = Z_OBJCE_P(mock); } else poser = zend_lookup_class(Z_STR_P(mock)); if (poser) { CACHE_PTR(Z_CACHE_SLOT_P(name), poser); } } zend_string_release(key); } CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)), NULL); if (uopz_fetch_class_constant_handler) { return uopz_fetch_class_constant_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); } return ZEND_USER_OPCODE_DISPATCH; } /* }}} */
int uopz_constant_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */ #if PHP_VERSION_ID >= 70100 if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)))) { CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)), NULL); } #else if (EX(opline)->op1_type == IS_UNUSED) { if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)))) { CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)), NULL); } } else { zend_string *key = NULL; zval *mock = NULL; zend_class_entry *poser = NULL; if (EX(opline)->op1_type == IS_CONST) { key = zend_string_tolower(Z_STR_P(EX_CONSTANT(EX(opline)->op1))); if ((mock = zend_hash_find(&UOPZ(mocks), key))) { if (Z_TYPE_P(mock) == IS_OBJECT) { poser = Z_OBJCE_P(mock); } else poser = zend_lookup_class(Z_STR_P(mock)); CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op1)), poser); } if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)))) { CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)), NULL); } zend_string_release(key); } else { key = zend_string_tolower(Z_CE_P(EX_VAR(EX(opline)->op1.var))->name); if ((mock = zend_hash_find(&UOPZ(mocks), key))) { if (Z_TYPE_P(mock) == IS_OBJECT) { poser = Z_OBJCE_P(mock); } else poser = zend_lookup_class(Z_STR_P(mock)); Z_CE_P(EX_VAR(EX(opline)->op1.var)) = poser; } CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)), Z_CE_P(EX_VAR(EX(opline)->op1.var)), NULL); zend_string_release(key); } } #endif if (uopz_fetch_constant_handler) { return uopz_fetch_constant_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); } return ZEND_USER_OPCODE_DISPATCH; } /* }}} */
static zval *get_zval_ptr_safe( int op_type, const znode_op *node, const zend_execute_data *execute_data ) { #ifdef ZEND_ENGINE_3 switch (op_type) { case IS_CONST: return EX_CONSTANT(*node); case IS_CV: case IS_TMP_VAR: case IS_VAR: { zval *zv = EX_VAR(node->var); ZVAL_DEREF(zv); return !Z_ISUNDEF_P(zv) ? zv : NULL; } default: return NULL; } #else switch (op_type) { case IS_CONST: return node->zv; case IS_TMP_VAR: return &SO_EX_T(node->var).tmp_var; case IS_VAR: return SO_EX_T(node->var).var.ptr; case IS_CV: { zval **tmp = SO_EX_CV(node->constant); return tmp ? *tmp : NULL; } default: return NULL; } #endif }
int uopz_add_class_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */ zval *name = EX_CONSTANT(EX(opline)->op2); zend_string *key = zend_string_tolower(Z_STR_P(name)); zval *mock = NULL; if ((mock = zend_hash_find(&UOPZ(mocks), key))) { if (Z_TYPE_P(mock) == IS_STRING) { zend_class_entry *ce = zend_lookup_class(Z_STR_P(mock)); if (ce) { CACHE_PTR(Z_CACHE_SLOT_P(name), ce); } } else { CACHE_PTR(Z_CACHE_SLOT_P(name), Z_OBJCE_P(mock)); } } zend_string_release(key); if (uopz_add_trait_handler || uopz_add_interface_handler) { switch (EX(opline)->opcode) { case ZEND_ADD_INTERFACE: return uopz_add_interface_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); case ZEND_ADD_TRAIT: return uopz_add_trait_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); } } return ZEND_USER_OPCODE_DISPATCH; } /* }}} */
/* {{{ */ static int php_memoize_return(zend_execute_data *execute_data) { zend_long ttl = 0; const zend_function *fbc = EX(func); if (MG(ini.enabled) && php_memoize_is_memoizing(fbc, &ttl)) { zend_string *key = php_memoize_key( &EX(This), fbc, EX_NUM_ARGS(), EX_VAR_NUM(0)); if (key) { zval *return_value; if (EX(opline)->op1_type & IS_CONST) { return_value = EX_CONSTANT(EX(opline)->op1); } else { return_value = EX_VAR(EX(opline)->op1.var); } apc_cache_store(php_memoize_cache, key, return_value, ttl, 1); if (EG(exception)) { zend_clear_exception(); } zend_string_release(key); } } if (zend_return_function) { return zend_return_function(execute_data); } return ZEND_USER_OPCODE_DISPATCH; } /* }}} */
static int coro_exit_handler(zend_execute_data *execute_data) { zval ex; zend_object *obj; zend_long flags = 0; if (sw_get_current_cid() != -1) { flags |= SW_EXIT_IN_COROUTINE; } if (SwooleG.serv && SwooleG.serv->gs->start) { flags |= SW_EXIT_IN_SERVER; } if (flags) { const zend_op *opline = EX(opline); zval _exit_status; zval *exit_status = NULL; if (opline->op1_type != IS_UNUSED) { if (opline->op1_type == IS_CONST) { // see: https://github.com/php/php-src/commit/e70618aff6f447a298605d07648f2ce9e5a284f5 #ifdef EX_CONSTANT exit_status = EX_CONSTANT(opline->op1); #else exit_status = RT_CONSTANT(opline, opline->op1); #endif } else { exit_status = EX_VAR(opline->op1.var); } if (Z_ISREF_P(exit_status)) { exit_status = Z_REFVAL_P(exit_status); } } else { exit_status = &_exit_status; ZVAL_NULL(exit_status); } obj = zend_throw_error_exception(swoole_exit_exception_class_entry_ptr, "swoole exit.", 0, E_ERROR TSRMLS_CC); ZVAL_OBJ(&ex, obj); zend_update_property_long(swoole_exit_exception_class_entry_ptr, &ex, ZEND_STRL("flags"), flags); Z_TRY_ADDREF_P(exit_status); zend_update_property(swoole_exit_exception_class_entry_ptr, &ex, ZEND_STRL("status"), exit_status); } return ZEND_USER_OPCODE_DISPATCH; }
static zval *smd_get_zval_ptr(zend_execute_data *execute_data, int op_type, znode_op op, zend_free_op *should_free, int type, int force_ret) /* {{{ */ { if (op_type & (IS_TMP_VAR|IS_VAR)) { return smd_get_zval_ptr_tmpvar(execute_data, op.var, should_free); } else { if (op_type == IS_CONST) { return EX_CONSTANT(op); } else if (op_type == IS_CV) { return smd_get_zval_ptr_cv(execute_data, op.var, type, force_ret); } else { return NULL; } } } /* }}} */
int uopz_no_exit_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */ if (UOPZ(exit)) { if (uopz_exit_handler) return uopz_exit_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); return ZEND_USER_OPCODE_DISPATCH; } if (EX(opline)->op1_type != IS_UNUSED) { zval *estatus; if (EX(opline)->op1_type == IS_CONST) { estatus = EX_CONSTANT(EX(opline)->op1); } else estatus = EX_VAR(EX(opline)->op1.var); if (Z_ISREF_P(estatus)) { estatus = Z_REFVAL_P(estatus); } if (Z_TYPE_P(estatus) == IS_LONG) { EG(exit_status) = Z_LVAL_P(estatus); } else EG(exit_status) = 0; ZVAL_COPY(&UOPZ(estatus), estatus); } if (EX(opline) < &EX(func)->op_array.opcodes[EX(func)->op_array.last - 1]) { EX(opline)++; while (EX(opline)->opcode == ZEND_EXT_STMT) { EX(opline)++; } return ZEND_USER_OPCODE_CONTINUE; } else { return ZEND_USER_OPCODE_RETURN; } } /* }}} */
int uopz_fetch_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */ zval *name = NULL; zend_string *key = NULL; int UOPZ_VM_ACTION = ZEND_USER_OPCODE_DISPATCH; do { if (EX(opline)->op2_type == IS_UNUSED) { break; } if (EX(opline)->op2_type == IS_CONST) { name = EX_CONSTANT(EX(opline)->op2); if (name) { key = Z_STR_P(name); } } else if (EX(opline)->op2_type != IS_UNUSED) { name = EX_VAR(EX(opline)->op2.var); if (Z_TYPE_P(name) == IS_STRING) { key = Z_STR_P(name); } else if (Z_TYPE_P(name) == IS_OBJECT) { key = Z_OBJCE_P(name)->name; } else { } } if (key) { zval *mock = NULL; zend_class_entry *ce = NULL; zend_string *lookup = zend_string_tolower(key); if (UNEXPECTED((mock = zend_hash_find(&UOPZ(mocks), lookup)))) { switch (Z_TYPE_P(mock)) { case IS_OBJECT: ce = Z_OBJCE_P(mock); break; case IS_STRING: ce = zend_lookup_class(Z_STR_P(mock)); break; } if (ce) { if (EX(opline)->op2_type == IS_CONST) { CACHE_PTR(Z_CACHE_SLOT_P(name), ce); } Z_CE_P(EX_VAR(EX(opline)->result.var)) = ce; UOPZ_VM_ACTION = ZEND_USER_OPCODE_CONTINUE; } } zend_string_release(lookup); } } while(0); if (UOPZ_VM_ACTION == ZEND_USER_OPCODE_CONTINUE) { EX(opline) = EX(opline) + 1; } else { if (uopz_fetch_class_handler) { return uopz_fetch_class_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); } } return UOPZ_VM_ACTION; } /* }}} */
int uopz_mock_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */ int UOPZ_VM_ACTION = ZEND_USER_OPCODE_DISPATCH; zend_string *key; zval *mock = NULL; zend_class_entry *ce; if (EX(opline)->op1_type == IS_CONST) { ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op1))); if (UNEXPECTED(ce == NULL)) { key = Z_STR_P(EX_CONSTANT(EX(opline)->op1)); } else { key = ce->name; } key = zend_string_tolower(key); } else if(EX(opline)->op1_type == IS_UNUSED) { ce = zend_fetch_class(NULL, EX(opline)->op1.num); if (UNEXPECTED(ce == NULL)) { return UOPZ_VM_ACTION; } key = zend_string_tolower(ce->name); } else { key = zend_string_tolower( Z_CE_P(EX_VAR(EX(opline)->op1.var))->name); } if (UNEXPECTED((mock = zend_hash_find(&UOPZ(mocks), key)))) { switch (Z_TYPE_P(mock)) { case IS_OBJECT: ZVAL_COPY( EX_VAR(EX(opline)->result.var), mock); #if PHP_VERSION_ID < 70100 EX(opline) = OP_JMP_ADDR(EX(opline), EX(opline)->op2); #else if (EX(opline)->extended_value == 0 && (EX(opline)+1)->opcode == ZEND_DO_FCALL) { EX(opline) += 2; } #endif UOPZ_VM_ACTION = ZEND_USER_OPCODE_CONTINUE; break; case IS_STRING: ce = zend_lookup_class(Z_STR_P(mock)); if (EXPECTED(ce)) { if (EX(opline)->op1_type == IS_CONST) { CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op1)), ce); } else if (EX(opline)->op1_type != IS_UNUSED) { Z_CE_P(EX_VAR(EX(opline)->op1.var)) = ce; } else { /* oh dear, can't do what is requested */ } } break; } } zend_string_release(key); if (UOPZ_VM_ACTION == ZEND_USER_OPCODE_DISPATCH) { if (uopz_new_handler) { return uopz_new_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); } } return UOPZ_VM_ACTION; } /* }}} */
int uopz_call_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */ switch (EX(opline)->opcode) { case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_FCALL: case ZEND_INIT_NS_FCALL_BY_NAME: { zval *function_name = EX_CONSTANT(EX(opline)->op2); CACHE_PTR(Z_CACHE_SLOT_P(function_name), NULL); } break; case ZEND_INIT_METHOD_CALL: { if (EX(opline)->op2_type == IS_CONST) { zval *function_name = EX_CONSTANT(EX(opline)->op2); CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), NULL, NULL); } } break; case ZEND_INIT_STATIC_METHOD_CALL: { zend_class_entry *ce; zval *mock; zend_string *key = NULL; if (EX(opline)->op1_type == IS_CONST) { key = zend_string_tolower(Z_STR_P(EX_CONSTANT(EX(opline)->op1))); } else if (EX(opline)->op1_type != IS_UNUSED) { ce = Z_CE_P(EX_VAR(EX(opline)->op1.var)); if (!ce) { break; } key = zend_string_tolower(ce->name); } if (key && (mock = zend_hash_find(&UOPZ(mocks), key))) { zend_class_entry *poser; if (Z_TYPE_P(mock) == IS_STRING) { poser = zend_lookup_class(Z_STR_P(mock)); if (!poser) { break; } } else poser = Z_OBJCE_P(mock); if (EX(opline)->op1_type == IS_CONST) { CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op1)), poser); } else { Z_CE_P(EX_VAR(EX(opline)->op1.var)) = poser; } } if (key && EX(opline)->op2_type == IS_CONST) { zval *function_name = EX_CONSTANT(EX(opline)->op2); if (EX(opline)->op1_type == IS_CONST) { CACHE_PTR(Z_CACHE_SLOT_P(function_name), NULL); } else { CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), NULL, NULL); } } if (key) { zend_string_release(key); } } break; } switch (EX(opline)->opcode) { case ZEND_INIT_FCALL_BY_NAME: if (uopz_init_fcall_by_name_handler) return uopz_init_fcall_by_name_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); case ZEND_INIT_FCALL: if (uopz_init_fcall_handler) return uopz_init_fcall_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); case ZEND_INIT_NS_FCALL_BY_NAME: if (uopz_init_ns_fcall_by_name_handler) return uopz_init_ns_fcall_by_name_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); case ZEND_INIT_METHOD_CALL: if (uopz_init_method_call_handler) return uopz_init_method_call_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); case ZEND_INIT_STATIC_METHOD_CALL: if (uopz_init_static_method_call_handler) return uopz_init_static_method_call_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); } return ZEND_USER_OPCODE_DISPATCH; } /* }}} */