2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2008 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Daniel Cowgill <dcowgill@communityconnect.com> |
16 +----------------------------------------------------------------------+
18 This software was contributed to PHP by Community Connect Inc. in 2002
19 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
20 Future revisions and derivatives of this source code must acknowledge
21 Community Connect Inc. as the original contributor of this module by
22 leaving this note intact in the source code.
24 All other licensing and usage conditions are those of the PHP Group.
28 /* $Id: apc_zend.c,v 3.14.2.1 2008/05/11 18:57:00 rasmus Exp $ */
31 #include "apc_globals.h"
33 void* apc_php_malloc(size_t n)
38 void apc_php_free(void* p)
43 #ifndef ZEND_VM_KIND_CALL /* Not currently defined by any ZE version */
44 # define ZEND_VM_KIND_CALL 1
47 #ifndef ZEND_VM_KIND /* Indicates PHP < 5.1 */
48 # define ZEND_VM_KIND ZEND_VM_KIND_CALL
51 #if defined(ZEND_ENGINE_2) && (ZEND_VM_KIND == ZEND_VM_KIND_CALL)
52 # define APC_OPCODE_OVERRIDE
55 #ifdef APC_OPCODE_OVERRIDE
57 #ifdef ZEND_ENGINE_2_1
58 /* Taken from Zend/zend_vm_execute.h */
62 #define _UNUSED_CODE 3
64 static inline int _apc_opcode_handler_decode(zend_op *opline)
66 static const int apc_vm_decode[] = {
68 _CONST_CODE, /* 1 = IS_CONST */
69 _TMP_CODE, /* 2 = IS_TMP_VAR */
71 _VAR_CODE, /* 4 = IS_VAR */
75 _UNUSED_CODE, /* 8 = IS_UNUSED */
77 _UNUSED_CODE, /* 10 */
78 _UNUSED_CODE, /* 11 */
79 _UNUSED_CODE, /* 12 */
80 _UNUSED_CODE, /* 13 */
81 _UNUSED_CODE, /* 14 */
82 _UNUSED_CODE, /* 15 */
83 _CV_CODE /* 16 = IS_CV */
85 return (opline->opcode * 25) + (apc_vm_decode[opline->op1.op_type] * 5) + apc_vm_decode[opline->op2.op_type];
88 # define APC_ZEND_OPLINE zend_op *opline = execute_data->opline;
89 # define APC_OPCODE_HANDLER_DECODE(opline) _apc_opcode_handler_decode(opline)
90 # if PHP_MAJOR_VERSION >= 6
91 # define APC_OPCODE_HANDLER_COUNT ((25 * 152) + 1)
93 # define APC_OPCODE_HANDLER_COUNT ((25 * 151) + 1)
95 # 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; }
98 # define APC_ZEND_ONLINE
99 # define APC_OPCODE_HANDLER_DECODE(opline) (opline->opcode)
100 # define APC_OPCODE_HANDLER_COUNT 512
101 # define APC_REPLACE_OPCODE(opname) zend_opcode_handlers[opname] = apc_op_##opname;
104 static opcode_handler_t *apc_original_opcode_handlers;
105 static opcode_handler_t apc_opcode_handlers[APC_OPCODE_HANDLER_COUNT];
107 #define APC_EX_T(offset) (*(temp_variable *)((char*)execute_data->Ts + offset))
109 static zval *apc_get_zval_ptr(znode *node, zval **freeval, zend_execute_data *execute_data TSRMLS_DC)
113 switch (node->op_type) {
115 return &(node->u.constant);
117 return APC_EX_T(node->u.var).var.ptr;
119 return (*freeval = &APC_EX_T(node->u.var).tmp_var);
120 #ifdef ZEND_ENGINE_2_1
123 zval ***ret = &execute_data->CVs[node->u.var];
126 zend_compiled_variable *cv = &EG(active_op_array)->vars[node->u.var];
128 if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void**)ret)==FAILURE) {
129 apc_nprint("Undefined variable: %s", cv->name);
130 return &EG(uninitialized_zval);
142 static int apc_op_ZEND_INCLUDE_OR_EVAL(ZEND_OPCODE_HANDLER_ARGS)
145 zval *freeop1 = NULL;
146 zval *inc_filename = NULL, tmp_inc_filename;
147 char realpath[MAXPATHLEN];
148 php_stream_wrapper *wrapper;
152 apc_opflags_t* flags = NULL;
155 if (Z_LVAL(opline->op2.u.constant) != ZEND_INCLUDE_ONCE &&
156 Z_LVAL(opline->op2.u.constant) != ZEND_REQUIRE_ONCE) {
157 return apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
160 inc_filename = apc_get_zval_ptr(&opline->op1, &freeop1, execute_data TSRMLS_CC);
161 if (Z_TYPE_P(inc_filename) != IS_STRING) {
162 tmp_inc_filename = *inc_filename;
163 zval_copy_ctor(&tmp_inc_filename);
164 convert_to_string(&tmp_inc_filename);
165 inc_filename = &tmp_inc_filename;
168 wrapper = php_stream_locate_url_wrapper(Z_STRVAL_P(inc_filename), &path_for_open, 0 TSRMLS_CC);
169 if (wrapper != &php_plain_files_wrapper ||
170 !IS_ABSOLUTE_PATH(path_for_open, strlen(path_for_open)) ||
171 !expand_filepath(path_for_open, realpath TSRMLS_CC)) {
172 /* Fallback to original handler */
173 if (inc_filename == &tmp_inc_filename) {
174 zval_dtor(&tmp_inc_filename);
176 return apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
179 if (zend_hash_exists(&EG(included_files), realpath, strlen(realpath) + 1)) {
180 if (!(opline->result.u.EA.type & EXT_TYPE_UNUSED)) {
181 ALLOC_INIT_ZVAL(APC_EX_T(opline->result.u.var).var.ptr);
182 ZVAL_TRUE(APC_EX_T(opline->result.u.var).var.ptr);
184 if (inc_filename == &tmp_inc_filename) {
185 zval_dtor(&tmp_inc_filename);
190 execute_data->opline++;
194 if (inc_filename == &tmp_inc_filename) {
195 zval_dtor(&tmp_inc_filename);
198 if(APCG(reserved_offset) != -1) {
199 /* Insanity alert: look into apc_compile.c for why a void** is cast to a apc_opflags_t* */
200 flags = (apc_opflags_t*) & (execute_data->op_array->reserved[APCG(reserved_offset)]);
204 if(flags && flags->deep_copy == 1) {
205 /* Since the op array is a local copy, we can cheat our way through the file inclusion by temporarily
206 * changing the op to a plain require/include, calling its handler and finally restoring the opcode.
208 Z_LVAL(opline->op2.u.constant) = (Z_LVAL(opline->op2.u.constant) == ZEND_INCLUDE_ONCE) ? ZEND_INCLUDE : ZEND_REQUIRE;
209 ret = apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
210 Z_LVAL(opline->op2.u.constant) = (Z_LVAL(opline->op2.u.constant) == ZEND_INCLUDE) ? ZEND_INCLUDE_ONCE : ZEND_REQUIRE_ONCE;
213 /* do nothing, have nothing, be nothing */
216 ret = apc_original_opcode_handlers[APC_OPCODE_HANDLER_DECODE(opline)](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
222 void apc_zend_init(TSRMLS_D)
224 zend_extension dummy_ext;
226 APCG(reserved_offset) = zend_get_resource_handle(&dummy_ext);
227 assert(APCG(reserved_offset) == dummy_ext.resource_number);
228 assert(APCG(reserved_offset) != -1);
229 assert(sizeof(apc_opflags_t) <= sizeof(void*));
231 if (!APCG(include_once)) {
232 /* If we're not overriding the INCLUDE_OR_EVAL handler, then just skip this malarkey */
236 memcpy(apc_opcode_handlers, zend_opcode_handlers, sizeof(apc_opcode_handlers));
238 /* 5.0 exposes zend_opcode_handlers differently than 5.1 and later */
239 #ifdef ZEND_ENGINE_2_1
240 apc_original_opcode_handlers = zend_opcode_handlers;
241 zend_opcode_handlers = apc_opcode_handlers;
243 apc_original_opcode_handlers = apc_opcode_handlers;
246 APC_REPLACE_OPCODE(ZEND_INCLUDE_OR_EVAL);
249 void apc_zend_shutdown(TSRMLS_D)
251 if (!APCG(include_once)) {
252 /* Nothing changed, nothing to restore */
256 #ifdef ZEND_ENGINE_2_1
257 zend_opcode_handlers = apc_original_opcode_handlers;
259 memcpy(zend_opcode_handlers, apc_original_opcode_handlers, sizeof(apc_opcode_handlers));
263 #else /* Opcode Overrides unavailable */
265 void apc_zend_init(TSRMLS_D) { }
266 void apc_zend_shutdown(TSRMLS_D) { }
268 #endif /* APC_OPCODE_OVERRIDE */
275 * vim600: expandtab sw=4 ts=4 sts=4 fdm=marker
276 * vim<600: expandtab sw=4 ts=4 sts=4