source: trunk/xcache.c @ 1445

Last change on this file since 1445 was 1445, checked in by moo, 9 months ago

output if segv

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