source: trunk/xcache.c

Last change on this file was 1493, checked in by moo, 2 months ago

decompiler: fix leak

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