source: svn/tags/3.2.0/xcache.c @ 1543

Last change on this file since 1543 was 1524, checked in by Xuefer, 6 years ago

MFT: [1523] refix fix leak in decompiler/disassembler, was broken for older PHP

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