source: trunk/xcache.c @ 1313

Last change on this file since 1313 was 1313, checked in by moo, 18 months ago

ZEND_STRS ZEND_STRL is inconsist between PHP5.0- and PHP5.0+

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