source: trunk/xcache.c

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

decompiler: fix leak

  • Property svn:eol-style set to native
File size: 28.9 KB
RevLine 
[1]1/* {{{ macros */
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5
6#include <signal.h>
7
8#include "xcache.h"
[993]9
10#ifdef HAVE_XCACHE_OPTIMIZER
[1003]11#   include "mod_optimizer/xc_optimizer.h"
[993]12#endif
[1040]13#ifdef HAVE_XCACHE_CACHER
14#   include "mod_cacher/xc_cacher.h"
15#endif
[993]16#ifdef HAVE_XCACHE_COVERAGER
[1003]17#   include "mod_coverager/xc_coverager.h"
[993]18#endif
19#ifdef HAVE_XCACHE_DISASSEMBLER
[1003]20#   include "mod_disassembler/xc_disassembler.h"
[993]21#endif
22
[1]23#include "xcache_globals.h"
[1026]24#include "xcache/xc_extension.h"
25#include "xcache/xc_ini.h"
[987]26#include "xcache/xc_const_string.h"
27#include "xcache/xc_opcode_spec.h"
28#include "xcache/xc_utils.h"
[982]29#include "util/xc_stack.h"
[1]30
[1026]31#include "php.h"
32#include "ext/standard/info.h"
33#include "ext/standard/php_string.h"
[1131]34#include "SAPI.h"
[1]35/* }}} */
36
37/* {{{ globals */
38static char *xc_coredump_dir = NULL;
[1230]39#ifdef ZEND_WIN32
40static zend_ulong xc_coredump_type = 0;
41#endif
[979]42static zend_bool xc_disable_on_crash = 0;
[1]43
[403]44static zend_compile_file_t *old_compile_file = NULL;
[1]45
[1040]46zend_bool xc_test = 0;
[1]47
[982]48ZEND_DECLARE_MODULE_GLOBALS(xcache)
[854]49
[1]50/* }}} */
51
[405]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;
[1040]55    return old_compile_file(h, type TSRMLS_CC);
[405]56}
57/* }}} */
[937]58
[1251]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
[1]74/* module helper function */
75static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */
76{
[11]77    typedef struct {
[1]78        const char *prefix;
[20]79        zend_uchar (*getsize)();
[1]80        const char *(*get)(zend_uchar i);
[1133]81    } xc_nameinfo_t;
82    xc_nameinfo_t nameinfos[] = {
[1]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;
[1134]90    xc_nameinfo_t *p;
[1]91
92    for (p = nameinfos; p->getsize; p ++) {
[1133]93        zend_uchar i, count;
94        char const_name[96];
95        int const_name_len;
96
[20]97        count = p->getsize();
98        for (i = 0; i < count; i ++) {
[1]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
[1313]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);
[1]113    return 0;
114}
115/* }}} */
[92]116/* {{{ PHP_GINIT_FUNCTION(xcache) */
[1346]117#ifdef __GNUC__
[1321]118#pragma GCC push_options
119#pragma GCC diagnostic ignored "-Wshadow"
[1346]120#endif
[1321]121
[92]122#ifdef PHP_GINIT_FUNCTION
[1050]123static PHP_GINIT_FUNCTION(xcache)
[92]124#else
[1321]125static void xc_init_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
[92]126#endif
[1]127{
[1346]128#ifdef __GNUC__
[1321]129#pragma GCC pop_options
[1346]130#endif
[1321]131
[92]132    memset(xcache_globals, 0, sizeof(zend_xcache_globals));
[429]133
[588]134#ifdef HAVE_XCACHE_CONSTANT
[640]135    zend_hash_init_ex(&xcache_globals->internal_constant_table, 1, NULL, (dtor_func_t) xc_zend_constant_dtor, 1, 0);
[588]136#endif
[429]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);
[1]139}
140/* }}} */
[92]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
[1]148{
[917]149    size_t i;
[1]150
[92]151    if (xcache_globals->php_holds != NULL) {
[1040]152        for (i = 0; i < xcache_globals->php_holds_size; i ++) {
[92]153            xc_stack_destroy(&xcache_globals->php_holds[i]);
[1]154        }
[92]155        free(xcache_globals->php_holds);
156        xcache_globals->php_holds = NULL;
[1040]157        xcache_globals->php_holds_size = 0;
[1]158    }
159
[92]160    if (xcache_globals->var_holds != NULL) {
[1040]161        for (i = 0; i < xcache_globals->var_holds_size; i ++) {
[92]162            xc_stack_destroy(&xcache_globals->var_holds[i]);
[1]163        }
[92]164        free(xcache_globals->var_holds);
165        xcache_globals->var_holds = NULL;
[1040]166        xcache_globals->var_holds_size = 0;
[1]167    }
[344]168
[438]169    if (xcache_globals->internal_table_copied) {
[588]170#ifdef HAVE_XCACHE_CONSTANT
171        zend_hash_destroy(&xcache_globals->internal_constant_table);
172#endif
[435]173        zend_hash_destroy(&xcache_globals->internal_function_table);
174        zend_hash_destroy(&xcache_globals->internal_class_table);
175    }
[1]176}
177/* }}} */
178
[1477]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"
[1476]183
184#ifdef ZEND_BEGIN_ARG_INFO_EX
[1477]185ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_dprint, 0, 0, 1)
186    ZEND_ARG_INFO(0, value)
[1476]187ZEND_END_ARG_INFO()
188#else
[1477]189static unsigned char arginfo_xcache_dprint[] = { 1, BYREF_NONE };
[1476]190#endif
191
[532]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
[1477]203#ifdef HAVE_XCACHE_ASSEMBLER
[9]204/* {{{ proto string xcache_asm(string filename)
205 */
[1]206PHP_FUNCTION(xcache_asm)
207{
208}
[1477]209/* }}} */
[1]210#endif
[1477]211#ifdef HAVE_XCACHE_ENCODER
[9]212/* {{{ proto string xcache_encode(string filename)
213   Encode php file into XCache opcode encoded format */
[1]214PHP_FUNCTION(xcache_encode)
215{
216}
[1477]217/* }}} */
[1]218#endif
[1477]219#ifdef HAVE_XCACHE_DECODER
[9]220/* {{{ proto bool xcache_decode_file(string filename)
221   Decode(load) opcode from XCache encoded format file */
222PHP_FUNCTION(xcache_decode_file)
[1]223{
224}
225/* }}} */
[9]226/* {{{ proto bool xcache_decode_string(string data)
227   Decode(load) opcode from XCache encoded format data */
228PHP_FUNCTION(xcache_decode_string)
229{
230}
[1477]231/* }}} */
[9]232#endif
[1]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) {
[11]244        name = getter((zend_uchar) spec);
[1]245        if (name) {
246            /* RETURN_STRING */
[1201]247            int len = (int) strlen(name);
[1]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) */
[1477]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
[1]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) */
[1477]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
[1]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) */
[1477]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
[1]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) */
[1477]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
[1]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) */
[1477]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
[1]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    }
[17]330    if ((zend_uchar) spec <= xc_get_opcode_spec_count()) {
[11]331        opspec = xc_get_opcode_spec((zend_uchar) spec);
[1]332        if (opspec) {
333            array_init(return_value);
[1313]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);
[1]338            return;
339        }
340    }
341    RETURN_NULL();
342}
343/* }}} */
[781]344/* {{{ proto mixed xcache_get_special_value(zval value)
345   XCache internal use only: For decompiler to get static value with type fixed */
[1477]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
[1]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
[713]362    switch ((Z_TYPE_P(value) & IS_CONSTANT_TYPE_MASK)) {
363    case IS_CONSTANT:
[1493]364        MAKE_COPY_ZVAL(&value, return_value)
[1]365        return_value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
[713]366        break;
[1]367
[1486]368#ifdef IS_CONSTANT_ARRAY
[713]369    case IS_CONSTANT_ARRAY:
[1493]370        MAKE_COPY_ZVAL(&value, return_value)
[1]371        return_value->type = IS_ARRAY;
[713]372        break;
[1486]373#endif
[713]374
[1486]375#ifdef IS_CONSTANT_AST
376    case IS_CONSTANT_AST:
377        RETURN_NULL();
378        break;
379#endif
380
[713]381    default:
[1374]382        if ((Z_TYPE_P(value) & ~IS_CONSTANT_TYPE_MASK)) {
[1493]383            MAKE_COPY_ZVAL(&value, return_value);
[1374]384            return_value->type &= IS_CONSTANT_TYPE_MASK;
385        }
386        else {
387            RETURN_NULL();
388        }
[1]389    }
390}
391/* }}} */
[781]392/* {{{ proto int xcache_get_type(zval value)
393   XCache internal use only for disassembler to get variable type in engine level */
[1477]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
[781]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/* }}} */
[1477]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
[1]421PHP_FUNCTION(xcache_coredump)
422{
[9]423    if (xc_test) {
[1181]424        char *null_ptr = NULL;
425        *null_ptr = 0;
[9]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    }
[1]431}
432/* }}} */
433/* {{{ proto string xcache_is_autoglobal(string name) */
[1477]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
[1]442PHP_FUNCTION(xcache_is_autoglobal)
443{
[860]444    zval *name;
[1]445
[862]446    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
[1]447        return;
448    }
449
[862]450#ifdef IS_UNICODE
451    convert_to_unicode(name);
452#else
453    convert_to_string(name);
454#endif
455
[860]456    RETURN_BOOL(zend_u_hash_exists(CG(auto_globals), UG(unicode), Z_STRVAL_P(name), Z_STRLEN_P(name) + 1));
[1]457}
458/* }}} */
[1477]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/* }}} */
[716]519static zend_function_entry xcache_functions[] = /* {{{ */
[1]520{
[1477]521#ifdef HAVE_XCACHE_DPRINT
522    PHP_FE(xcache_dprint,            arginfo_xcache_dprint)
523#endif
[1]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
[9]531    PHP_FE(xcache_decode_file,       NULL)
532    PHP_FE(xcache_decode_string,     NULL)
[1]533#endif
[1477]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)
[1476]542    PHP_FE(xcache_get_refcount,      arginfo_xcache_get_refcount)
543    PHP_FE(xcache_get_cowcount,      arginfo_xcache_get_cowcount)
[781]544    PHP_FE(xcache_get_isref,         arginfo_xcache_get_isref)
[983]545    PHP_FE_END
[1]546};
547/* }}} */
548
[914]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
[915]557static PTOP_LEVEL_EXCEPTION_FILTER oldFilter = NULL;
[914]558static HMODULE dbghelpModule = NULL;
[915]559static char crash_dumpPath[_MAX_PATH] = { 0 };
560static MINIDUMPWRITEDUMP dbghelp_MiniDumpWriteDump = NULL;
[914]561
562static LONG WINAPI miniDumperFilter(struct _EXCEPTION_POINTERS *pExceptionInfo) /* {{{ */
563{
564    HANDLE fileHandle;
[1106]565    LONG ret = EXCEPTION_CONTINUE_SEARCH;
[914]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;
[1182]574        MINIDUMP_TYPE type = xc_coredump_type ? xc_coredump_type : (MiniDumpNormal|MiniDumpWithDataSegs|MiniDumpWithIndirectlyReferencedMemory);
[914]575        BOOL ok;
576
577        exceptionInformation.ThreadId = GetCurrentThreadId();
578        exceptionInformation.ExceptionPointers = pExceptionInfo;
579        exceptionInformation.ClientPointers = FALSE;
580
581        /* write the dump */
[1182]582        ok = dbghelp_MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), fileHandle, type, &exceptionInformation, NULL, NULL);
[914]583        CloseHandle(fileHandle);
584        if (ok) {
585            zend_error(E_ERROR, "Saved dump file to '%s'", crash_dumpPath);
[1106]586            ret = EXCEPTION_EXECUTE_HANDLER;
[914]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
[1106]596    if (xc_disable_on_crash) {
597        xc_disable_on_crash = 0;
598        xc_cacher_disable();
599    }
600
601    return ret;
[914]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");
[918]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");
[914]640        return;
641    }
642
[923]643#ifdef XCACHE_VERSION_REVISION
644#define REVISION "r" XCACHE_VERSION_REVISION
645#else
646#define REVISION ""
647#endif
[925]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());
[923]649#undef REVISION
[914]650
651    oldFilter = SetUnhandledExceptionFilter(&miniDumperFilter);
652}
653/* }}} */
654#else
[75]655/* old signal handlers {{{ */
656typedef void (*xc_sighandler_t)(int);
657#define FOREACH_SIG(sig) static xc_sighandler_t old_##sig##_handler = NULL
[982]658#include "util/xc_foreachcoresig.h"
[75]659#undef FOREACH_SIG
660/* }}} */
661static void xcache_signal_handler(int sig);
[914]662static void xcache_restore_crash_handler() /* {{{ */
[1]663{
[75]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)
[982]672#include "util/xc_foreachcoresig.h"
[75]673#undef FOREACH_SIG
674}
675/* }}} */
[914]676static void xcache_init_crash_handler() /* {{{ */
[75]677{
678#define FOREACH_SIG(sig) \
679    old_##sig##_handler = signal(sig, xcache_signal_handler)
[982]680#include "util/xc_foreachcoresig.h"
[75]681#undef FOREACH_SIG
682}
683/* }}} */
684static void xcache_signal_handler(int sig) /* {{{ */
685{
[914]686    xcache_restore_crash_handler();
[1]687    if (xc_coredump_dir && xc_coredump_dir[0]) {
[767]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        }
[1]692    }
[979]693    if (xc_disable_on_crash) {
694        xc_disable_on_crash = 0;
[1040]695        xc_cacher_disable();
[979]696    }
[1445]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
[65]711    raise(sig);
[1]712}
713/* }}} */
[914]714#endif
[1]715
[1047]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[] = {
[1251]722    { "Zend Extension Manager", NULL },
[1163]723    { "Zend Optimizer", NULL },
724    { "the ionCube PHP Loader", NULL }
[1047]725};
726
727static xc_incompatible_zend_extension_info_t *xc_get_incompatible_zend_extension_info(const char *name)
[164]728{
[1047]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;
[1026]735        }
736    }
[1045]737
[1047]738    return NULL;
739}
740/* }}} */
[1177]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/* }}} */
[1047]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;
[1251]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;
[1172]762    zend_extension *ext;
[1177]763    size_t i;
764    zend_llist_element *element;
[1164]765    TSRMLS_FETCH();
[1047]766
[1251]767    /* restore startup hack */
[1047]768    extension->startup = incompatible_zend_extension_info->old_startup;
769    incompatible_zend_extension_info->old_startup = NULL;
770    assert(extension->startup);
771
[1251]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;
[1177]777    }
778
779    /* hide all XCache extensions from it */
[1163]780    zend_extensions.head = NULL;
781    zend_extensions.tail = NULL;
782    zend_extensions.count = 0;
[1177]783
[1251]784    for (i = 0; i < saved_zend_extensions_container.count; ++i) {
785        element = saved_zend_extensions_elments[i];
[1177]786        element->next = element->prev = NULL;
787
788        ext = (zend_extension *) element->data;
789
[1172]790        if (!(strcmp(ext->name, XCACHE_NAME) == 0 || strncmp(ext->name, XCACHE_NAME " ", sizeof(XCACHE_NAME " ") - 1) == 0)) {
[1177]791            xc_zend_llist_add_element(&zend_extensions, element);
792            ++zend_extensions.count;
[1172]793        }
794    }
[1163]795
796    assert(extension->startup != xc_incompatible_zend_extension_startup_hook);
[1047]797    zend_try {
798        status = extension->startup(extension);
799    } zend_catch {
800        catched = 1;
801    } zend_end_try();
802
[1251]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;
[1177]816    zend_extensions.head = NULL;
817    zend_extensions.tail = NULL;
818    zend_extensions.count = 0;
[1251]819    for (i = 0; i < saved_zend_extensions_container.count; ++i) {
820        element = saved_zend_extensions_elments[i];
[1177]821        element->next = element->prev = NULL;
822
823        xc_zend_llist_add_element(&zend_extensions, element);
824        ++zend_extensions.count;
[1251]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        }
[1177]838    }
[1251]839    free(saved_zend_extensions_elments);
840    if (new_zend_extensions_elments) {
841        free(new_zend_extensions_elments);
842    }
[1177]843
[1047]844    if (catched) {
845        zend_bailout();
[1045]846    }
[1047]847    return status;
[164]848}
[1026]849/* }}} */
850static int xc_zend_startup(zend_extension *extension) /* {{{ */
[164]851{
[1047]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) {
[1435]857        zend_error(E_WARNING, "XCache failed to load itself to before zend_extension=\"%s\". compatibility downgraded", ext->name);
[1047]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)) {
[1061]863        xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(ext->name);
[1047]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;
[1026]868        }
[1]869    }
870    return SUCCESS;
871}
[1026]872/* }}} */
873static void xc_zend_shutdown(zend_extension *extension) /* {{{ */
[1]874{
875}
[1026]876/* }}} */
877/* {{{ zend extension definition structure */
[1040]878static zend_extension xc_zend_extension_entry = {
[1026]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/* }}} */
[82]898
[1026]899/* {{{ PHP_INI */
[1]900PHP_INI_BEGIN()
[1026]901    PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_coredump_dir)
[1230]902#ifdef ZEND_WIN32
[1182]903    PHP_INI_ENTRY1     ("xcache.coredump_type",          "0", PHP_INI_SYSTEM, xcache_OnUpdateULong,    &xc_coredump_type)
[1230]904#endif
[1067]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)
[399]907    STD_PHP_INI_BOOLEAN("xcache.experimental",           "0", PHP_INI_ALL,    OnUpdateBool,        experimental,      zend_xcache_globals, xcache_globals)
[1]908PHP_INI_END()
909/* }}} */
[1026]910static PHP_MINFO_FUNCTION(xcache) /* {{{ */
[1]911{
912    php_info_print_table_start();
[1026]913    php_info_print_table_row(2, "XCache Version", XCACHE_VERSION);
[923]914#ifdef XCACHE_VERSION_REVISION
915    php_info_print_table_row(2, "Revision", "r" XCACHE_VERSION_REVISION);
916#endif
[26]917    php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
[1]918    php_info_print_table_end();
[82]919
[1]920    DISPLAY_INI_ENTRIES();
921}
922/* }}} */
[1026]923static PHP_MINIT_FUNCTION(xcache) /* {{{ */
[1]924{
[92]925#ifndef PHP_GINIT
[17]926    ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
[92]927#endif
[17]928    REGISTER_INI_ENTRIES();
929
[65]930    if (xc_coredump_dir && xc_coredump_dir[0]) {
[914]931        xcache_init_crash_handler();
[65]932    }
[1]933
[1129]934    if (strcmp(sapi_module.name, "cli") == 0) {
[1131]935        char *env;
[1129]936        if ((env = getenv("XCACHE_TEST")) != NULL) {
[1201]937            xc_test = (zend_bool) atoi(env);
[1129]938        }
939    }
940
[1]941    xc_init_constant(module_number TSRMLS_CC);
[148]942    xc_shm_init_modules();
[1]943
[1047]944    /* must be the first */
945    xcache_zend_extension_add(&xc_zend_extension_entry, 1);
[1435]946    old_compile_file = zend_compile_file;
947    zend_compile_file = xc_check_initial_compile_file;
948
[1047]949#ifdef HAVE_XCACHE_OPTIMIZER
950    xc_optimizer_startup_module();
951#endif
952#ifdef HAVE_XCACHE_CACHER
953    xc_cacher_startup_module();
954#endif
[27]955#ifdef HAVE_XCACHE_COVERAGER
[1026]956    xc_coverager_startup_module();
[1]957#endif
[1026]958#ifdef HAVE_XCACHE_DISASSEMBLER
959    xc_disassembler_startup_module();
960#endif
[1045]961
[1]962    return SUCCESS;
963}
964/* }}} */
[1040]965static PHP_MSHUTDOWN_FUNCTION(xcache) /* {{{ */
[1]966{
[1040]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;
[1]970    }
971
[65]972    if (xc_coredump_dir && xc_coredump_dir[0]) {
[914]973        xcache_restore_crash_handler();
[65]974    }
[1]975    if (xc_coredump_dir) {
976        pefree(xc_coredump_dir, 1);
977        xc_coredump_dir = NULL;
978    }
[92]979#ifndef PHP_GINIT
980#   ifdef ZTS
[25]981    ts_free_id(xcache_globals_id);
[92]982#   else
[1]983    xc_shutdown_globals(&xcache_globals TSRMLS_CC);
[92]984#   endif
[1]985#endif
986
987    UNREGISTER_INI_ENTRIES();
[1045]988    xcache_zend_extension_remove(&xc_zend_extension_entry);
[1]989    return SUCCESS;
990}
991/* }}} */
[492]992/* {{{ module dependencies */
[1026]993#ifdef STANDARD_MODULE_HEADER_EX
[847]994static zend_module_dep xcache_module_deps[] = {
[492]995    ZEND_MOD_REQUIRED("standard")
996    ZEND_MOD_CONFLICTS("apc")
997    ZEND_MOD_CONFLICTS("eAccelerator")
998    ZEND_MOD_CONFLICTS("Turck MMCache")
[983]999    ZEND_MOD_END
[492]1000};
1001#endif
1002/* }}} */ 
[1]1003/* {{{ module definition structure */
1004zend_module_entry xcache_module_entry = {
[1026]1005#ifdef STANDARD_MODULE_HEADER_EX
[492]1006    STANDARD_MODULE_HEADER_EX,
1007    NULL,
1008    xcache_module_deps,
1009#else
[1]1010    STANDARD_MODULE_HEADER,
[492]1011#endif
1012    XCACHE_NAME,
[1]1013    xcache_functions,
1014    PHP_MINIT(xcache),
1015    PHP_MSHUTDOWN(xcache),
[1040]1016    NULL, /* RINIT */
1017    NULL, /* RSHUTDOWN */
[1]1018    PHP_MINFO(xcache),
1019    XCACHE_VERSION,
[92]1020#ifdef PHP_GINIT
1021    PHP_MODULE_GLOBALS(xcache),
1022    PHP_GINIT(xcache),
1023    PHP_GSHUTDOWN(xcache),
1024#endif
[1321]1025#ifdef ZEND_ENGINE_2
[1040]1026    NULL /* ZEND_MODULE_POST_ZEND_DEACTIVATE_N */,
[1321]1027#else
1028    NULL,
1029    NULL,
1030#endif
[1]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.