X-Git-Url: http://ftp.carnet.hr/carnet-debian/scm?p=php5-apc.git;a=blobdiff_plain;f=apc_zend.c;fp=apc_zend.c;h=6cd21be0e4bfdcaa91bd1938e0b282358b9f671d;hp=0000000000000000000000000000000000000000;hb=3682e0a7a26931aabca2b6e54eb08efd7dc0430b;hpb=575ce08215526bb71a967d69d601e77e1afbcd11 diff --git a/apc_zend.c b/apc_zend.c new file mode 100644 index 0000000..6cd21be --- /dev/null +++ b/apc_zend.c @@ -0,0 +1,277 @@ +/* + +----------------------------------------------------------------------+ + | 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 + */