/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Daniel Cowgill | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ /* $Id: apc_zend.c,v 3.14 2007/04/02 22:57:10 rasmus Exp $ */ #include "apc_zend.h" #include "apc_globals.h" void* apc_php_malloc(size_t n) { return emalloc(n); } void apc_php_free(void* p) { efree(p); } #ifndef ZEND_VM_KIND_CALL /* Not currently defined by any ZE version */ # define ZEND_VM_KIND_CALL 1 #endif #ifndef ZEND_VM_KIND /* Indicates PHP < 5.1 */ # define ZEND_VM_KIND ZEND_VM_KIND_CALL #endif #if defined(ZEND_ENGINE_2) && (ZEND_VM_KIND == ZEND_VM_KIND_CALL) # define APC_OPCODE_OVERRIDE #endif #ifdef APC_OPCODE_OVERRIDE #ifdef ZEND_ENGINE_2_1 /* Taken from Zend/zend_vm_execute.h */ #define _CONST_CODE 0 #define _TMP_CODE 1 #define _VAR_CODE 2 #define _UNUSED_CODE 3 #define _CV_CODE 4 static inline int _apc_opcode_handler_decode(zend_op *opline) { static const int apc_vm_decode[] = { _UNUSED_CODE, /* 0 */ _CONST_CODE, /* 1 = IS_CONST */ _TMP_CODE, /* 2 = IS_TMP_VAR */ _UNUSED_CODE, /* 3 */ _VAR_CODE, /* 4 = IS_VAR */ _UNUSED_CODE, /* 5 */ _UNUSED_CODE, /* 6 */ _UNUSED_CODE, /* 7 */ _UNUSED_CODE, /* 8 = IS_UNUSED */ _UNUSED_CODE, /* 9 */ _UNUSED_CODE, /* 10 */ _UNUSED_CODE, /* 11 */ _UNUSED_CODE, /* 12 */ _UNUSED_CODE, /* 13 */ _UNUSED_CODE, /* 14 */ _UNUSED_CODE, /* 15 */ _CV_CODE /* 16 = IS_CV */ }; return (opline->opcode * 25) + (apc_vm_decode[opline->op1.op_type] * 5) + apc_vm_decode[opline->op2.op_type]; } # define APC_ZEND_OPLINE zend_op *opline = execute_data->opline; # define APC_OPCODE_HANDLER_DECODE(opline) _apc_opcode_handler_decode(opline) # if PHP_MAJOR_VERSION >= 6 # define APC_OPCODE_HANDLER_COUNT ((25 * 152) + 1) # else # define APC_OPCODE_HANDLER_COUNT ((25 * 151) + 1) # endif # define APC_REPLACE_OPCODE(opname) { int i; for(i = 0; i < 25; i++) if (zend_opcode_handlers[(opname*25) + i]) zend_opcode_handlers[(opname*25) + i] = apc_op_##opname; } #else /* ZE2.0 */ # define APC_ZEND_ONLINE # define APC_OPCODE_HANDLER_DECODE(opline) (opline->opcode) # define APC_OPCODE_HANDLER_COUNT 512 # define APC_REPLACE_OPCODE(opname) zend_opcode_handlers[opname] = apc_op_##opname; #endif static opcode_handler_t *apc_original_opcode_handlers; static opcode_handler_t apc_opcode_handlers[APC_OPCODE_HANDLER_COUNT]; #define APC_EX_T(offset) (*(temp_variable *)((char*)execute_data->Ts + offset)) static zval *apc_get_zval_ptr(znode *node, zval **freeval, zend_execute_data *execute_data TSRMLS_DC) { *freeval = NULL; switch (node->op_type) { case IS_CONST: return &(node->u.constant); case IS_VAR: return APC_EX_T(node->u.var).var.ptr; case IS_TMP_VAR: return (*freeval = &APC_EX_T(node->u.var).tmp_var); #ifdef ZEND_ENGINE_2_1 case IS_CV: { zval ***ret = &execute_data->CVs[node->u.var]; if (!*ret) { zend_compiled_variable *cv = &EG(active_op_array)->vars[node->u.var]; if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void**)ret)==FAILURE) { apc_nprint("Undefined variable: %s", cv->name); return &EG(uninitialized_zval); } } return **ret; } #endif case IS_UNUSED: default: return NULL; } } static int apc_op_ZEND_INCLUDE_OR_EVAL(ZEND_OPCODE_HANDLER_ARGS) { APC_ZEND_OPLINE zval *freeop1 = NULL; zval *inc_filename = NULL, tmp_inc_filename; char realpath[MAXPATHLEN]; php_stream_wrapper *wrapper; char *path_for_open; int ret = 0; #ifdef ZEND_ENGINE_2 apc_opflags_t* flags = NULL; #endif if (Z_LVAL(opline->op2.u.constant) != ZEND_INCLUDE_ONCE && Z_LVAL(opline->op2.u.constant) != ZEND_REQUIRE_ONCE) { return apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } inc_filename = apc_get_zval_ptr(&opline->op1, &freeop1, execute_data TSRMLS_CC); if (Z_TYPE_P(inc_filename) != IS_STRING) { tmp_inc_filename = *inc_filename; zval_copy_ctor(&tmp_inc_filename); convert_to_string(&tmp_inc_filename); inc_filename = &tmp_inc_filename; } wrapper = php_stream_locate_url_wrapper(Z_STRVAL_P(inc_filename), &path_for_open, 0 TSRMLS_CC); if (wrapper != &php_plain_files_wrapper || !IS_ABSOLUTE_PATH(path_for_open, strlen(path_for_open)) || !expand_filepath(path_for_open, realpath TSRMLS_CC)) { /* Fallback to original handler */ if (inc_filename == &tmp_inc_filename) { zval_dtor(&tmp_inc_filename); } return apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } if (zend_hash_exists(&EG(included_files), realpath, strlen(realpath) + 1)) { if (!(opline->result.u.EA.type & EXT_TYPE_UNUSED)) { ALLOC_INIT_ZVAL(APC_EX_T(opline->result.u.var).var.ptr); ZVAL_TRUE(APC_EX_T(opline->result.u.var).var.ptr); } if (inc_filename == &tmp_inc_filename) { zval_dtor(&tmp_inc_filename); } if (freeop1) { zval_dtor(freeop1); } execute_data->opline++; return 0; } if (inc_filename == &tmp_inc_filename) { zval_dtor(&tmp_inc_filename); } if(APCG(reserved_offset) != -1) { /* Insanity alert: look into apc_compile.c for why a void** is cast to a apc_opflags_t* */ flags = (apc_opflags_t*) & (execute_data->op_array->reserved[APCG(reserved_offset)]); } #ifdef ZEND_ENGINE_2 if(flags && flags->deep_copy == 1) { /* Since the op array is a local copy, we can cheat our way through the file inclusion by temporarily * changing the op to a plain require/include, calling its handler and finally restoring the opcode. */ Z_LVAL(opline->op2.u.constant) = (Z_LVAL(opline->op2.u.constant) == ZEND_INCLUDE_ONCE) ? ZEND_INCLUDE : ZEND_REQUIRE; ret = apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); Z_LVAL(opline->op2.u.constant) = (Z_LVAL(opline->op2.u.constant) == ZEND_INCLUDE) ? ZEND_INCLUDE_ONCE : ZEND_REQUIRE_ONCE; #else if(0) { /* do nothing, have nothing, be nothing */ #endif } else { ret = apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } return ret; } void apc_zend_init(TSRMLS_D) { zend_extension dummy_ext; #ifdef ZEND_ENGINE_2 APCG(reserved_offset) = zend_get_resource_handle(&dummy_ext); assert(APCG(reserved_offset) == dummy_ext.resource_number); assert(APCG(reserved_offset) != -1); assert(sizeof(apc_opflags_t) <= sizeof(void*)); #endif if (!APCG(include_once)) { /* If we're not overriding the INCLUDE_OR_EVAL handler, then just skip this malarkey */ return; } memcpy(apc_opcode_handlers, zend_opcode_handlers, sizeof(apc_opcode_handlers)); /* 5.0 exposes zend_opcode_handlers differently than 5.1 and later */ #ifdef ZEND_ENGINE_2_1 apc_original_opcode_handlers = zend_opcode_handlers; zend_opcode_handlers = apc_opcode_handlers; #else apc_original_opcode_handlers = apc_opcode_handlers; #endif APC_REPLACE_OPCODE(ZEND_INCLUDE_OR_EVAL); } void apc_zend_shutdown(TSRMLS_D) { if (!APCG(include_once)) { /* Nothing changed, nothing to restore */ return; } #ifdef ZEND_ENGINE_2_1 zend_opcode_handlers = apc_original_opcode_handlers; #else memcpy(zend_opcode_handlers, apc_original_opcode_handlers, sizeof(apc_opcode_handlers)); #endif } #else /* Opcode Overrides unavailable */ void apc_zend_init(TSRMLS_D) { } void apc_zend_shutdown(TSRMLS_D) { } #endif /* APC_OPCODE_OVERRIDE */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: expandtab sw=4 ts=4 sts=4 */