source: trunk/xcache.c @ 1476

Last change on this file since 1476 was 1476, checked in by moo, 11 months ago

updates ChangeLog? & NEWS, updates xcache_get_refcount, adds xcache_get_cowcount

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