source: trunk/xcache.c @ 1177

Last change on this file since 1177 was 1177, checked in by moo, 22 months ago

better compatibility using exception list instead of empty list to startup incompatible extension

  • Property svn:eol-style set to native
File size: 23.3 KB
RevLine 
[1]1/* {{{ macros */
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5
6#include <signal.h>
7
8#include "xcache.h"
[993]9
10#ifdef HAVE_XCACHE_OPTIMIZER
[1003]11#   include "mod_optimizer/xc_optimizer.h"
[993]12#endif
[1040]13#ifdef HAVE_XCACHE_CACHER
14#   include "mod_cacher/xc_cacher.h"
15#endif
[993]16#ifdef HAVE_XCACHE_COVERAGER
[1003]17#   include "mod_coverager/xc_coverager.h"
[993]18#endif
19#ifdef HAVE_XCACHE_DISASSEMBLER
[1003]20#   include "mod_disassembler/xc_disassembler.h"
[993]21#endif
22
[1]23#include "xcache_globals.h"
[1026]24#include "xcache/xc_extension.h"
25#include "xcache/xc_ini.h"
[987]26#include "xcache/xc_const_string.h"
27#include "xcache/xc_opcode_spec.h"
28#include "xcache/xc_utils.h"
[982]29#include "util/xc_stack.h"
[1]30
[1026]31#include "php.h"
32#include "ext/standard/info.h"
33#include "ext/standard/php_string.h"
[1131]34#include "SAPI.h"
[1]35/* }}} */
36
37/* {{{ globals */
38static char *xc_coredump_dir = NULL;
[979]39static zend_bool xc_disable_on_crash = 0;
[1]40
[403]41static zend_compile_file_t *old_compile_file = NULL;
[1]42
[1040]43zend_bool xc_test = 0;
[1]44
[982]45ZEND_DECLARE_MODULE_GLOBALS(xcache)
[854]46
[1]47/* }}} */
48
[405]49static zend_op_array *xc_check_initial_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
50{
51    XG(initial_compile_file_called) = 1;
[1040]52    return old_compile_file(h, type TSRMLS_CC);
[405]53}
54/* }}} */
[937]55
[1]56/* module helper function */
57static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */
58{
[11]59    typedef struct {
[1]60        const char *prefix;
[20]61        zend_uchar (*getsize)();
[1]62        const char *(*get)(zend_uchar i);
[1133]63    } xc_nameinfo_t;
64    xc_nameinfo_t nameinfos[] = {
[1]65        { "",        xc_get_op_type_count,   xc_get_op_type   },
66        { "",        xc_get_data_type_count, xc_get_data_type },
67        { "",        xc_get_opcode_count,    xc_get_opcode    },
68        { "OPSPEC_", xc_get_op_spec_count,   xc_get_op_spec   },
69        { NULL, NULL, NULL }
70    };
71    int undefdone = 0;
[1134]72    xc_nameinfo_t *p;
[1]73
74    for (p = nameinfos; p->getsize; p ++) {
[1133]75        zend_uchar i, count;
76        char const_name[96];
77        int const_name_len;
78
[20]79        count = p->getsize();
80        for (i = 0; i < count; i ++) {
[1]81            const char *name = p->get(i);
82            if (!name) continue;
83            if (strcmp(name, "UNDEF") == 0) {
84                if (undefdone) continue;
85                undefdone = 1;
86            }
87            const_name_len = snprintf(const_name, sizeof(const_name), "XC_%s%s", p->prefix, name);
88            zend_register_long_constant(const_name, const_name_len+1, i, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
89        }
90    }
91
92    zend_register_long_constant(ZEND_STRS("XC_SIZEOF_TEMP_VARIABLE"), sizeof(temp_variable), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
[119]93    zend_register_stringl_constant(ZEND_STRS("XCACHE_VERSION"), ZEND_STRL(XCACHE_VERSION), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
94    zend_register_stringl_constant(ZEND_STRS("XCACHE_MODULES"), ZEND_STRL(XCACHE_MODULES), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
[1]95    return 0;
96}
97/* }}} */
[92]98/* {{{ PHP_GINIT_FUNCTION(xcache) */
[1050]99#pragma GCC push_options
100#pragma GCC diagnostic ignored "-Wshadow"
101
[92]102#ifdef PHP_GINIT_FUNCTION
[1050]103static PHP_GINIT_FUNCTION(xcache)
[92]104#else
[1050]105static void xc_init_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
[92]106#endif
[1]107{
[1050]108#pragma GCC pop_options
109
[92]110    memset(xcache_globals, 0, sizeof(zend_xcache_globals));
[429]111
[588]112#ifdef HAVE_XCACHE_CONSTANT
[640]113    zend_hash_init_ex(&xcache_globals->internal_constant_table, 1, NULL, (dtor_func_t) xc_zend_constant_dtor, 1, 0);
[588]114#endif
[429]115    zend_hash_init_ex(&xcache_globals->internal_function_table, 1, NULL, NULL, 1, 0);
116    zend_hash_init_ex(&xcache_globals->internal_class_table,    1, NULL, NULL, 1, 0);
[1]117}
118/* }}} */
[92]119/* {{{ PHP_GSHUTDOWN_FUNCTION(xcache) */
120static
121#ifdef PHP_GSHUTDOWN_FUNCTION
122PHP_GSHUTDOWN_FUNCTION(xcache)
123#else
124void xc_shutdown_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
125#endif
[1]126{
[917]127    size_t i;
[1]128
[92]129    if (xcache_globals->php_holds != NULL) {
[1040]130        for (i = 0; i < xcache_globals->php_holds_size; i ++) {
[92]131            xc_stack_destroy(&xcache_globals->php_holds[i]);
[1]132        }
[92]133        free(xcache_globals->php_holds);
134        xcache_globals->php_holds = NULL;
[1040]135        xcache_globals->php_holds_size = 0;
[1]136    }
137
[92]138    if (xcache_globals->var_holds != NULL) {
[1040]139        for (i = 0; i < xcache_globals->var_holds_size; i ++) {
[92]140            xc_stack_destroy(&xcache_globals->var_holds[i]);
[1]141        }
[92]142        free(xcache_globals->var_holds);
143        xcache_globals->var_holds = NULL;
[1040]144        xcache_globals->var_holds_size = 0;
[1]145    }
[344]146
[438]147    if (xcache_globals->internal_table_copied) {
[588]148#ifdef HAVE_XCACHE_CONSTANT
149        zend_hash_destroy(&xcache_globals->internal_constant_table);
150#endif
[435]151        zend_hash_destroy(&xcache_globals->internal_function_table);
152        zend_hash_destroy(&xcache_globals->internal_class_table);
153    }
[1]154}
155/* }}} */
156
[780]157/* {{{ proto int xcache_get_refcount(mixed variable)
[781]158   XCache internal uses only: Get reference count of variable */
[780]159PHP_FUNCTION(xcache_get_refcount)
160{
161    zval *variable;
162    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variable) == FAILURE) {
163        RETURN_NULL();
164    }
165
[798]166    RETURN_LONG(Z_REFCOUNT(*variable));
[780]167}
168/* }}} */
169/* {{{ proto bool xcache_get_isref(mixed variable)
[781]170   XCache internal uses only: Check if variable data is marked referenced */
[1027]171#ifdef ZEND_BEGIN_ARG_INFO_EX
[781]172ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_isref, 0, 0, 1)
173    ZEND_ARG_INFO(1, variable)
174ZEND_END_ARG_INFO()
[1027]175#else
176static unsigned char arginfo_xcache_get_isref[] = { 1, BYREF_FORCE };
177#endif
[781]178
[780]179PHP_FUNCTION(xcache_get_isref)
180{
181    zval *variable;
182    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variable) == FAILURE) {
183        RETURN_NULL();
184    }
185
[798]186    RETURN_BOOL(Z_ISREF(*variable) && Z_REFCOUNT(*variable) >= 3);
[780]187}
188/* }}} */
[532]189#ifdef HAVE_XCACHE_DPRINT
190/* {{{ proto bool  xcache_dprint(mixed value)
191   Prints variable (or value) internal struct (debug only) */
192PHP_FUNCTION(xcache_dprint)
193{
194    zval *value;
195
196    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
197        return;
198    }
199    xc_dprint_zval(value, 0 TSRMLS_CC);
200}
201/* }}} */
202#endif
[9]203/* {{{ proto string xcache_asm(string filename)
204 */
[1]205#ifdef HAVE_XCACHE_ASSEMBLER
206PHP_FUNCTION(xcache_asm)
207{
208}
209#endif
210/* }}} */
[9]211/* {{{ proto string xcache_encode(string filename)
212   Encode php file into XCache opcode encoded format */
[1]213#ifdef HAVE_XCACHE_ENCODER
214PHP_FUNCTION(xcache_encode)
215{
216}
217#endif
218/* }}} */
[9]219/* {{{ proto bool xcache_decode_file(string filename)
220   Decode(load) opcode from XCache encoded format file */
[1]221#ifdef HAVE_XCACHE_DECODER
[9]222PHP_FUNCTION(xcache_decode_file)
[1]223{
224}
225#endif
226/* }}} */
[9]227/* {{{ proto bool xcache_decode_string(string data)
228   Decode(load) opcode from XCache encoded format data */
229#ifdef HAVE_XCACHE_DECODER
230PHP_FUNCTION(xcache_decode_string)
231{
232}
233#endif
234/* }}} */
[1]235/* {{{ xc_call_getter */
236typedef const char *(xc_name_getter_t)(zend_uchar type);
237static void xc_call_getter(xc_name_getter_t getter, int count, INTERNAL_FUNCTION_PARAMETERS)
238{
239    long spec;
240    const char *name;
241
242    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
243        return;
244    }
245    if (spec >= 0 && spec < count) {
[11]246        name = getter((zend_uchar) spec);
[1]247        if (name) {
248            /* RETURN_STRING */
249            int len = strlen(name);
250            return_value->value.str.len = len;
251            return_value->value.str.val = estrndup(name, len);
252            return_value->type = IS_STRING; 
253            return;
254        }
255    }
256    RETURN_NULL();
257}
258/* }}} */
259/* {{{ proto string xcache_get_op_type(int op_type) */
260PHP_FUNCTION(xcache_get_op_type)
261{
262    xc_call_getter(xc_get_op_type, xc_get_op_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
263}
264/* }}} */
265/* {{{ proto string xcache_get_data_type(int type) */
266PHP_FUNCTION(xcache_get_data_type)
267{
268    xc_call_getter(xc_get_data_type, xc_get_data_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
269}
270/* }}} */
271/* {{{ proto string xcache_get_opcode(int opcode) */
272PHP_FUNCTION(xcache_get_opcode)
273{
274    xc_call_getter(xc_get_opcode, xc_get_opcode_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
275}
276/* }}} */
277/* {{{ proto string xcache_get_op_spec(int op_type) */
278PHP_FUNCTION(xcache_get_op_spec)
279{
280    xc_call_getter(xc_get_op_spec, xc_get_op_spec_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
281}
282/* }}} */
283/* {{{ proto string xcache_get_opcode_spec(int opcode) */
284PHP_FUNCTION(xcache_get_opcode_spec)
285{
286    long spec;
287    const xc_opcode_spec_t *opspec;
288
289    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
290        return;
291    }
[17]292    if ((zend_uchar) spec <= xc_get_opcode_spec_count()) {
[11]293        opspec = xc_get_opcode_spec((zend_uchar) spec);
[1]294        if (opspec) {
295            array_init(return_value);
296            add_assoc_long_ex(return_value, ZEND_STRS("ext"), opspec->ext);
297            add_assoc_long_ex(return_value, ZEND_STRS("op1"), opspec->op1);
298            add_assoc_long_ex(return_value, ZEND_STRS("op2"), opspec->op2);
299            add_assoc_long_ex(return_value, ZEND_STRS("res"), opspec->res);
300            return;
301        }
302    }
303    RETURN_NULL();
304}
305/* }}} */
[781]306/* {{{ proto mixed xcache_get_special_value(zval value)
307   XCache internal use only: For decompiler to get static value with type fixed */
[1]308PHP_FUNCTION(xcache_get_special_value)
309{
310    zval *value;
311
312    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
313        return;
314    }
315
[713]316    switch ((Z_TYPE_P(value) & IS_CONSTANT_TYPE_MASK)) {
317    case IS_CONSTANT:
[1]318        *return_value = *value;
319        zval_copy_ctor(return_value);
320        return_value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
[713]321        break;
[1]322
[713]323    case IS_CONSTANT_ARRAY:
[1]324        *return_value = *value;
325        zval_copy_ctor(return_value);
326        return_value->type = IS_ARRAY;
[713]327        break;
328
329    default:
330        RETURN_NULL();
[1]331    }
332}
333/* }}} */
[781]334/* {{{ proto int xcache_get_type(zval value)
335   XCache internal use only for disassembler to get variable type in engine level */
336PHP_FUNCTION(xcache_get_type)
337{
338    zval *value;
339
340    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
341        return;
342    }
343
344    RETURN_LONG(Z_TYPE_P(value));
345}
346/* }}} */
[1]347/* {{{ proto string xcache_coredump(int op_type) */
348PHP_FUNCTION(xcache_coredump)
349{
[9]350    if (xc_test) {
351        raise(SIGSEGV);
352    }
353    else {
354        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.test must be enabled to test xcache_coredump()");
355    }
[1]356}
357/* }}} */
358/* {{{ proto string xcache_is_autoglobal(string name) */
359PHP_FUNCTION(xcache_is_autoglobal)
360{
[860]361    zval *name;
[1]362
[862]363    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
[1]364        return;
365    }
366
[862]367#ifdef IS_UNICODE
368    convert_to_unicode(name);
369#else
370    convert_to_string(name);
371#endif
372
[860]373    RETURN_BOOL(zend_u_hash_exists(CG(auto_globals), UG(unicode), Z_STRVAL_P(name), Z_STRLEN_P(name) + 1));
[1]374}
375/* }}} */
[716]376static zend_function_entry xcache_functions[] = /* {{{ */
[1]377{
378    PHP_FE(xcache_coredump,          NULL)
379#ifdef HAVE_XCACHE_ASSEMBLER
380    PHP_FE(xcache_asm,               NULL)
381#endif
382#ifdef HAVE_XCACHE_ENCODER
383    PHP_FE(xcache_encode,            NULL)
384#endif
385#ifdef HAVE_XCACHE_DECODER
[9]386    PHP_FE(xcache_decode_file,       NULL)
387    PHP_FE(xcache_decode_string,     NULL)
[1]388#endif
389    PHP_FE(xcache_get_special_value, NULL)
[781]390    PHP_FE(xcache_get_type,          NULL)
[1]391    PHP_FE(xcache_get_op_type,       NULL)
392    PHP_FE(xcache_get_data_type,     NULL)
393    PHP_FE(xcache_get_opcode,        NULL)
394    PHP_FE(xcache_get_opcode_spec,   NULL)
395    PHP_FE(xcache_is_autoglobal,     NULL)
[780]396    PHP_FE(xcache_get_refcount,      NULL)
[781]397    PHP_FE(xcache_get_isref,         arginfo_xcache_get_isref)
[532]398#ifdef HAVE_XCACHE_DPRINT
399    PHP_FE(xcache_dprint,            NULL)
400#endif
[983]401    PHP_FE_END
[1]402};
403/* }}} */
404
[914]405#ifdef ZEND_WIN32
406#include "dbghelp.h"
407typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
408        CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
409        CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
410        CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
411        );
412
[915]413static PTOP_LEVEL_EXCEPTION_FILTER oldFilter = NULL;
[914]414static HMODULE dbghelpModule = NULL;
[915]415static char crash_dumpPath[_MAX_PATH] = { 0 };
416static MINIDUMPWRITEDUMP dbghelp_MiniDumpWriteDump = NULL;
[914]417
418static LONG WINAPI miniDumperFilter(struct _EXCEPTION_POINTERS *pExceptionInfo) /* {{{ */
419{
420    HANDLE fileHandle;
[1106]421    LONG ret = EXCEPTION_CONTINUE_SEARCH;
[914]422
423    SetUnhandledExceptionFilter(oldFilter);
424
425    /* create the file */
426    fileHandle = CreateFile(crash_dumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
427
428    if (fileHandle != INVALID_HANDLE_VALUE) {
429        MINIDUMP_EXCEPTION_INFORMATION exceptionInformation;
430        BOOL ok;
431
432        exceptionInformation.ThreadId = GetCurrentThreadId();
433        exceptionInformation.ExceptionPointers = pExceptionInfo;
434        exceptionInformation.ClientPointers = FALSE;
435
436        /* write the dump */
[925]437        ok = dbghelp_MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), fileHandle, MiniDumpNormal|MiniDumpWithDataSegs|MiniDumpWithIndirectlyReferencedMemory, &exceptionInformation, NULL, NULL);
[914]438        CloseHandle(fileHandle);
439        if (ok) {
440            zend_error(E_ERROR, "Saved dump file to '%s'", crash_dumpPath);
[1106]441            ret = EXCEPTION_EXECUTE_HANDLER;
[914]442        }
443        else {
444            zend_error(E_ERROR, "Failed to save dump file to '%s' (error %d)", crash_dumpPath, GetLastError());
445        }
446    }
447    else {
448        zend_error(E_ERROR, "Failed to create dump file '%s' (error %d)", crash_dumpPath, GetLastError());
449    }
450
[1106]451    if (xc_disable_on_crash) {
452        xc_disable_on_crash = 0;
453        xc_cacher_disable();
454    }
455
456    return ret;
[914]457}
458/* }}} */
459
460static void xcache_restore_crash_handler() /* {{{ */
461{
462    if (oldFilter) {
463        SetUnhandledExceptionFilter(oldFilter);
464        oldFilter = NULL;
465    }
466}
467/* }}} */
468static void xcache_init_crash_handler() /* {{{ */
469{
470    /* firstly see if dbghelp.dll is around and has the function we need
471       look next to the EXE first, as the one in System32 might be old
472       (e.g. Windows 2000) */
473    char dbghelpPath[_MAX_PATH];
474
475    if (GetModuleFileName(NULL, dbghelpPath, _MAX_PATH)) {
476        char *slash = strchr(dbghelpPath, '\\');
477        if (slash) {
478            strcpy(slash + 1, "DBGHELP.DLL");
479            dbghelpModule = LoadLibrary(dbghelpPath);
480        }
481    }
482
483    if (!dbghelpModule) {
484        /* load any version we can */
485        dbghelpModule = LoadLibrary("DBGHELP.DLL");
486        if (!dbghelpModule) {
487            zend_error(E_ERROR, "Unable to enable crash dump saver: %s", "DBGHELP.DLL not found");
488            return;
489        }
490    }
491
492    dbghelp_MiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress(dbghelpModule, "MiniDumpWriteDump");
[918]493    if (!dbghelp_MiniDumpWriteDump) {
494        zend_error(E_ERROR, "Unable to enable crash dump saver: %s", "DBGHELP.DLL too old. Get updated dll and put it aside of php_xcache.dll");
[914]495        return;
496    }
497
[923]498#ifdef XCACHE_VERSION_REVISION
499#define REVISION "r" XCACHE_VERSION_REVISION
500#else
501#define REVISION ""
502#endif
[925]503    sprintf(crash_dumpPath, "%s\\php-%s-xcache-%s%s-%lu-%lu.dmp", xc_coredump_dir, zend_get_module_version("standard"), XCACHE_VERSION, REVISION, (unsigned long) time(NULL), (unsigned long) GetCurrentProcessId());
[923]504#undef REVISION
[914]505
506    oldFilter = SetUnhandledExceptionFilter(&miniDumperFilter);
507}
508/* }}} */
509#else
[75]510/* old signal handlers {{{ */
511typedef void (*xc_sighandler_t)(int);
512#define FOREACH_SIG(sig) static xc_sighandler_t old_##sig##_handler = NULL
[982]513#include "util/xc_foreachcoresig.h"
[75]514#undef FOREACH_SIG
515/* }}} */
516static void xcache_signal_handler(int sig);
[914]517static void xcache_restore_crash_handler() /* {{{ */
[1]518{
[75]519#define FOREACH_SIG(sig) do { \
520    if (old_##sig##_handler != xcache_signal_handler) { \
521        signal(sig, old_##sig##_handler); \
522    } \
523    else { \
524        signal(sig, SIG_DFL); \
525    } \
526} while (0)
[982]527#include "util/xc_foreachcoresig.h"
[75]528#undef FOREACH_SIG
529}
530/* }}} */
[914]531static void xcache_init_crash_handler() /* {{{ */
[75]532{
533#define FOREACH_SIG(sig) \
534    old_##sig##_handler = signal(sig, xcache_signal_handler)
[982]535#include "util/xc_foreachcoresig.h"
[75]536#undef FOREACH_SIG
537}
538/* }}} */
539static void xcache_signal_handler(int sig) /* {{{ */
540{
[914]541    xcache_restore_crash_handler();
[1]542    if (xc_coredump_dir && xc_coredump_dir[0]) {
[767]543        if (chdir(xc_coredump_dir) != 0) {
544            /* error, but nothing can do about it
545             * and should'nt print anything which might SEGV again */
546        }
[1]547    }
[979]548    if (xc_disable_on_crash) {
549        xc_disable_on_crash = 0;
[1040]550        xc_cacher_disable();
[979]551    }
[65]552    raise(sig);
[1]553}
554/* }}} */
[914]555#endif
[1]556
[1047]557/* {{{ incompatible zend extensions handling */
558typedef struct {
559    const char *name;
560    startup_func_t old_startup;
561} xc_incompatible_zend_extension_info_t;
562static xc_incompatible_zend_extension_info_t xc_incompatible_zend_extensions[] = {
[1163]563    { "Zend Optimizer", NULL },
564    { "the ionCube PHP Loader", NULL }
[1047]565};
[1177]566zend_llist_element **xc_zend_extension_elements;
[1047]567
568static xc_incompatible_zend_extension_info_t *xc_get_incompatible_zend_extension_info(const char *name)
[164]569{
[1047]570    size_t i;
571
572    for (i = 0; i < sizeof(xc_incompatible_zend_extensions) / sizeof(xc_incompatible_zend_extensions[0]); ++i) {
573        xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = &xc_incompatible_zend_extensions[i];
574        if (strcmp(incompatible_zend_extension_info->name, name) == 0) {
575            return incompatible_zend_extension_info;
[1026]576        }
577    }
[1045]578
[1047]579    return NULL;
580}
581/* }}} */
[1177]582static void xc_zend_llist_add_element(zend_llist *list, zend_llist_element *element) /* {{{ */
583{
584    if (!zend_extensions.head) {
585        zend_extensions.head = zend_extensions.tail = element;
586    }
587    else {
588        zend_extensions.tail->next = element;
589        element->prev = zend_extensions.tail;
590        zend_extensions.tail = element;
591    }
592}
593/* }}} */
[1047]594static int xc_incompatible_zend_extension_startup_hook(zend_extension *extension) /* {{{ */
595{
596    xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(extension->name);
597    int status;
598    zend_bool catched = 0;
[1177]599    zend_llist old_zend_extensions;
[1172]600    zend_extension *ext;
[1177]601    size_t i;
602    zend_llist_element *element;
[1164]603    TSRMLS_FETCH();
[1047]604
605    /* restore */
606    extension->startup = incompatible_zend_extension_info->old_startup;
607    incompatible_zend_extension_info->old_startup = NULL;
608    assert(extension->startup);
609
[1177]610    /* save */
611    assert(!xc_zend_extension_elements);
612    old_zend_extensions = zend_extensions;
613    xc_zend_extension_elements = malloc(sizeof(zend_llist_element *) * old_zend_extensions.count);
614    for (i = 0, element = old_zend_extensions.head; element; ++i, element = element->next) {
615        xc_zend_extension_elements[i] = element;
616    }
617
618    /* hide all XCache extensions from it */
[1163]619    zend_extensions.head = NULL;
620    zend_extensions.tail = NULL;
621    zend_extensions.count = 0;
[1177]622
623    for (i = 0; i < old_zend_extensions.count; ++i) {
624        element = xc_zend_extension_elements[i];
625        element->next = element->prev = NULL;
626
627        ext = (zend_extension *) element->data;
628
[1172]629        if (!(strcmp(ext->name, XCACHE_NAME) == 0 || strncmp(ext->name, XCACHE_NAME " ", sizeof(XCACHE_NAME " ") - 1) == 0)) {
[1177]630            xc_zend_llist_add_element(&zend_extensions, element);
631            ++zend_extensions.count;
[1172]632        }
633    }
[1163]634
635    assert(extension->startup != xc_incompatible_zend_extension_startup_hook);
[1047]636    zend_try {
637        status = extension->startup(extension);
638    } zend_catch {
639        catched = 1;
640    } zend_end_try();
641
[1163]642    /* restore */
[1047]643    zend_extensions = old_zend_extensions;
[1177]644    zend_extensions.head = NULL;
645    zend_extensions.tail = NULL;
646    zend_extensions.count = 0;
647    for (i = 0; i < old_zend_extensions.count; ++i) {
648        element = xc_zend_extension_elements[i];
649        element->next = element->prev = NULL;
650
651        xc_zend_llist_add_element(&zend_extensions, element);
652        ++zend_extensions.count;
653    }
654
655    free(xc_zend_extension_elements);
656    xc_zend_extension_elements = NULL;
657
[1047]658    if (catched) {
659        zend_bailout();
[1045]660    }
[1047]661    return status;
[164]662}
[1026]663/* }}} */
664static int xc_zend_startup(zend_extension *extension) /* {{{ */
[164]665{
[1047]666    zend_llist_position lpos;
667    zend_extension *ext;
668
669    ext = (zend_extension *) zend_extensions.head->data;
670    if (strcmp(ext->name, XCACHE_NAME) != 0) {
671        zend_error(E_WARNING, "XCache failed to load itself as the before \"%s\". compatibility downgraded", ext->name);
672    }
673
[1040]674    old_compile_file = zend_compile_file;
[1030]675    zend_compile_file = xc_check_initial_compile_file;
[164]676
[1047]677    for (ext = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &lpos);
678            ext;
679            ext = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &lpos)) {
[1061]680        xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(ext->name);
[1047]681        if (incompatible_zend_extension_info) {
682            assert(!incompatible_zend_extension_info->old_startup);
683            incompatible_zend_extension_info->old_startup = ext->startup;
684            ext->startup = xc_incompatible_zend_extension_startup_hook;
[1026]685        }
[1]686    }
687    return SUCCESS;
688}
[1026]689/* }}} */
690static void xc_zend_shutdown(zend_extension *extension) /* {{{ */
[1]691{
692}
[1026]693/* }}} */
694/* {{{ zend extension definition structure */
[1040]695static zend_extension xc_zend_extension_entry = {
[1026]696    XCACHE_NAME,
697    XCACHE_VERSION,
698    XCACHE_AUTHOR,
699    XCACHE_URL,
700    XCACHE_COPYRIGHT,
701    xc_zend_startup,
702    xc_zend_shutdown,
703    NULL,           /* activate_func_t */
704    NULL,           /* deactivate_func_t */
705    NULL,           /* message_handler_func_t */
706    NULL,           /* op_array_handler_func_t */
707    NULL,           /* statement_handler_func_t */
708    NULL,           /* fcall_begin_handler_func_t */
709    NULL,           /* fcall_end_handler_func_t */
710    NULL,           /* op_array_ctor_func_t */
711    NULL,           /* op_array_dtor_func_t */
712    STANDARD_ZEND_EXTENSION_PROPERTIES
713};
714/* }}} */
[82]715
[1026]716/* {{{ PHP_INI */
[1]717PHP_INI_BEGIN()
[1026]718    PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_coredump_dir)
[1067]719    PHP_INI_ENTRY1_EX  ("xcache.disable_on_crash",       "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_disable_on_crash, zend_ini_boolean_displayer_cb)
720    PHP_INI_ENTRY1_EX  ("xcache.test",                   "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_test,             zend_ini_boolean_displayer_cb)
[399]721    STD_PHP_INI_BOOLEAN("xcache.experimental",           "0", PHP_INI_ALL,    OnUpdateBool,        experimental,      zend_xcache_globals, xcache_globals)
[1]722PHP_INI_END()
723/* }}} */
[1026]724static PHP_MINFO_FUNCTION(xcache) /* {{{ */
[1]725{
726    php_info_print_table_start();
[1026]727    php_info_print_table_row(2, "XCache Version", XCACHE_VERSION);
[923]728#ifdef XCACHE_VERSION_REVISION
729    php_info_print_table_row(2, "Revision", "r" XCACHE_VERSION_REVISION);
730#endif
[26]731    php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
[1]732    php_info_print_table_end();
[82]733
[1]734    DISPLAY_INI_ENTRIES();
735}
736/* }}} */
[1026]737static PHP_MINIT_FUNCTION(xcache) /* {{{ */
[1]738{
[92]739#ifndef PHP_GINIT
[17]740    ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
[92]741#endif
[17]742    REGISTER_INI_ENTRIES();
743
[65]744    if (xc_coredump_dir && xc_coredump_dir[0]) {
[914]745        xcache_init_crash_handler();
[65]746    }
[1]747
[1129]748    if (strcmp(sapi_module.name, "cli") == 0) {
[1131]749        char *env;
[1129]750        if ((env = getenv("XCACHE_TEST")) != NULL) {
751            xc_test = atoi(env);
752        }
753    }
754
[1]755    xc_init_constant(module_number TSRMLS_CC);
[148]756    xc_shm_init_modules();
[1]757
[1047]758    /* must be the first */
759    xcache_zend_extension_add(&xc_zend_extension_entry, 1);
760#ifdef HAVE_XCACHE_OPTIMIZER
761    xc_optimizer_startup_module();
762#endif
763#ifdef HAVE_XCACHE_CACHER
764    xc_cacher_startup_module();
765#endif
[27]766#ifdef HAVE_XCACHE_COVERAGER
[1026]767    xc_coverager_startup_module();
[1]768#endif
[1026]769#ifdef HAVE_XCACHE_DISASSEMBLER
770    xc_disassembler_startup_module();
771#endif
[1045]772
[1]773    return SUCCESS;
774}
775/* }}} */
[1040]776static PHP_MSHUTDOWN_FUNCTION(xcache) /* {{{ */
[1]777{
[1040]778    if (old_compile_file && zend_compile_file == xc_check_initial_compile_file) {
779        zend_compile_file = old_compile_file;
780        old_compile_file = NULL;
[1]781    }
782
[65]783    if (xc_coredump_dir && xc_coredump_dir[0]) {
[914]784        xcache_restore_crash_handler();
[65]785    }
[1]786    if (xc_coredump_dir) {
787        pefree(xc_coredump_dir, 1);
788        xc_coredump_dir = NULL;
789    }
[92]790#ifndef PHP_GINIT
791#   ifdef ZTS
[25]792    ts_free_id(xcache_globals_id);
[92]793#   else
[1]794    xc_shutdown_globals(&xcache_globals TSRMLS_CC);
[92]795#   endif
[1]796#endif
797
798    UNREGISTER_INI_ENTRIES();
[1045]799    xcache_zend_extension_remove(&xc_zend_extension_entry);
[1]800    return SUCCESS;
801}
802/* }}} */
[492]803/* {{{ module dependencies */
[1026]804#ifdef STANDARD_MODULE_HEADER_EX
[847]805static zend_module_dep xcache_module_deps[] = {
[492]806    ZEND_MOD_REQUIRED("standard")
807    ZEND_MOD_CONFLICTS("apc")
808    ZEND_MOD_CONFLICTS("eAccelerator")
809    ZEND_MOD_CONFLICTS("Turck MMCache")
[983]810    ZEND_MOD_END
[492]811};
812#endif
813/* }}} */ 
[1]814/* {{{ module definition structure */
815zend_module_entry xcache_module_entry = {
[1026]816#ifdef STANDARD_MODULE_HEADER_EX
[492]817    STANDARD_MODULE_HEADER_EX,
818    NULL,
819    xcache_module_deps,
820#else
[1]821    STANDARD_MODULE_HEADER,
[492]822#endif
823    XCACHE_NAME,
[1]824    xcache_functions,
825    PHP_MINIT(xcache),
826    PHP_MSHUTDOWN(xcache),
[1040]827    NULL, /* RINIT */
828    NULL, /* RSHUTDOWN */
[1]829    PHP_MINFO(xcache),
830    XCACHE_VERSION,
[92]831#ifdef PHP_GINIT
832    PHP_MODULE_GLOBALS(xcache),
833    PHP_GINIT(xcache),
834    PHP_GSHUTDOWN(xcache),
835#endif
[1]836#ifdef ZEND_ENGINE_2
[1040]837    NULL /* ZEND_MODULE_POST_ZEND_DEACTIVATE_N */,
[1]838#else
839    NULL,
840    NULL,
841#endif
842    STANDARD_MODULE_PROPERTIES_EX
843};
844
845#ifdef COMPILE_DL_XCACHE
846ZEND_GET_MODULE(xcache)
847#endif
848/* }}} */
Note: See TracBrowser for help on using the repository browser.