Annotation of embedaddon/php/Zend/zend_exceptions.c, revision 1.1.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>