source: git/xcache.c @ 1dfe7cc

3.2
Last change on this file since 1dfe7cc was 1dfe7cc, checked in by Xuefer <xuefer@…>, 6 years ago

MFT: merge [1493],[1496] from trunk, fix leak in decompiler/disassembler

git-svn-id: svn://svn.lighttpd.net/xcache/branches/3.2@1516 c26eb9a1-5813-0410-bd6c-c2e55f420ca7

  • Property mode set to 100644
File size: 25.4 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        MAKE_COPY_ZVAL(&value, return_value)
342        return_value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
343        break;
344
345#ifdef IS_CONSTANT_ARRAY
346    case IS_CONSTANT_ARRAY:
347        MAKE_COPY_ZVAL(&value, return_value)
348        return_value->type = IS_ARRAY;
349        break;
350#endif
351
352#ifdef IS_CONSTANT_AST
353    case IS_CONSTANT_AST:
354        RETURN_NULL();
355        break;
356#endif
357
358    default:
359        if ((Z_TYPE_P(value) & ~IS_CONSTANT_TYPE_MASK)) {
360            MAKE_COPY_ZVAL(&value, return_value);
361            return_value->type &= IS_CONSTANT_TYPE_MASK;
362        }
363        else {
364            RETURN_NULL();
365        }
366    }
367}
368/* }}} */
369/* {{{ proto int xcache_get_type(zval value)
370   XCache internal use only for disassembler to get variable type in engine level */
371PHP_FUNCTION(xcache_get_type)
372{
373    zval *value;
374
375    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
376        return;
377    }
378
379    RETURN_LONG(Z_TYPE_P(value));
380}
381/* }}} */
382/* {{{ proto string xcache_coredump(int op_type) */
383PHP_FUNCTION(xcache_coredump)
384{
385    if (xc_test) {
386        char *null_ptr = NULL;
387        *null_ptr = 0;
388        raise(SIGSEGV);
389    }
390    else {
391        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.test must be enabled to test xcache_coredump()");
392    }
393}
394/* }}} */
395/* {{{ proto string xcache_is_autoglobal(string name) */
396PHP_FUNCTION(xcache_is_autoglobal)
397{
398    zval *name;
399
400    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
401        return;
402    }
403
404#ifdef IS_UNICODE
405    convert_to_unicode(name);
406#else
407    convert_to_string(name);
408#endif
409
410    RETURN_BOOL(zend_u_hash_exists(CG(auto_globals), UG(unicode), Z_STRVAL_P(name), Z_STRLEN_P(name) + 1));
411}
412/* }}} */
413static zend_function_entry xcache_functions[] = /* {{{ */
414{
415    PHP_FE(xcache_coredump,          NULL)
416#ifdef HAVE_XCACHE_ASSEMBLER
417    PHP_FE(xcache_asm,               NULL)
418#endif
419#ifdef HAVE_XCACHE_ENCODER
420    PHP_FE(xcache_encode,            NULL)
421#endif
422#ifdef HAVE_XCACHE_DECODER
423    PHP_FE(xcache_decode_file,       NULL)
424    PHP_FE(xcache_decode_string,     NULL)
425#endif
426    PHP_FE(xcache_get_special_value, NULL)
427    PHP_FE(xcache_get_type,          NULL)
428    PHP_FE(xcache_get_op_type,       NULL)
429    PHP_FE(xcache_get_data_type,     NULL)
430    PHP_FE(xcache_get_opcode,        NULL)
431    PHP_FE(xcache_get_opcode_spec,   NULL)
432    PHP_FE(xcache_is_autoglobal,     NULL)
433    PHP_FE(xcache_get_refcount,      NULL)
434    PHP_FE(xcache_get_isref,         arginfo_xcache_get_isref)
435#ifdef HAVE_XCACHE_DPRINT
436    PHP_FE(xcache_dprint,            NULL)
437#endif
438    PHP_FE_END
439};
440/* }}} */
441
442#ifdef ZEND_WIN32
443#include "dbghelp.h"
444typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
445        CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
446        CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
447        CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
448        );
449
450static PTOP_LEVEL_EXCEPTION_FILTER oldFilter = NULL;
451static HMODULE dbghelpModule = NULL;
452static char crash_dumpPath[_MAX_PATH] = { 0 };
453static MINIDUMPWRITEDUMP dbghelp_MiniDumpWriteDump = NULL;
454
455static LONG WINAPI miniDumperFilter(struct _EXCEPTION_POINTERS *pExceptionInfo) /* {{{ */
456{
457    HANDLE fileHandle;
458    LONG ret = EXCEPTION_CONTINUE_SEARCH;
459
460    SetUnhandledExceptionFilter(oldFilter);
461
462    /* create the file */
463    fileHandle = CreateFile(crash_dumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
464
465    if (fileHandle != INVALID_HANDLE_VALUE) {
466        MINIDUMP_EXCEPTION_INFORMATION exceptionInformation;
467        MINIDUMP_TYPE type = xc_coredump_type ? xc_coredump_type : (MiniDumpNormal|MiniDumpWithDataSegs|MiniDumpWithIndirectlyReferencedMemory);
468        BOOL ok;
469
470        exceptionInformation.ThreadId = GetCurrentThreadId();
471        exceptionInformation.ExceptionPointers = pExceptionInfo;
472        exceptionInformation.ClientPointers = FALSE;
473
474        /* write the dump */
475        ok = dbghelp_MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), fileHandle, type, &exceptionInformation, NULL, NULL);
476        CloseHandle(fileHandle);
477        if (ok) {
478            zend_error(E_ERROR, "Saved dump file to '%s'", crash_dumpPath);
479            ret = EXCEPTION_EXECUTE_HANDLER;
480        }
481        else {
482            zend_error(E_ERROR, "Failed to save dump file to '%s' (error %d)", crash_dumpPath, GetLastError());
483        }
484    }
485    else {
486        zend_error(E_ERROR, "Failed to create dump file '%s' (error %d)", crash_dumpPath, GetLastError());
487    }
488
489    if (xc_disable_on_crash) {
490        xc_disable_on_crash = 0;
491        xc_cacher_disable();
492    }
493
494    return ret;
495}
496/* }}} */
497
498static void xcache_restore_crash_handler() /* {{{ */
499{
500    if (oldFilter) {
501        SetUnhandledExceptionFilter(oldFilter);
502        oldFilter = NULL;
503    }
504}
505/* }}} */
506static void xcache_init_crash_handler() /* {{{ */
507{
508    /* firstly see if dbghelp.dll is around and has the function we need
509       look next to the EXE first, as the one in System32 might be old
510       (e.g. Windows 2000) */
511    char dbghelpPath[_MAX_PATH];
512
513    if (GetModuleFileName(NULL, dbghelpPath, _MAX_PATH)) {
514        char *slash = strchr(dbghelpPath, '\\');
515        if (slash) {
516            strcpy(slash + 1, "DBGHELP.DLL");
517            dbghelpModule = LoadLibrary(dbghelpPath);
518        }
519    }
520
521    if (!dbghelpModule) {
522        /* load any version we can */
523        dbghelpModule = LoadLibrary("DBGHELP.DLL");
524        if (!dbghelpModule) {
525            zend_error(E_ERROR, "Unable to enable crash dump saver: %s", "DBGHELP.DLL not found");
526            return;
527        }
528    }
529
530    dbghelp_MiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress(dbghelpModule, "MiniDumpWriteDump");
531    if (!dbghelp_MiniDumpWriteDump) {
532        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");
533        return;
534    }
535
536#ifdef XCACHE_VERSION_REVISION
537#define REVISION "r" XCACHE_VERSION_REVISION
538#else
539#define REVISION ""
540#endif
541    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());
542#undef REVISION
543
544    oldFilter = SetUnhandledExceptionFilter(&miniDumperFilter);
545}
546/* }}} */
547#else
548/* old signal handlers {{{ */
549typedef void (*xc_sighandler_t)(int);
550#define FOREACH_SIG(sig) static xc_sighandler_t old_##sig##_handler = NULL
551#include "util/xc_foreachcoresig.h"
552#undef FOREACH_SIG
553/* }}} */
554static void xcache_signal_handler(int sig);
555static void xcache_restore_crash_handler() /* {{{ */
556{
557#define FOREACH_SIG(sig) do { \
558    if (old_##sig##_handler != xcache_signal_handler) { \
559        signal(sig, old_##sig##_handler); \
560    } \
561    else { \
562        signal(sig, SIG_DFL); \
563    } \
564} while (0)
565#include "util/xc_foreachcoresig.h"
566#undef FOREACH_SIG
567}
568/* }}} */
569static void xcache_init_crash_handler() /* {{{ */
570{
571#define FOREACH_SIG(sig) \
572    old_##sig##_handler = signal(sig, xcache_signal_handler)
573#include "util/xc_foreachcoresig.h"
574#undef FOREACH_SIG
575}
576/* }}} */
577static void xcache_signal_handler(int sig) /* {{{ */
578{
579    xcache_restore_crash_handler();
580    if (xc_coredump_dir && xc_coredump_dir[0]) {
581        if (chdir(xc_coredump_dir) != 0) {
582            /* error, but nothing can do about it
583             * and should'nt print anything which might SEGV again */
584        }
585    }
586    if (xc_disable_on_crash) {
587        xc_disable_on_crash = 0;
588        xc_cacher_disable();
589    }
590    raise(sig);
591}
592/* }}} */
593#endif
594
595/* {{{ incompatible zend extensions handling */
596typedef struct {
597    const char *name;
598    startup_func_t old_startup;
599} xc_incompatible_zend_extension_info_t;
600static xc_incompatible_zend_extension_info_t xc_incompatible_zend_extensions[] = {
601    { "Zend Extension Manager", NULL },
602    { "Zend Optimizer", NULL },
603    { "the ionCube PHP Loader", NULL }
604};
605
606static xc_incompatible_zend_extension_info_t *xc_get_incompatible_zend_extension_info(const char *name)
607{
608    size_t i;
609
610    for (i = 0; i < sizeof(xc_incompatible_zend_extensions) / sizeof(xc_incompatible_zend_extensions[0]); ++i) {
611        xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = &xc_incompatible_zend_extensions[i];
612        if (strcmp(incompatible_zend_extension_info->name, name) == 0) {
613            return incompatible_zend_extension_info;
614        }
615    }
616
617    return NULL;
618}
619/* }}} */
620static void xc_zend_llist_add_element(zend_llist *list, zend_llist_element *element) /* {{{ */
621{
622    if (!zend_extensions.head) {
623        zend_extensions.head = zend_extensions.tail = element;
624    }
625    else {
626        zend_extensions.tail->next = element;
627        element->prev = zend_extensions.tail;
628        zend_extensions.tail = element;
629    }
630}
631/* }}} */
632static int xc_incompatible_zend_extension_startup_hook(zend_extension *extension) /* {{{ */
633{
634    xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(extension->name);
635    int status;
636    zend_bool catched = 0;
637    zend_llist saved_zend_extensions_container; /* without elements */
638    zend_llist_element **saved_zend_extensions_elments;
639    size_t new_zend_extensions_elments_count;
640    zend_llist_element **new_zend_extensions_elments;
641    zend_extension *ext;
642    size_t i;
643    zend_llist_element *element;
644    TSRMLS_FETCH();
645
646    /* restore startup hack */
647    extension->startup = incompatible_zend_extension_info->old_startup;
648    incompatible_zend_extension_info->old_startup = NULL;
649    assert(extension->startup);
650
651    /* save extensions list */
652    saved_zend_extensions_container = zend_extensions;
653    saved_zend_extensions_elments = malloc(sizeof(zend_llist_element *) * saved_zend_extensions_container.count);
654    for (i = 0, element = saved_zend_extensions_container.head; element; ++i, element = element->next) {
655        saved_zend_extensions_elments[i] = element;
656    }
657
658    /* hide all XCache extensions from it */
659    zend_extensions.head = NULL;
660    zend_extensions.tail = NULL;
661    zend_extensions.count = 0;
662
663    for (i = 0; i < saved_zend_extensions_container.count; ++i) {
664        element = saved_zend_extensions_elments[i];
665        element->next = element->prev = NULL;
666
667        ext = (zend_extension *) element->data;
668
669        if (!(strcmp(ext->name, XCACHE_NAME) == 0 || strncmp(ext->name, XCACHE_NAME " ", sizeof(XCACHE_NAME " ") - 1) == 0)) {
670            xc_zend_llist_add_element(&zend_extensions, element);
671            ++zend_extensions.count;
672        }
673    }
674
675    assert(extension->startup != xc_incompatible_zend_extension_startup_hook);
676    zend_try {
677        status = extension->startup(extension);
678    } zend_catch {
679        catched = 1;
680    } zend_end_try();
681
682    /* save newly added extensions added by this extension*/
683    new_zend_extensions_elments_count = zend_extensions.count - 1;
684    new_zend_extensions_elments = NULL;
685    if (new_zend_extensions_elments_count) {
686        new_zend_extensions_elments = malloc(sizeof(zend_llist_element *) * new_zend_extensions_elments_count);
687        element = zend_extensions.head;
688        for (i = 0, element = element->next; element; ++i, element = element->next) {
689            new_zend_extensions_elments[i] = element;
690        }
691    }
692
693    /* restore original extension list*/
694    zend_extensions = saved_zend_extensions_container;
695    zend_extensions.head = NULL;
696    zend_extensions.tail = NULL;
697    zend_extensions.count = 0;
698    for (i = 0; i < saved_zend_extensions_container.count; ++i) {
699        element = saved_zend_extensions_elments[i];
700        element->next = element->prev = NULL;
701
702        xc_zend_llist_add_element(&zend_extensions, element);
703        ++zend_extensions.count;
704
705        ext = (zend_extension *) element->data;
706        if (ext == extension && new_zend_extensions_elments_count) {
707            /* add new created extension */
708            size_t j;
709            for (j = 0; j < new_zend_extensions_elments_count; ++j) {
710                element = new_zend_extensions_elments[j];
711                element->next = element->prev = NULL;
712
713                xc_zend_llist_add_element(&zend_extensions, element);
714                ++zend_extensions.count;
715            }
716        }
717    }
718    free(saved_zend_extensions_elments);
719    if (new_zend_extensions_elments) {
720        free(new_zend_extensions_elments);
721    }
722
723    if (catched) {
724        zend_bailout();
725    }
726    return status;
727}
728/* }}} */
729static int xc_zend_startup(zend_extension *extension) /* {{{ */
730{
731    zend_llist_position lpos;
732    zend_extension *ext;
733
734    ext = (zend_extension *) zend_extensions.head->data;
735    if (strcmp(ext->name, XCACHE_NAME) != 0) {
736        zend_error(E_WARNING, "XCache failed to load itself to before zend_extension=\"%s\". compatibility downgraded", ext->name);
737    }
738
739    for (ext = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &lpos);
740            ext;
741            ext = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &lpos)) {
742        xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(ext->name);
743        if (incompatible_zend_extension_info) {
744            assert(!incompatible_zend_extension_info->old_startup);
745            incompatible_zend_extension_info->old_startup = ext->startup;
746            ext->startup = xc_incompatible_zend_extension_startup_hook;
747        }
748    }
749    return SUCCESS;
750}
751/* }}} */
752static void xc_zend_shutdown(zend_extension *extension) /* {{{ */
753{
754}
755/* }}} */
756/* {{{ zend extension definition structure */
757static zend_extension xc_zend_extension_entry = {
758    XCACHE_NAME,
759    XCACHE_VERSION,
760    XCACHE_AUTHOR,
761    XCACHE_URL,
762    XCACHE_COPYRIGHT,
763    xc_zend_startup,
764    xc_zend_shutdown,
765    NULL,           /* activate_func_t */
766    NULL,           /* deactivate_func_t */
767    NULL,           /* message_handler_func_t */
768    NULL,           /* op_array_handler_func_t */
769    NULL,           /* statement_handler_func_t */
770    NULL,           /* fcall_begin_handler_func_t */
771    NULL,           /* fcall_end_handler_func_t */
772    NULL,           /* op_array_ctor_func_t */
773    NULL,           /* op_array_dtor_func_t */
774    STANDARD_ZEND_EXTENSION_PROPERTIES
775};
776/* }}} */
777
778/* {{{ PHP_INI */
779PHP_INI_BEGIN()
780    PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_coredump_dir)
781#ifdef ZEND_WIN32
782    PHP_INI_ENTRY1     ("xcache.coredump_type",          "0", PHP_INI_SYSTEM, xcache_OnUpdateULong,    &xc_coredump_type)
783#endif
784    PHP_INI_ENTRY1_EX  ("xcache.disable_on_crash",       "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_disable_on_crash, zend_ini_boolean_displayer_cb)
785    PHP_INI_ENTRY1_EX  ("xcache.test",                   "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_test,             zend_ini_boolean_displayer_cb)
786    STD_PHP_INI_BOOLEAN("xcache.experimental",           "0", PHP_INI_ALL,    OnUpdateBool,        experimental,      zend_xcache_globals, xcache_globals)
787PHP_INI_END()
788/* }}} */
789static PHP_MINFO_FUNCTION(xcache) /* {{{ */
790{
791    php_info_print_table_start();
792    php_info_print_table_row(2, "XCache Version", XCACHE_VERSION);
793#ifdef XCACHE_VERSION_REVISION
794    php_info_print_table_row(2, "Revision", "r" XCACHE_VERSION_REVISION);
795#endif
796    php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
797    php_info_print_table_end();
798
799    DISPLAY_INI_ENTRIES();
800}
801/* }}} */
802static PHP_MINIT_FUNCTION(xcache) /* {{{ */
803{
804#ifndef PHP_GINIT
805    ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
806#endif
807    REGISTER_INI_ENTRIES();
808
809    if (xc_coredump_dir && xc_coredump_dir[0]) {
810        xcache_init_crash_handler();
811    }
812
813    if (strcmp(sapi_module.name, "cli") == 0) {
814        char *env;
815        if ((env = getenv("XCACHE_TEST")) != NULL) {
816            xc_test = (zend_bool) atoi(env);
817        }
818    }
819
820    xc_init_constant(module_number TSRMLS_CC);
821    xc_shm_init_modules();
822
823    /* must be the first */
824    xcache_zend_extension_add(&xc_zend_extension_entry, 1);
825    old_compile_file = zend_compile_file;
826    zend_compile_file = xc_check_initial_compile_file;
827
828#ifdef HAVE_XCACHE_OPTIMIZER
829    xc_optimizer_startup_module();
830#endif
831#ifdef HAVE_XCACHE_CACHER
832    xc_cacher_startup_module();
833#endif
834#ifdef HAVE_XCACHE_COVERAGER
835    xc_coverager_startup_module();
836#endif
837#ifdef HAVE_XCACHE_DISASSEMBLER
838    xc_disassembler_startup_module();
839#endif
840
841    return SUCCESS;
842}
843/* }}} */
844static PHP_MSHUTDOWN_FUNCTION(xcache) /* {{{ */
845{
846    if (old_compile_file && zend_compile_file == xc_check_initial_compile_file) {
847        zend_compile_file = old_compile_file;
848        old_compile_file = NULL;
849    }
850
851    if (xc_coredump_dir && xc_coredump_dir[0]) {
852        xcache_restore_crash_handler();
853    }
854    if (xc_coredump_dir) {
855        pefree(xc_coredump_dir, 1);
856        xc_coredump_dir = NULL;
857    }
858#ifndef PHP_GINIT
859#   ifdef ZTS
860    ts_free_id(xcache_globals_id);
861#   else
862    xc_shutdown_globals(&xcache_globals TSRMLS_CC);
863#   endif
864#endif
865
866    UNREGISTER_INI_ENTRIES();
867    xcache_zend_extension_remove(&xc_zend_extension_entry);
868    return SUCCESS;
869}
870/* }}} */
871/* {{{ module dependencies */
872#ifdef STANDARD_MODULE_HEADER_EX
873static zend_module_dep xcache_module_deps[] = {
874    ZEND_MOD_REQUIRED("standard")
875    ZEND_MOD_CONFLICTS("apc")
876    ZEND_MOD_CONFLICTS("eAccelerator")
877    ZEND_MOD_CONFLICTS("Turck MMCache")
878    ZEND_MOD_END
879};
880#endif
881/* }}} */ 
882/* {{{ module definition structure */
883zend_module_entry xcache_module_entry = {
884#ifdef STANDARD_MODULE_HEADER_EX
885    STANDARD_MODULE_HEADER_EX,
886    NULL,
887    xcache_module_deps,
888#else
889    STANDARD_MODULE_HEADER,
890#endif
891    XCACHE_NAME,
892    xcache_functions,
893    PHP_MINIT(xcache),
894    PHP_MSHUTDOWN(xcache),
895    NULL, /* RINIT */
896    NULL, /* RSHUTDOWN */
897    PHP_MINFO(xcache),
898    XCACHE_VERSION,
899#ifdef PHP_GINIT
900    PHP_MODULE_GLOBALS(xcache),
901    PHP_GINIT(xcache),
902    PHP_GSHUTDOWN(xcache),
903#endif
904#ifdef ZEND_ENGINE_2
905    NULL /* ZEND_MODULE_POST_ZEND_DEACTIVATE_N */,
906#else
907    NULL,
908    NULL,
909#endif
910    STANDARD_MODULE_PROPERTIES_EX
911};
912
913#ifdef COMPILE_DL_XCACHE
914ZEND_GET_MODULE(xcache)
915#endif
916/* }}} */
Note: See TracBrowser for help on using the repository browser.