source: trunk/xcache.c @ 1346

Last change on this file since 1346 was 1346, checked in by moo, 12 months ago

fixed #320: void warning for gcc only pragma

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