Skip to content

Commit 61a808d

Browse files
committed
- MFH Add support for linking exceptions (implements TODO)
1 parent 8cbd7cc commit 61a808d

File tree

1 file changed

+73
-45
lines changed

1 file changed

+73
-45
lines changed

Zend/zend_exceptions.c

Lines changed: 73 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ void zend_throw_exception_internal(zval *exception TSRMLS_DC) /* {{{ */
3737
{
3838
if (exception != NULL) {
3939
if (EG(exception)) {
40-
/* FIXME: bail out? */
41-
return;
40+
zend_update_property(default_exception_ce, exception, "previous", sizeof("previous")-1, EG(exception) TSRMLS_CC);
4241
}
4342
EG(exception) = exception;
4443
}
@@ -121,16 +120,16 @@ ZEND_METHOD(exception, __clone)
121120
}
122121
/* }}} */
123122

124-
/* {{{ proto Exception::__construct(string message, int code)
123+
/* {{{ proto Exception::__construct(string message, int code [, Exception previous])
125124
Exception constructor */
126125
ZEND_METHOD(exception, __construct)
127126
{
128127
char *message = NULL;
129128
long code = 0;
130-
zval *object;
129+
zval *object, *previous = NULL;
131130
int argc = ZEND_NUM_ARGS(), message_len;
132131

133-
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, "|sl", &message, &message_len, &code) == FAILURE) {
132+
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, "|slO", &message, &message_len, &code, &previous, default_exception_ce) == FAILURE) {
134133
zend_error(E_ERROR, "Wrong parameters for Exception([string $exception [, long $code ]])");
135134
}
136135

@@ -143,19 +142,23 @@ ZEND_METHOD(exception, __construct)
143142
if (code) {
144143
zend_update_property_long(default_exception_ce, object, "code", sizeof("code")-1, code TSRMLS_CC);
145144
}
145+
146+
if (previous) {
147+
zend_update_property(default_exception_ce, object, "previous", sizeof("previous")-1, previous TSRMLS_CC);
148+
}
146149
}
147150
/* }}} */
148151

149-
/* {{{ proto ErrorException::__construct(string message, int code, int severity [, string filename [, int lineno]])
152+
/* {{{ proto ErrorException::__construct(string message, int code, int severity [, string filename [, int lineno [, Exception previous]]])
150153
ErrorException constructor */
151154
ZEND_METHOD(error_exception, __construct)
152155
{
153156
char *message = NULL, *filename = NULL;
154157
long code = 0, severity = E_ERROR, lineno;
155-
zval *object;
158+
zval *object, *previous = NULL;
156159
int argc = ZEND_NUM_ARGS(), message_len, filename_len;
157160

158-
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, argc TSRMLS_CC, "|sllsl", &message, &message_len, &code, &severity, &filename, &filename_len, &lineno) == FAILURE) {
161+
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) {
159162
zend_error(E_ERROR, "Wrong parameters for ErrorException([string $exception [, long $code, [ long $severity, [ string $filename, [ long $lineno ]]]]])");
160163
}
161164

@@ -169,6 +172,10 @@ ZEND_METHOD(error_exception, __construct)
169172
zend_update_property_long(default_exception_ce, object, "code", sizeof("code")-1, code TSRMLS_CC);
170173
}
171174

175+
if (previous) {
176+
zend_update_property(default_exception_ce, object, "previous", sizeof("previous")-1, previous TSRMLS_CC);
177+
}
178+
172179
zend_update_property_long(default_exception_ce, object, "severity", sizeof("severity")-1, severity TSRMLS_CC);
173180

174181
if (argc >= 4) {
@@ -445,6 +452,15 @@ ZEND_METHOD(exception, getTraceAsString)
445452
}
446453
/* }}} */
447454

455+
/* {{{ proto string Exception::getPrevious()
456+
Return previous Exception or NULL. */
457+
ZEND_METHOD(exception, getPrevious)
458+
{
459+
zval *previous;
460+
previous = zend_read_property(default_exception_ce, getThis(), "previous", sizeof("previous")-1, 1 TSRMLS_CC);
461+
RETURN_ZVAL(previous, 1, 0);
462+
}
463+
448464
int zend_spprintf(char **message, int max_len, char *format, ...) /* {{{ */
449465
{
450466
va_list arg;
@@ -461,47 +477,60 @@ int zend_spprintf(char **message, int max_len, char *format, ...) /* {{{ */
461477
Obtain the string representation of the Exception object */
462478
ZEND_METHOD(exception, __toString)
463479
{
464-
zval message, file, line, *trace;
465-
char *str;
466-
int len;
480+
zval message, file, line, *trace, *exception;
481+
char *str = estrndup("", 0), *prev_str;
482+
int len = 0;
467483
zend_fcall_info fci;
468484
zval fname;
469485

470-
_default_exception_get_entry(getThis(), "message", sizeof("message")-1, &message TSRMLS_CC);
471-
_default_exception_get_entry(getThis(), "file", sizeof("file")-1, &file TSRMLS_CC);
472-
_default_exception_get_entry(getThis(), "line", sizeof("line")-1, &line TSRMLS_CC);
473-
474-
convert_to_string(&message);
475-
convert_to_string(&file);
476-
convert_to_long(&line);
477-
486+
exception = getThis();
478487
ZVAL_STRINGL(&fname, "gettraceasstring", sizeof("gettraceasstring")-1, 0);
479488

480-
fci.size = sizeof(fci);
481-
fci.function_table = &Z_OBJCE_P(getThis())->function_table;
482-
fci.function_name = &fname;
483-
fci.symbol_table = NULL;
484-
fci.object_pp = &getThis();
485-
fci.retval_ptr_ptr = &trace;
486-
fci.param_count = 0;
487-
fci.params = NULL;
488-
fci.no_separation = 1;
489-
490-
zend_call_function(&fci, NULL TSRMLS_CC);
489+
while (exception && Z_TYPE_P(exception) == IS_OBJECT) {
490+
prev_str = str;
491+
_default_exception_get_entry(exception, "message", sizeof("message")-1, &message TSRMLS_CC);
492+
_default_exception_get_entry(exception, "file", sizeof("file")-1, &file TSRMLS_CC);
493+
_default_exception_get_entry(exception, "line", sizeof("line")-1, &line TSRMLS_CC);
494+
495+
convert_to_string(&message);
496+
convert_to_string(&file);
497+
convert_to_long(&line);
498+
499+
fci.size = sizeof(fci);
500+
fci.function_table = &Z_OBJCE_P(exception)->function_table;
501+
fci.function_name = &fname;
502+
fci.symbol_table = NULL;
503+
fci.object_pp = &exception;
504+
fci.retval_ptr_ptr = &trace;
505+
fci.param_count = 0;
506+
fci.params = NULL;
507+
fci.no_separation = 1;
508+
509+
zend_call_function(&fci, NULL TSRMLS_CC);
510+
511+
if (Z_TYPE_P(trace) != IS_STRING) {
512+
trace = NULL;
513+
}
491514

492-
if (Z_TYPE_P(trace) != IS_STRING) {
493-
trace = NULL;
494-
}
515+
if (Z_STRLEN(message) > 0) {
516+
len = zend_spprintf(&str, 0, "exception '%s' with message '%s' in %s:%ld\nStack trace:\n%s%s%s",
517+
Z_OBJCE_P(exception)->name, Z_STRVAL(message), Z_STRVAL(file), Z_LVAL(line),
518+
(trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n",
519+
len ? "\n\nNext " : "", prev_str);
520+
} else {
521+
len = zend_spprintf(&str, 0, "exception '%s' in %s:%ld\nStack trace:\n%s%s%s",
522+
Z_OBJCE_P(exception)->name, Z_STRVAL(file), Z_LVAL(line),
523+
(trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n",
524+
len ? "\n\nNext " : "", prev_str);
525+
}
526+
efree(prev_str);
527+
zval_dtor(&message);
528+
zval_dtor(&file);
529+
zval_dtor(&line);
495530

496-
if (Z_STRLEN(message) > 0) {
497-
len = zend_spprintf(&str, 0, "exception '%s' with message '%s' in %s:%ld\nStack trace:\n%s",
498-
Z_OBJCE_P(getThis())->name, Z_STRVAL(message), Z_STRVAL(file), Z_LVAL(line),
499-
(trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n");
500-
} else {
501-
len = zend_spprintf(&str, 0, "exception '%s' in %s:%ld\nStack trace:\n%s",
502-
Z_OBJCE_P(getThis())->name, Z_STRVAL(file), Z_LVAL(line),
503-
(trace && Z_STRLEN_P(trace)) ? Z_STRVAL_P(trace) : "#0 {main}\n");
531+
exception = zend_read_property(default_exception_ce, exception, "previous", sizeof("previous")-1, 0 TSRMLS_CC);
504532
}
533+
zval_dtor(&fname);
505534

506535
/* We store the result in the private property string so we can access
507536
* the result in uncaught exception handlers without memleaks. */
@@ -511,10 +540,6 @@ ZEND_METHOD(exception, __toString)
511540
zval_ptr_dtor(&trace);
512541
}
513542

514-
zval_dtor(&message);
515-
zval_dtor(&file);
516-
zval_dtor(&line);
517-
518543
RETURN_STRINGL(str, len, 0);
519544
}
520545
/* }}} */
@@ -543,6 +568,7 @@ const static zend_function_entry default_exception_functions[] = {
543568
ZEND_ME(exception, getFile, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
544569
ZEND_ME(exception, getLine, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
545570
ZEND_ME(exception, getTrace, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
571+
ZEND_ME(exception, getPrevious, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
546572
ZEND_ME(exception, getTraceAsString, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
547573
ZEND_ME(exception, __toString, NULL, 0)
548574
{NULL, NULL, NULL}
@@ -555,6 +581,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_error_exception___construct, 0, 0, 0)
555581
ZEND_ARG_INFO(0, severity)
556582
ZEND_ARG_INFO(0, filename)
557583
ZEND_ARG_INFO(0, lineno)
584+
ZEND_ARG_INFO(0, previous)
558585
ZEND_END_ARG_INFO()
559586

560587
static const zend_function_entry error_exception_functions[] = {
@@ -580,6 +607,7 @@ void zend_register_default_exception(TSRMLS_D) /* {{{ */
580607
zend_declare_property_null(default_exception_ce, "file", sizeof("file")-1, ZEND_ACC_PROTECTED TSRMLS_CC);
581608
zend_declare_property_null(default_exception_ce, "line", sizeof("line")-1, ZEND_ACC_PROTECTED TSRMLS_CC);
582609
zend_declare_property_null(default_exception_ce, "trace", sizeof("trace")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
610+
zend_declare_property_null(default_exception_ce, "previous", sizeof("previous")-1, ZEND_ACC_PRIVATE TSRMLS_CC);
583611

584612
INIT_CLASS_ENTRY(ce, "ErrorException", error_exception_functions);
585613
error_exception_ce = zend_register_internal_class_ex(&ce, default_exception_ce, NULL TSRMLS_CC);

0 commit comments

Comments
 (0)