source: trunk/xcache.c @ 1281

Last change on this file since 1281 was 1281, checked in by moo, 17 months ago

remove php 4 support completely

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