source: trunk/xcache.c @ 1486

Last change on this file since 1486 was 1486, checked in by moo, 4 months ago

WIP PHP_5_6 support

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