source: trunk/xcache.c @ 1230

Last change on this file since 1230 was 1230, checked in by moo, 21 months ago

fixes #297: segv on startup under sparc, ini setting overflow

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