Annotation of embedaddon/php/Zend/zend_exceptions.c, revision 1.1

1.1     ! misho       1: /*
        !             2:    +----------------------------------------------------------------------+
        !             3:    | Zend Engine                                                          |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1998-2012 Zend Technologies Ltd. (http://www.zend.com) |
        !             6:    +----------------------------------------------------------------------+
        !             7:    | This source file is subject to version 2.00 of the Zend license,     |
        !             8:    | that is bundled with this package in the file LICENSE, and is        |
        !             9:    | available through the world-wide-web at the following url:           |
        !            10:    | http://www.zend.com/license/2_00.txt.                                |
        !            11:    | If you did not receive a copy of the Zend license and are unable to  |
        !            12:    | obtain it through the world-wide-web, please send a note to          |
        !            13:    | license@zend.com so we can mail you a copy immediately.              |
        !            14:    +----------------------------------------------------------------------+
        !            15:    | Authors: Andi Gutmans <andi@zend.com>                                |
        !            16:    |          Marcus Boerger <helly@php.net>                              |
        !            17:    |          Sterling Hughes <sterling@php.net>                          |
        !            18:    |          Zeev Suraski <zeev@zend.com>                                |
        !            19:    +----------------------------------------------------------------------+
        !            20: */
        !            21: 
        !            22: /* $Id: zend_exceptions.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            23: 
        !            24: #include "zend.h"
        !            25: #include "zend_API.h"
        !            26: #include "zend_builtin_functions.h"
        !            27: #include "zend_interfaces.h"
        !            28: #include "zend_exceptions.h"
        !            29: #include "zend_vm.h"
        !            30: 
        !            31: zend_class_entry *default_exception_ce;
        !            32: zend_class_entry *error_exception_ce;
        !            33: static zend_object_handlers default_exception_handlers;
        !            34: ZEND_API void (*zend_throw_exception_hook)(zval *ex TSRMLS_DC);
        !            35: 
        !            36: void zend_exception_set_previous(zval *exception, zval *add_previous TSRMLS_DC)
        !            37: {
        !            38:        zval *previous;
        !            39: 
        !            40:        if (exception == add_previous || !add_previous || !exception) {
        !            41:                return;
        !            42:        }
        !            43:        if (Z_TYPE_P(add_previous) != IS_OBJECT && !instanceof_function(Z_OBJCE_P(add_previous), default_exception_ce TSRMLS_CC)) {
        !            44:                zend_error(E_ERROR, "Cannot set non exception as previous exception");
        !            45:                return;
        !            46:        }
        !            47:        while (exception && exception != add_previous && Z_OBJ_HANDLE_P(exception) != Z_OBJ_HANDLE_P(add_previous)) {
        !            48:                previous = zend_read_property(default_exception_ce, exception, "previous", sizeof("previous")-1, 1 TSRMLS_CC);
        !            49:                if (Z_TYPE_P(previous) == IS_NULL) {
        !            50:                        zend_update_property(default_exception_ce, exception, "previous", sizeof("previous")-1, add_previous TSRMLS_CC);
        !            51:                        Z_DELREF_P(add_previous);
        !            52:                        return;
        !            53:                }
        !            54:                exception = previous;
        !            55:        }
        !            56: }
        !            57: 
        !            58: void zend_exception_save(TSRMLS_D) /* {{{ */
        !            59: {
        !            60:        if (EG(prev_exception)) {
        !            61:                zend_exception_set_previous(EG(exception), EG(prev_exception) TSRMLS_CC);
        !            62:        }
        !            63:        if (EG(exception)) {
        !            64:                EG(prev_exception) = EG(exception);
        !            65:        }
        !            66:        EG(exception) = NULL;
        !            67: }
        !            68: /* }}} */
        !            69: 
        !            70: void zend_exception_restore(TSRMLS_D) /* {{{ */
        !            71: {
        !            72:        if (EG(prev_exception)) {
        !            73:                if (EG(exception)) {
        !            74:                        zend_exception_set_previous(EG(exception), EG(prev_exception) TSRMLS_CC);
        !            75:                } else {
        !            76:                        EG(exception) = EG(prev_exception);
        !            77:                }
        !            78:                EG(prev_exception) = NULL;
        !            79:        }
        !            80: }
        !            81: /* }}} */
        !            82: 
        !            83: void zend_throw_exception_internal(zval *exception TSRMLS_DC) /* {{{ */
        !            84: {
        !            85:        if (exception != NULL) {
        !            86:                zval *previous = EG(exception);
        !            87:                zend_exception_set_previous(exception, EG(exception) TSRMLS_CC);
        !            88:                EG(exception) = exception;
        !            89:                if (previous) {
        !            90:                        return;
        !            91:                }
        !            92:        }
        !            93:        if (!EG(current_execute_data)) {
        !            94:                if(EG(exception)) {
        !            95:                        zend_exception_error(EG(exception), E_ERROR TSRMLS_CC);
        !            96:                }
        !            97:                zend_error(E_ERROR, "Exception thrown without a stack frame");
        !            98:        }
        !            99: 
        !           100:        if (zend_throw_exception_hook) {
        !           101:                zend_throw_exception_hook(exception TSRMLS_CC);
        !           102:        }
        !           103: 
        !           104:        if (EG(current_execute_data)->opline == NULL ||
        !           105:            (EG(current_execute_data)->opline+1)->opcode == ZEND_HANDLE_EXCEPTION) {
        !           106:                /* no need to rethrow the exception */
        !           107:                return;
        !           108:        }
        !           109:        EG(opline_before_exception) = EG(current_execute_data)->opline;
        !           110:        EG(current_execute_data)->opline = EG(exception_op);
        !           111: }
        !           112: /* }}} */
        !           113: 
        !           114: ZEND_API void zend_clear_exception(TSRMLS_D) /* {{{ */
        !           115: {
        !           116:        if (EG(prev_exception)) {
        !           117:                zval_ptr_dtor(&EG(prev_exception));
        !           118:                EG(prev_exception) = NULL;
        !           119:        }
        !           120:        if (!EG(exception)) {
        !           121:                return;
        !           122:        }
        !           123:        zval_ptr_dtor(&EG(exception));
        !           124:        EG(exception) = NULL;
        !           125:        EG(current_execute_data)->opline = EG(opline_before_exception);
        !           126: #if ZEND_DEBUG
        !           127:        EG(opline_before_exception) = NULL;
        !           128: #endif
        !           129: }
        !           130: /* }}} */
        !           131: 
        !           132: static zend_object_value zend_default_exception_new_ex(zend_class_entry *class_type, int skip_top_traces TSRMLS_DC) /* {{{ */
        !           133: {
        !           134:        zval tmp, obj;
        !           135:        zend_object *object;
        !           136:        zval *trace;
        !           137: 
        !           138:        Z_OBJVAL(obj) = zend_objects_new(&object, class_type TSRMLS_CC);
        !           139:        Z_OBJ_HT(obj) = &default_exception_handlers;
        !           140: 
        !           141:        ALLOC_HASHTABLE(object->properties);
        !           142:        zend_hash_init(object->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
        !           143:        zend_hash_copy(object->properties, &class_type->default_properties, zval_copy_property_ctor(class_type), (void *) &tmp, sizeof(zval *));
        !           144: 
        !           145:        ALLOC_ZVAL(trace);
        !           146:        Z_UNSET_ISREF_P(trace);
        !           147:        Z_SET_REFCOUNT_P(trace, 0);
        !           148:        zend_fetch_debug_backtrace(trace, skip_top_traces, 0 TSRMLS_CC);
        !           149: 
        !           150:        zend_update_property_string(default_exception_ce, &obj, "file", sizeof("file")-1, zend_get_executed_filename(TSRMLS_C) TSRMLS_CC);
        !           151:        zend_update_property_long(default_exception_ce, &obj, "line", sizeof("line")-1, zend_get_executed_lineno(TSRMLS_C) TSRMLS_CC);
        !           152:        zend_update_property(default_exception_ce, &obj, "trace", sizeof("trace")-1, trace TSRMLS_CC);
        !           153: 
        !           154:        return Z_OBJVAL(obj);
        !           155: }
        !           156: /* }}} */
        !           157: 
        !           158: static zend_object_value zend_default_exception_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
        !           159: {
        !           160:        return zend_default_exception_new_ex(class_type, 0 TSRMLS_CC);
        !           161: }
        !           162: /* }}} */
        !           163: 
        !           164: static zend_object_value zend_error_exception_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
        !           165: {
        !           166:        return zend_default_exception_new_ex(class_type, 2 TSRMLS_CC);
        !           167: }
        !           168: /* }}} */
        !           169: 
        !           170: /* {{{ proto Exception Exception::__clone()
        !           171:    Clone the exception object */
        !           172: ZEND_METHOD(exception, __clone)
        !           173: {
        !           174:        /* Should never be executable */
        !           175:        zend_throw_exception(NULL, "Cannot clone object using __clone()", 0 TSRMLS_CC);
        !           176: }
        !           177: /* }}} */
        !           178: 
        !           179: /* {{{ proto Exception::__construct(string message, int code [, Exception previous])
        !           180:    Exception constructor */
        !           181: ZEND_METHOD(exception, __construct)
        !           182: {
        !           183:        char  *message = NULL;
        !           184:        long   code = 0;
        !           185:        zval  *object, *previous = NULL;
        !           186:        int    argc = ZEND_NUM_ARGS(), message_len;
        !           187: 
        !           188:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, "|slO!", &message, &message_len, &code, &previous, default_exception_ce) == FAILURE) {
        !           189:                zend_error(E_ERROR, "Wrong parameters for Exception([string $exception [, long $code [, Exception $previous = NULL]]])");
        !           190:        }
        !           191: 
        !           192:        object = getThis();
        !           193: 
        !           194:        if (message) {
        !           195:                zend_update_property_string(default_exception_ce, object, "message", sizeof("message")-1, message TSRMLS_CC);
        !           196:        }
        !           197: 
        !           198:        if (code) {
        !           199:                zend_update_property_long(default_exception_ce, object, "code", sizeof("code")-1, code TSRMLS_CC);
        !           200:        }
        !           201: 
        !           202:        if (previous) {
        !           203:                zend_update_property(default_exception_ce, object, "previous", sizeof("previous")-1, previous TSRMLS_CC);
        !           204:        }
        !           205: }
        !           206: /* }}} */
        !           207: 
        !           208: /* {{{ proto ErrorException::__construct(string message, int code, int severity [, string filename [, int lineno [, Exception previous]]])
        !           209:    ErrorException constructor */
        !           210: ZEND_METHOD(error_exception, __construct)
        !           211: {
        !           212:        char  *message = NULL, *filename = NULL;
        !           213:        long   code = 0, severity = E_ERROR, lineno;
        !           214:        zval  *object, *previous = NULL;
        !           215:        int    argc = ZEND_NUM_ARGS(), message_len, filename_len;
        !           216: 
        !           217:        if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, "|sllslO!", &message, &message_len, &code, &severity, &filename, &filename_len, &lineno, &previous, default_exception_ce) == FAILURE) {
        !           218:                zend_error(E_ERROR, "Wrong parameters for ErrorException([string $exception [, long $code, [ long $severity, [ string $filename, [ long $lineno  [, Exception $previous = NULL]]]]]])");
        !           219:        }
        !           220: 
        !           221:        object = getThis();
        !           222: 
        !           223:        if (message) {
        !           224:                zend_update_property_string(default_exception_ce, object, "message", sizeof("message")-1, message TSRMLS_CC);
        !           225:        }
        !           226: 
        !           227:        if (code) {
        !           228:                zend_update_property_long(default_exception_ce, object, "code", sizeof("code")-1, code TSRMLS_CC);
        !           229:        }
        !           230: 
        !           231:        if (previous) {
        !           232:                zend_update_property(default_exception_ce, object, "previous", sizeof("previous")-1, previous TSRMLS_CC);
        !           233:        }
        !           234: 
        !           235:        zend_update_property_long(default_exception_ce, object, "severity", sizeof("severity")-1, severity TSRMLS_CC);
        !           236: 
        !           237:        if (argc >= 4) {
        !           238:            zend_update_property_string(default_exception_ce, object, "file", sizeof("file")-1, filename TSRMLS_CC);
        !           239:        if (argc < 5) {
        !           240:            lineno = 0; /* invalidate lineno */
        !           241:        }
        !           242:        zend_update_property_long(default_exception_ce, object, "line", sizeof("line")-1, lineno TSRMLS_CC);
        !           243:        }
        !           244: }
        !           245: /* }}} */
        !           246: 
        !           247: #define DEFAULT_0_PARAMS \
        !           248:        if (zend_parse_parameters_none() == FAILURE) { \
        !           249:                return; \
        !           250:        }
        !           251: 
        !           252: static void _default_exception_get_entry(zval *object, char *name, int name_len, zval *return_value TSRMLS_DC) /* {{{ */
        !           253: {
        !           254:        zval *value;
        !           255: 
        !           256:        value = zend_read_property(default_exception_ce, object, name, name_len, 0 TSRMLS_CC);
        !           257: 
        !           258:        *return_value = *value;
        !           259:        zval_copy_ctor(return_value);
        !           260:        INIT_PZVAL(return_value);
        !           261: }
        !           262: /* }}} */
        !           263: 
        !           264: /* {{{ proto string Exception::getFile()
        !           265:    Get the file in which the exception occurred */
        !           266: ZEND_METHOD(exception, getFile)
        !           267: {
        !           268:        DEFAULT_0_PARAMS;
        !           269: 
        !           270:        _default_exception_get_entry(getThis(), "file", sizeof("file")-1, return_value TSRMLS_CC);
        !           271: }
        !           272: /* }}} */
        !           273: 
        !           274: /* {{{ proto int Exception::getLine()
        !           275:    Get the line in which the exception occurred */
        !           276: ZEND_METHOD(exception, getLine)
        !           277: {
        !           278:        DEFAULT_0_PARAMS;
        !           279: 
        !           280:        _default_exception_get_entry(getThis(), "line", sizeof("line")-1, return_value TSRMLS_CC);
        !           281: }
        !           282: /* }}} */
        !           283: 
        !           284: /* {{{ proto string Exception::getMessage()
        !           285:    Get the exception message */
        !           286: ZEND_METHOD(exception, getMessage)
        !           287: {
        !           288:        DEFAULT_0_PARAMS;
        !           289: 
        !           290:        _default_exception_get_entry(getThis(), "message", sizeof("message")-1, return_value TSRMLS_CC);
        !           291: }
        !           292: /* }}} */
        !           293: 
        !           294: /* {{{ proto int Exception::getCode()
        !           295:    Get the exception code */
        !           296: ZEND_METHOD(exception, getCode)
        !           297: {
        !           298:        DEFAULT_0_PARAMS;
        !           299: 
        !           300:        _default_exception_get_entry(getThis(), "code", sizeof("code")-1, return_value TSRMLS_CC);
        !           301: }
        !           302: /* }}} */
        !           303: 
        !           304: /* {{{ proto array Exception::getTrace()
        !           305:    Get the stack trace for the location in which the exception occurred */
        !           306: ZEND_METHOD(exception, getTrace)
        !           307: {
        !           308:        DEFAULT_0_PARAMS;
        !           309: 
        !           310:        _default_exception_get_entry(getThis(), "trace", sizeof("trace")-1, return_value TSRMLS_CC);
        !           311: }
        !           312: /* }}} */
        !           313: 
        !           314: /* {{{ proto int ErrorException::getSeverity()
        !           315:    Get the exception severity */
        !           316: ZEND_METHOD(error_exception, getSeverity)
        !           317: {
        !           318:        DEFAULT_0_PARAMS;
        !           319: 
        !           320:        _default_exception_get_entry(getThis(), "severity", sizeof("severity")-1, return_value TSRMLS_CC);
        !           321: }
        !           322: /* }}} */
        !           323: 
        !           324: /* {{{ gettraceasstring() macros */
        !           325: #define TRACE_APPEND_CHR(chr)                                            \
        !           326:        *str = (char*)erealloc(*str, *len + 1 + 1);                          \
        !           327:        (*str)[(*len)++] = chr
        !           328: 
        !           329: #define TRACE_APPEND_STRL(val, vallen)                                   \
        !           330:        {                                                                    \
        !           331:                int l = vallen;                                                  \
        !           332:                *str = (char*)erealloc(*str, *len + l + 1);                      \
        !           333:                memcpy((*str) + *len, val, l);                                   \
        !           334:                *len += l;                                                       \
        !           335:        }
        !           336: 
        !           337: #define TRACE_APPEND_STR(val)                                            \
        !           338:        TRACE_APPEND_STRL(val, sizeof(val)-1)
        !           339: 
        !           340: #define TRACE_APPEND_KEY(key)                                            \
        !           341:        if (zend_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
        !           342:            TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));           \
        !           343:        }
        !           344: 
        !           345: /* }}} */
        !           346: 
        !           347: static int _build_trace_args(zval **arg TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
        !           348: {
        !           349:        char **str;
        !           350:        int *len;
        !           351: 
        !           352:        str = va_arg(args, char**);
        !           353:        len = va_arg(args, int*);
        !           354: 
        !           355:        /* the trivial way would be to do:
        !           356:         * conver_to_string_ex(arg);
        !           357:         * append it and kill the now tmp arg.
        !           358:         * but that could cause some E_NOTICE and also damn long lines.
        !           359:         */
        !           360: 
        !           361:        switch (Z_TYPE_PP(arg)) {
        !           362:                case IS_NULL:
        !           363:                        TRACE_APPEND_STR("NULL, ");
        !           364:                        break;
        !           365:                case IS_STRING: {
        !           366:                        int l_added;
        !           367:                        TRACE_APPEND_CHR('\'');
        !           368:                        if (Z_STRLEN_PP(arg) > 15) {
        !           369:                                TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
        !           370:                                TRACE_APPEND_STR("...', ");
        !           371:                                l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
        !           372:                        } else {
        !           373:                                l_added = Z_STRLEN_PP(arg);
        !           374:                                TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
        !           375:                                TRACE_APPEND_STR("', ");
        !           376:                                l_added += 3 + 1;
        !           377:                        }
        !           378:                        while (--l_added) {
        !           379:                                if ((*str)[*len - l_added] < 32) {
        !           380:                                        (*str)[*len - l_added] = '?';
        !           381:                                }
        !           382:                        }
        !           383:                        break;
        !           384:                }
        !           385:                case IS_BOOL:
        !           386:                        if (Z_LVAL_PP(arg)) {
        !           387:                                TRACE_APPEND_STR("true, ");
        !           388:                        } else {
        !           389:                                TRACE_APPEND_STR("false, ");
        !           390:                        }
        !           391:                        break;
        !           392:                case IS_RESOURCE:
        !           393:                        TRACE_APPEND_STR("Resource id #");
        !           394:                        /* break; */
        !           395:                case IS_LONG: {
        !           396:                        long lval = Z_LVAL_PP(arg);
        !           397:                        char s_tmp[MAX_LENGTH_OF_LONG + 1];
        !           398:                        int l_tmp = zend_sprintf(s_tmp, "%ld", lval);  /* SAFE */
        !           399:                        TRACE_APPEND_STRL(s_tmp, l_tmp);
        !           400:                        TRACE_APPEND_STR(", ");
        !           401:                        break;
        !           402:                }
        !           403:                case IS_DOUBLE: {
        !           404:                        double dval = Z_DVAL_PP(arg);
        !           405:                        char *s_tmp;
        !           406:                        int l_tmp;
        !           407: 
        !           408:                        s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
        !           409:                        l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval);  /* SAFE */
        !           410:                        TRACE_APPEND_STRL(s_tmp, l_tmp);
        !           411:                        /* %G already handles removing trailing zeros from the fractional part, yay */
        !           412:                        efree(s_tmp);
        !           413:                        TRACE_APPEND_STR(", ");
        !           414:                        break;
        !           415:                }
        !           416:                case IS_ARRAY:
        !           417:                        TRACE_APPEND_STR("Array, ");
        !           418:                        break;
        !           419:                case IS_OBJECT: {
        !           420:                        char *class_name;
        !           421:                        zend_uint class_name_len;
        !           422:                        int dup;
        !           423: 
        !           424:                        TRACE_APPEND_STR("Object(");
        !           425: 
        !           426:                        dup = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC);
        !           427: 
        !           428:                        TRACE_APPEND_STRL(class_name, class_name_len);
        !           429:                        if(!dup) {
        !           430:                                efree(class_name);
        !           431:                        }
        !           432: 
        !           433:                        TRACE_APPEND_STR("), ");
        !           434:                        break;
        !           435:                }
        !           436:                default:
        !           437:                        break;
        !           438:        }
        !           439:        return ZEND_HASH_APPLY_KEEP;
        !           440: }
        !           441: /* }}} */
        !           442: 
        !           443: static int _build_trace_string(zval **frame TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
        !           444: {
        !           445:        char *s_tmp, **str;
        !           446:        int *len, *num;
        !           447:        long line;
        !           448:        HashTable *ht = Z_ARRVAL_PP(frame);
        !           449:        zval **file, **tmp;
        !           450: 
        !           451:        str = va_arg(args, char**);
        !           452:        len = va_arg(args, int*);
        !           453:        num = va_arg(args, int*);
        !           454: 
        !           455:        s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
        !           456:        sprintf(s_tmp, "#%d ", (*num)++);
        !           457:        TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
        !           458:        efree(s_tmp);
        !           459:        if (zend_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
        !           460:                if (zend_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
        !           461:                        line = Z_LVAL_PP(tmp);
        !           462:                } else {
        !           463:                        line = 0;
        !           464:                }
        !           465:                s_tmp = emalloc(Z_STRLEN_PP(file) + MAX_LENGTH_OF_LONG + 4 + 1);
        !           466:                sprintf(s_tmp, "%s(%ld): ", Z_STRVAL_PP(file), line);
        !           467:                TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
        !           468:                efree(s_tmp);
        !           469:        } else {
        !           470:                TRACE_APPEND_STR("[internal function]: ");
        !           471:        }
        !           472:        TRACE_APPEND_KEY("class");
        !           473:        TRACE_APPEND_KEY("type");
        !           474:        TRACE_APPEND_KEY("function");
        !           475:        TRACE_APPEND_CHR('(');
        !           476:        if (zend_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
        !           477:                int last_len = *len;
        !           478:                zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp) TSRMLS_CC, (apply_func_args_t)_build_trace_args, 2, str, len);
        !           479:                if (last_len != *len) {
        !           480:                        *len -= 2; /* remove last ', ' */
        !           481:                }
        !           482:        }
        !           483:        TRACE_APPEND_STR(")\n");
        !           484:        return ZEND_HASH_APPLY_KEEP;
        !           485: }
        !           486: /* }}} */
        !           487: 
        !           488: /* {{{ proto string Exception::getTraceAsString()
        !           489:    Obtain the backtrace for the exception as a string (instead of an array) */
        !           490: ZEND_METHOD(exception, getTraceAsString)
        !           491: {
        !           492:        zval *trace;
        !           493:        char *res, **str, *s_tmp;
        !           494:        int res_len = 0, *len = &res_len, num = 0;
        !           495: 
        !           496:        DEFAULT_0_PARAMS;
        !           497:        
        !           498:        res = estrdup("");
        !           499:        str = &res;
        !           500: 
        !           501:        trace = zend_read_property(default_exception_ce, getThis(), "trace", sizeof("trace")-1, 1 TSRMLS_CC);
        !           502:        zend_hash_apply_with_arguments(Z_ARRVAL_P(trace) TSRMLS_CC, (apply_func_args_t)_build_trace_string, 3, str, len, &num);
        !           503: 
        !           504:        s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 7 + 1);
        !           505:        sprintf(s_tmp, "#%d {main}", num);
        !           506:        TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
        !           507:        efree(s_tmp);
        !           508: 
        !           509:        res[res_len] = '\0';    
        !           510:        RETURN_STRINGL(res, res_len, 0); 
        !           511: }
        !           512: /* }}} */
        !           513: 
        !           514: /* {{{ proto string Exception::getPrevious()
        !           515:    Return previous Exception or NULL. */
        !           516: ZEND_METHOD(exception, getPrevious)
        !           517: {
        !           518:        zval *previous;
        !           519: 
        !           520:        DEFAULT_0_PARAMS;
        !           521: 
        !           522:        previous = zend_read_property(default_exception_ce, getThis(), "previous", sizeof("previous")-1, 1 TSRMLS_CC);
        !           523:        RETURN_ZVAL(previous, 1, 0);
        !           524: }
        !           525: 
        !           526: int zend_spprintf(char **message, int max_len, char *format, ...) /* {{{ */
        !           527: {
        !           528:        va_list arg;
        !           529:        int len;
        !           530: 
        !           531:        va_start(arg, format);
        !           532:        len = zend_vspprintf(message, max_len, format, arg);
        !           533:        va_end(arg);
        !           534:        return len;
        !           535: }
        !           536: /* }}} */
        !           537: 
        !           538: /* {{{ proto string Exception::__toString()
        !           539:    Obtain the string representation of the Exception object */
        !           540: ZEND_METHOD(exception, __toString)
        !           541: {
        !           542:        zval message, file, line, *trace, *exception;
        !           543:        char *str, *prev_str;
        !           544:        int len = 0;
        !           545:        zend_fcall_info fci;
        !           546:        zval fname;
        !           547:        
        !           548:        DEFAULT_0_PARAMS;
        !           549:        
        !           550:        str = estrndup("", 0);
        !           551: 
        !           552:        exception = getThis();
        !           553:        ZVAL_STRINGL(&fname, "gettraceasstring", sizeof("gettraceasstring")-1, 1);
        !           554: 
        !           555:        while (exception && Z_TYPE_P(exception) == IS_OBJECT) {
        !           556:                prev_str = str;
        !           557:                _default_exception_get_entry(exception, "message", sizeof("message")-1, &message TSRMLS_CC);
        !           558:                _default_exception_get_entry(exception, "file", sizeof("file")-1, &file TSRMLS_CC);
        !           559:                _default_exception_get_entry(exception, "line", sizeof("line")-1, &line TSRMLS_CC);
        !           560: 
        !           561:                convert_to_string(&message);
        !           562:                convert_to_string(&file);
        !           563:                convert_to_long(&line);
        !           564: 
        !           565:                fci.size = sizeof(fci);
        !           566:                fci.function_table = &Z_OBJCE_P(exception)->function_table;
        !           567:                fci.function_name = &fname;
        !           568:                fci.symbol_table = NULL;
        !           569:                fci.object_ptr = exception;
        !           570:                fci.retval_ptr_ptr = &trace;
        !           571:                fci.param_count = 0;
        !           572:                fci.params = NULL;
        !           573:                fci.no_separation = 1;
        !           574: 
        !           575:                zend_call_function(&fci, NULL TSRMLS_CC);
        !           576: 
        !           577:                if (Z_TYPE_P(trace) != IS_STRING) {
        !           578:                        zval_ptr_dtor(&trace);
        !           579:                        trace = NULL;
        !           580:                }
        !           581: 
        !           582:                if (Z_STRLEN(message) > 0) {
        !           583:                        len = zend_spprintf(&str, 0, "exception '%s' with message '%s' in %s:%ld\nStack trace:\n%s%s%s",
        !           584:                                                                Z_OBJCE_P(exception)->name, Z_STRVAL(message), Z_STRVAL(file), Z_LVAL(line),
        !           585:                                                                (trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n",
        !           586:                                                                len ? "\n\nNext " : "", prev_str);
        !           587:                } else {
        !           588:                        len = zend_spprintf(&str, 0, "exception '%s' in %s:%ld\nStack trace:\n%s%s%s",
        !           589:                                                                Z_OBJCE_P(exception)->name, Z_STRVAL(file), Z_LVAL(line),
        !           590:                                                                (trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n",
        !           591:                                                                len ? "\n\nNext " : "", prev_str);
        !           592:                }
        !           593:                efree(prev_str);
        !           594:                zval_dtor(&message);
        !           595:                zval_dtor(&file);
        !           596:                zval_dtor(&line);
        !           597: 
        !           598:                exception = zend_read_property(default_exception_ce, exception, "previous", sizeof("previous")-1, 0 TSRMLS_CC);
        !           599: 
        !           600:                if (trace) {
        !           601:                        zval_ptr_dtor(&trace);
        !           602:                }
        !           603:        }
        !           604:        zval_dtor(&fname);
        !           605: 
        !           606:        /* We store the result in the private property string so we can access
        !           607:         * the result in uncaught exception handlers without memleaks. */
        !           608:        zend_update_property_string(default_exception_ce, getThis(), "string", sizeof("string")-1, str TSRMLS_CC);
        !           609: 
        !           610:        RETURN_STRINGL(str, len, 0);
        !           611: }
        !           612: /* }}} */
        !           613: 
        !           614: /* {{{ internal structs */
        !           615: /* All functions that may be used in uncaught exception handlers must be final
        !           616:  * and must not throw exceptions. Otherwise we would need a facility to handle
        !           617:  * such exceptions in that handler.
        !           618:  * Also all getXY() methods are final because thy serve as read only access to
        !           619:  * their corresponding properties, no more, no less. If after all you need to
        !           620:  * override somthing then it is method __toString().
        !           621:  * And never try to change the state of exceptions and never implement anything
        !           622:  * that gives the user anything to accomplish this.
        !           623:  */
        !           624: ZEND_BEGIN_ARG_INFO_EX(arginfo_exception___construct, 0, 0, 0)
        !           625:        ZEND_ARG_INFO(0, message)
        !           626:        ZEND_ARG_INFO(0, code)
        !           627:        ZEND_ARG_INFO(0, previous)
        !           628: ZEND_END_ARG_INFO()
        !           629: 
        !           630: const static zend_function_entry default_exception_functions[] = {
        !           631:        ZEND_ME(exception, __clone, NULL, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
        !           632:        ZEND_ME(exception, __construct, arginfo_exception___construct, ZEND_ACC_PUBLIC)
        !           633:        ZEND_ME(exception, getMessage, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
        !           634:        ZEND_ME(exception, getCode, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
        !           635:        ZEND_ME(exception, getFile, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
        !           636:        ZEND_ME(exception, getLine, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
        !           637:        ZEND_ME(exception, getTrace, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
        !           638:        ZEND_ME(exception, getPrevious, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
        !           639:        ZEND_ME(exception, getTraceAsString, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
        !           640:        ZEND_ME(exception, __toString, NULL, 0)
        !           641:        {NULL, NULL, NULL}
        !           642: };
        !           643: 
        !           644: ZEND_BEGIN_ARG_INFO_EX(arginfo_error_exception___construct, 0, 0, 0)
        !           645:        ZEND_ARG_INFO(0, message)
        !           646:        ZEND_ARG_INFO(0, code)
        !           647:        ZEND_ARG_INFO(0, severity)
        !           648:        ZEND_ARG_INFO(0, filename)
        !           649:        ZEND_ARG_INFO(0, lineno)
        !           650:        ZEND_ARG_INFO(0, previous)
        !           651: ZEND_END_ARG_INFO()
        !           652: 
        !           653: static const zend_function_entry error_exception_functions[] = {
        !           654:        ZEND_ME(error_exception, __construct, arginfo_error_exception___construct, ZEND_ACC_PUBLIC)
        !           655:        ZEND_ME(error_exception, getSeverity, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
        !           656:        {NULL, NULL, NULL}
        !           657: };
        !           658: /* }}} */
        !           659: 
        !           660: void zend_register_default_exception(TSRMLS_D) /* {{{ */
        !           661: {
        !           662:        zend_class_entry ce;
        !           663: 
        !           664:        INIT_CLASS_ENTRY(ce, "Exception", default_exception_functions);
        !           665:        default_exception_ce = zend_register_internal_class(&ce TSRMLS_CC);
        !           666:        default_exception_ce->create_object = zend_default_exception_new;
        !           667:        memcpy(&default_exception_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
        !           668:        default_exception_handlers.clone_obj = NULL;
        !           669: 
        !           670:        zend_declare_property_string(default_exception_ce, "message", sizeof("message")-1, "", ZEND_ACC_PROTECTED TSRMLS_CC);
        !           671:        zend_declare_property_string(default_exception_ce, "string", sizeof("string")-1, "", ZEND_ACC_PRIVATE TSRMLS_CC);
        !           672:        zend_declare_property_long(default_exception_ce, "code", sizeof("code")-1, 0, ZEND_ACC_PROTECTED TSRMLS_CC);
        !           673:        zend_declare_property_null(default_exception_ce, "file", sizeof("file")-1, ZEND_ACC_PROTECTED TSRMLS_CC);
        !           674:        zend_declare_property_null(default_exception_ce, "line", sizeof("line")-1, ZEND_ACC_PROTECTED TSRMLS_CC);
        !           675:        zend_declare_property_null(default_exception_ce, "trace", sizeof("trace")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
        !           676:        zend_declare_property_null(default_exception_ce, "previous", sizeof("previous")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
        !           677: 
        !           678:        INIT_CLASS_ENTRY(ce, "ErrorException", error_exception_functions);
        !           679:        error_exception_ce = zend_register_internal_class_ex(&ce, default_exception_ce, NULL TSRMLS_CC);
        !           680:        error_exception_ce->create_object = zend_error_exception_new;
        !           681:        zend_declare_property_long(error_exception_ce, "severity", sizeof("severity")-1, E_ERROR, ZEND_ACC_PROTECTED TSRMLS_CC);
        !           682: }
        !           683: /* }}} */
        !           684: 
        !           685: ZEND_API zend_class_entry *zend_exception_get_default(TSRMLS_D) /* {{{ */
        !           686: {
        !           687:        return default_exception_ce;
        !           688: }
        !           689: /* }}} */
        !           690: 
        !           691: ZEND_API zend_class_entry *zend_get_error_exception(TSRMLS_D) /* {{{ */
        !           692: {
        !           693:        return error_exception_ce;
        !           694: }
        !           695: /* }}} */
        !           696: 
        !           697: ZEND_API zval * zend_throw_exception(zend_class_entry *exception_ce, char *message, long code TSRMLS_DC) /* {{{ */
        !           698: {
        !           699:        zval *ex;
        !           700: 
        !           701:        MAKE_STD_ZVAL(ex);
        !           702:        if (exception_ce) {
        !           703:                if (!instanceof_function(exception_ce, default_exception_ce TSRMLS_CC)) {
        !           704:                        zend_error(E_NOTICE, "Exceptions must be derived from the Exception base class");
        !           705:                        exception_ce = default_exception_ce;
        !           706:                }
        !           707:        } else {
        !           708:                exception_ce = default_exception_ce;
        !           709:        }
        !           710:        object_init_ex(ex, exception_ce);
        !           711: 
        !           712: 
        !           713:        if (message) {
        !           714:                zend_update_property_string(default_exception_ce, ex, "message", sizeof("message")-1, message TSRMLS_CC);
        !           715:        }
        !           716:        if (code) {
        !           717:                zend_update_property_long(default_exception_ce, ex, "code", sizeof("code")-1, code TSRMLS_CC);
        !           718:        }
        !           719: 
        !           720:        zend_throw_exception_internal(ex TSRMLS_CC);
        !           721:        return ex;
        !           722: }
        !           723: /* }}} */
        !           724: 
        !           725: ZEND_API zval * zend_throw_exception_ex(zend_class_entry *exception_ce, long code TSRMLS_DC, char *format, ...) /* {{{ */
        !           726: {
        !           727:        va_list arg;
        !           728:        char *message;
        !           729:        zval *zexception;
        !           730: 
        !           731:        va_start(arg, format);
        !           732:        zend_vspprintf(&message, 0, format, arg);
        !           733:        va_end(arg);
        !           734:        zexception = zend_throw_exception(exception_ce, message, code TSRMLS_CC);
        !           735:        efree(message);
        !           736:        return zexception;
        !           737: }
        !           738: /* }}} */
        !           739: 
        !           740: ZEND_API zval * zend_throw_error_exception(zend_class_entry *exception_ce, char *message, long code, int severity TSRMLS_DC) /* {{{ */
        !           741: {
        !           742:        zval *ex = zend_throw_exception(exception_ce, message, code TSRMLS_CC);
        !           743:        zend_update_property_long(default_exception_ce, ex, "severity", sizeof("severity")-1, severity TSRMLS_CC);
        !           744:        return ex;
        !           745: }
        !           746: /* }}} */
        !           747: 
        !           748: static void zend_error_va(int type, const char *file, uint lineno, const char *format, ...) /* {{{ */
        !           749: {
        !           750:        va_list args;
        !           751: 
        !           752:        va_start(args, format);
        !           753:        zend_error_cb(type, file, lineno, format, args);
        !           754:        va_end(args);
        !           755: }
        !           756: /* }}} */
        !           757: 
        !           758: /* This function doesn't return if it uses E_ERROR */
        !           759: ZEND_API void zend_exception_error(zval *exception, int severity TSRMLS_DC) /* {{{ */
        !           760: {
        !           761:        zend_class_entry *ce_exception = Z_OBJCE_P(exception);
        !           762:        if (instanceof_function(ce_exception, default_exception_ce TSRMLS_CC)) {
        !           763:                zval *str, *file, *line;
        !           764: 
        !           765:                EG(exception) = NULL;
        !           766: 
        !           767:                zend_call_method_with_0_params(&exception, ce_exception, NULL, "__tostring", &str);
        !           768:                if (!EG(exception)) {
        !           769:                        if (Z_TYPE_P(str) != IS_STRING) {
        !           770:                                zend_error(E_WARNING, "%s::__toString() must return a string", ce_exception->name);
        !           771:                        } else {
        !           772:                                zend_update_property_string(default_exception_ce, exception, "string", sizeof("string")-1, EG(exception) ? ce_exception->name : Z_STRVAL_P(str) TSRMLS_CC);
        !           773:                        }
        !           774:                }
        !           775:                zval_ptr_dtor(&str);
        !           776: 
        !           777:                if (EG(exception)) {
        !           778:                        /* do the best we can to inform about the inner exception */
        !           779:                        if (instanceof_function(ce_exception, default_exception_ce TSRMLS_CC)) {
        !           780:                                file = zend_read_property(default_exception_ce, EG(exception), "file", sizeof("file")-1, 1 TSRMLS_CC);
        !           781:                                line = zend_read_property(default_exception_ce, EG(exception), "line", sizeof("line")-1, 1 TSRMLS_CC);
        !           782:                        } else {
        !           783:                                file = NULL;
        !           784:                                line = NULL;
        !           785:                        }
        !           786:                        zend_error_va(E_WARNING, file ? Z_STRVAL_P(file) : NULL, line ? Z_LVAL_P(line) : 0, "Uncaught %s in exception handling during call to %s::__tostring()", Z_OBJCE_P(EG(exception))->name, ce_exception->name);
        !           787:                }
        !           788: 
        !           789:                str = zend_read_property(default_exception_ce, exception, "string", sizeof("string")-1, 1 TSRMLS_CC);
        !           790:                file = zend_read_property(default_exception_ce, exception, "file", sizeof("file")-1, 1 TSRMLS_CC);
        !           791:                line = zend_read_property(default_exception_ce, exception, "line", sizeof("line")-1, 1 TSRMLS_CC);
        !           792: 
        !           793:                zend_error_va(severity, Z_STRVAL_P(file), Z_LVAL_P(line), "Uncaught %s\n  thrown", Z_STRVAL_P(str));
        !           794:        } else {
        !           795:                zend_error(severity, "Uncaught exception '%s'", ce_exception->name);
        !           796:        }
        !           797: }
        !           798: /* }}} */
        !           799: 
        !           800: ZEND_API void zend_throw_exception_object(zval *exception TSRMLS_DC) /* {{{ */
        !           801: {
        !           802:        zend_class_entry *exception_ce;
        !           803: 
        !           804:        if (exception == NULL || Z_TYPE_P(exception) != IS_OBJECT) {
        !           805:                zend_error(E_ERROR, "Need to supply an object when throwing an exception");
        !           806:        }
        !           807: 
        !           808:        exception_ce = Z_OBJCE_P(exception);
        !           809: 
        !           810:        if (!exception_ce || !instanceof_function(exception_ce, default_exception_ce TSRMLS_CC)) {
        !           811:                zend_error(E_ERROR, "Exceptions must be valid objects derived from the Exception base class");
        !           812:        }
        !           813:        zend_throw_exception_internal(exception TSRMLS_CC);
        !           814: }
        !           815: /* }}} */
        !           816: 
        !           817: /*
        !           818:  * Local variables:
        !           819:  * tab-width: 4
        !           820:  * c-basic-offset: 4
        !           821:  * indent-tabs-mode: t
        !           822:  * End:
        !           823:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>