source: trunk/xcache.c @ 1181

Last change on this file since 1181 was 1181, checked in by moo, 20 months ago

use null ptr to generate coredump

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