diff options
author | Marcus Boerger <helly@php.net> | 2008-07-12 14:56:51 +0000 |
---|---|---|
committer | Marcus Boerger <helly@php.net> | 2008-07-12 14:56:51 +0000 |
commit | 5197ffd54fd8d63139c9abaa87445e3f27c8b32d (patch) | |
tree | 04f2ed8d252c6d086a46db5e529f172159469f33 /Zend/zend_exceptions.c | |
parent | 7e6861866467b2fbe308f18bfe0723c9938821a9 (diff) | |
download | php-git-5197ffd54fd8d63139c9abaa87445e3f27c8b32d.tar.gz |
- Add support for linking exceptions (implements TODO)
# Right now backtrace is broken, for internal functions I only see the
# first char and debugging reveals the length of the function name is seen
# as one when building the trace. There is something out of the scope of
# this patch broken.
Diffstat (limited to 'Zend/zend_exceptions.c')
-rw-r--r-- | Zend/zend_exceptions.c | 137 |
1 files changed, 78 insertions, 59 deletions
diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index fa633cea69..8ec5ecdb5e 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -33,13 +33,11 @@ zend_class_entry *error_exception_ce; static zend_object_handlers default_exception_handlers; ZEND_API void (*zend_throw_exception_hook)(zval *ex TSRMLS_DC); - void zend_throw_exception_internal(zval *exception TSRMLS_DC) /* {{{ */ { if (exception != NULL) { if (EG(exception)) { - /* FIXME: bail out? */ - return; + zend_update_property(default_exception_ce, exception, "previous", sizeof("previous")-1, EG(exception) TSRMLS_CC); } EG(exception) = exception; } @@ -122,17 +120,17 @@ ZEND_METHOD(exception, __clone) } /* }}} */ -/* {{{ proto Exception::__construct(string message, int code) U +/* {{{ proto Exception::__construct(string message, int code [, Exception previous]) U Exception constructor */ ZEND_METHOD(exception, __construct) { void *message = NULL; long code = 0; - zval *object; + zval *object, *previous = NULL; int argc = ZEND_NUM_ARGS(), message_len; zend_uchar message_type; - if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, "|tl", &message, &message_len, &message_type, &code) == FAILURE) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, "|tlO", &message, &message_len, &message_type, &code, &previous, default_exception_ce) == FAILURE) { zend_error(E_ERROR, "Wrong parameters for Exception([string $exception [, long $code ]])"); } @@ -149,20 +147,24 @@ ZEND_METHOD(exception, __construct) if (code) { zend_update_property_long(default_exception_ce, object, "code", sizeof("code")-1, code TSRMLS_CC); } + + if (previous) { + zend_update_property(default_exception_ce, object, "previous", sizeof("previous")-1, previous TSRMLS_CC); + } } /* }}} */ -/* {{{ proto ErrorException::__construct(string message, int code, int severity [, string filename [, int lineno]]) U +/* {{{ proto ErrorException::__construct(string message, int code, int severity [, string filename [, int lineno [, Exception previous]]]) U ErrorException constructor */ ZEND_METHOD(error_exception, __construct) { void *message = NULL, *filename = NULL; long code = 0, severity = E_ERROR, lineno; - zval *object; + zval *object, *previous = NULL; int argc = ZEND_NUM_ARGS(), message_len, filename_len; zend_uchar message_type, file_type; - if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, "|tlltl", &message, &message_len, &message_type, &code, &severity, &filename, &filename_len, &file_type, &lineno) == FAILURE) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, "|tlltlO", &message, &message_len, &message_type, &code, &severity, &filename, &filename_len, &file_type, &lineno, &previous, default_exception_ce) == FAILURE) { zend_error(E_ERROR, "Wrong parameters for ErrorException([string $exception [, long $code, [ long $severity, [ string $filename, [ long $lineno ]]]]])"); } @@ -180,6 +182,10 @@ ZEND_METHOD(error_exception, __construct) zend_update_property_long(default_exception_ce, object, "code", sizeof("code")-1, code TSRMLS_CC); } + if (previous) { + zend_update_property(default_exception_ce, object, "previous", sizeof("previous")-1, previous TSRMLS_CC); + } + zend_update_property_long(default_exception_ce, object, "severity", sizeof("severity")-1, severity TSRMLS_CC); if (argc >= 4) { @@ -302,8 +308,8 @@ ZEND_METHOD(error_exception, getSeverity) zval copy; \ int use_copy; \ zend_make_printable_zval((zv), ©, &use_copy); \ - TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \ - zval_dtor(©); \ + TRACE_APPEND_STRL(Z_STRVAL_P((use_copy ? © : (zv))), Z_STRLEN_P((use_copy ? © : (zv)))); \ + if (use_copy) zval_dtor(©); \ } else { \ TRACE_APPEND_STRL(Z_STRVAL_P((zv)), Z_STRLEN_P((zv))); \ } @@ -311,17 +317,9 @@ ZEND_METHOD(error_exception, getSeverity) #define TRACE_APPEND_STR(val) \ TRACE_APPEND_STRL(val, sizeof(val)-1) -#define TRACE_APPEND_KEY(key) \ +#define TRACE_APPEND_KEY(key,dump) \ if (zend_ascii_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \ - if (Z_TYPE_PP(tmp) == IS_UNICODE) { \ - zval copy; \ - int use_copy; \ - zend_make_printable_zval(*tmp, ©, &use_copy); \ - TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \ - zval_dtor(©); \ - } else { \ - TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); \ - } \ + TRACE_APPEND_ZVAL(*tmp); \ } /* }}} */ @@ -495,9 +493,9 @@ static int _build_trace_string(zval **frame, int num_args, va_list args, zend_ha } else { TRACE_APPEND_STR("[internal function]: "); } - TRACE_APPEND_KEY("class"); - TRACE_APPEND_KEY("type"); - TRACE_APPEND_KEY("function"); + TRACE_APPEND_KEY("class",0); + TRACE_APPEND_KEY("type",0); + TRACE_APPEND_KEY("function",1); TRACE_APPEND_CHR('('); if (zend_ascii_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) { int last_len = *len; @@ -532,6 +530,15 @@ ZEND_METHOD(exception, getTraceAsString) } /* }}} */ +/* {{{ proto string Exception::getPrevious() + Return previous Exception or NULL. */ +ZEND_METHOD(exception, getPrevious) +{ + zval *previous; + previous = zend_read_property(default_exception_ce, getThis(), "previous", sizeof("previous")-1, 1 TSRMLS_CC); + RETURN_ZVAL(previous, 1, 0); +} + int zend_spprintf(char **message, int max_len, char *format, ...) /* {{{ */ { va_list arg; @@ -548,46 +555,58 @@ int zend_spprintf(char **message, int max_len, char *format, ...) /* {{{ */ Obtain the string representation of the Exception object */ ZEND_METHOD(exception, __toString) { - zval message, file, line, *trace; - char *str; - int len; + zval message, file, line, *trace, *exception; + char *str = estrndup("", 0), *prev_str; + int len = 0; zend_fcall_info fci; zval fname; - _default_exception_get_entry(getThis(), "message", sizeof("message")-1, &message TSRMLS_CC); - _default_exception_get_entry(getThis(), "file", sizeof("file")-1, &file TSRMLS_CC); - _default_exception_get_entry(getThis(), "line", sizeof("line")-1, &line TSRMLS_CC); + exception = getThis(); + ZVAL_ASCII_STRINGL(&fname, "gettraceasstring", sizeof("gettraceasstring")-1, 1); - convert_to_long(&line); + while (exception && Z_TYPE_P(exception) == IS_OBJECT) { + prev_str = str; + _default_exception_get_entry(exception, "message", sizeof("message")-1, &message TSRMLS_CC); + _default_exception_get_entry(exception, "file", sizeof("file")-1, &file TSRMLS_CC); + _default_exception_get_entry(exception, "line", sizeof("line")-1, &line TSRMLS_CC); - ZVAL_ASCII_STRINGL(&fname, "gettraceasstring", sizeof("gettraceasstring")-1, 1); + convert_to_long(&line); - fci.size = sizeof(fci); - fci.function_table = &Z_OBJCE_P(getThis())->function_table; - fci.function_name = &fname; - fci.symbol_table = NULL; - fci.object_pp = &getThis(); - fci.retval_ptr_ptr = &trace; - fci.param_count = 0; - fci.params = NULL; - fci.no_separation = 1; - - zend_call_function(&fci, NULL TSRMLS_CC); - zval_dtor(&fname); + fci.size = sizeof(fci); + fci.function_table = &Z_OBJCE_P(getThis())->function_table; + fci.function_name = &fname; + fci.symbol_table = NULL; + fci.object_pp = &exception; + fci.retval_ptr_ptr = &trace; + fci.param_count = 0; + fci.params = NULL; + fci.no_separation = 1; - if (Z_TYPE_P(trace) != IS_STRING && Z_TYPE_P(trace) != IS_UNICODE) { - trace = NULL; - } + zend_call_function(&fci, NULL TSRMLS_CC); - if (Z_UNILEN(message) > 0) { - len = zend_spprintf(&str, 0, "exception '%v' with message '%R' in %R:%ld\nStack trace:\n%s", - Z_OBJCE_P(getThis())->name, Z_TYPE(message), Z_UNIVAL(message), Z_TYPE(file), Z_UNIVAL(file), Z_LVAL(line), - (trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n"); - } else { - len = zend_spprintf(&str, 0, "exception '%v' in %R:%ld\nStack trace:\n%s", - Z_OBJCE_P(getThis())->name, Z_TYPE(file), Z_UNIVAL(file), Z_LVAL(line), - (trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n"); + if (Z_TYPE_P(trace) != IS_STRING && Z_TYPE_P(trace) != IS_UNICODE) { + trace = NULL; + } + + if (Z_UNILEN(message) > 0) { + len = zend_spprintf(&str, 0, "exception '%v' with message '%R' in %R:%ld\nStack trace:\n%s%s%s", + Z_OBJCE_P(exception)->name, Z_TYPE(message), Z_UNIVAL(message), Z_TYPE(file), Z_UNIVAL(file), Z_LVAL(line), + (trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n", + len ? "\n\nNext " : "", prev_str); + } else { + len = zend_spprintf(&str, 0, "exception '%v' in %R:%ld\nStack trace:\n%s%s%s", + Z_OBJCE_P(exception)->name, Z_TYPE(file), Z_UNIVAL(file), Z_LVAL(line), + (trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n", + len ? "\n\nNext " : "", prev_str); + } + efree(prev_str); + zval_dtor(&message); + zval_dtor(&file); + zval_dtor(&line); + + exception = zend_read_property(default_exception_ce, exception, "previous", sizeof("previous")-1, 0 TSRMLS_CC); } + zval_dtor(&fname); /* We store the result in the private property string so we can access * the result in uncaught exception handlers without memleaks. */ @@ -597,10 +616,6 @@ ZEND_METHOD(exception, __toString) zval_ptr_dtor(&trace); } - zval_dtor(&message); - zval_dtor(&file); - zval_dtor(&line); - RETURN_STRINGL(str, len, 0); } /* }}} */ @@ -619,6 +634,7 @@ static ZEND_BEGIN_ARG_INFO_EX(arginfo_exception___construct, 0, 0, 0) ZEND_ARG_INFO(0, message) ZEND_ARG_INFO(0, code) + ZEND_ARG_INFO(0, previous) ZEND_END_ARG_INFO() static const zend_function_entry default_exception_functions[] = { @@ -629,6 +645,7 @@ static const zend_function_entry default_exception_functions[] = { ZEND_ME(exception, getFile, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(exception, getLine, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(exception, getTrace, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) + ZEND_ME(exception, getPrevious, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(exception, getTraceAsString, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(exception, __toString, NULL, 0) {NULL, NULL, NULL} @@ -641,6 +658,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_error_exception___construct, 0, 0, 0) ZEND_ARG_INFO(0, severity) ZEND_ARG_INFO(0, filename) ZEND_ARG_INFO(0, lineno) + ZEND_ARG_INFO(0, previous) ZEND_END_ARG_INFO() static const zend_function_entry error_exception_functions[] = { @@ -666,6 +684,7 @@ void zend_register_default_exception(TSRMLS_D) /* {{{ */ zend_declare_property_null(default_exception_ce, "file", sizeof("file")-1, ZEND_ACC_PROTECTED TSRMLS_CC); zend_declare_property_null(default_exception_ce, "line", sizeof("line")-1, ZEND_ACC_PROTECTED TSRMLS_CC); zend_declare_property_null(default_exception_ce, "trace", sizeof("trace")-1, ZEND_ACC_PRIVATE TSRMLS_CC); + zend_declare_property_null(default_exception_ce, "previous", sizeof("previous")-1, ZEND_ACC_PRIVATE TSRMLS_CC); INIT_CLASS_ENTRY(ce, "ErrorException", error_exception_functions); error_exception_ce = zend_register_internal_class_ex(&ce, default_exception_ce, NULL TSRMLS_CC); |