[xdebug-dev] xdebug xdebug/xdebug.c xdebug/tests/bug00476-2.phpt xdebug/tests/bug00476.phpt xdebug/tests/bug00173.phpt - Fixed bug #476: Xdebug doesn't support PHP 5.3's exception chaining.

From: Derick Rethans <derick[@]derickrethans.nl>
Date: Sun, 22 Nov 2009 14:43:23 +0100

Date: Sun Nov 22 14:43:23 CET 2009
User: Derick Rethans
Directory: xdebug

Log Message:
[20.00]
- Fixed bug #476: Xdebug doesn't support PHP 5.3's exception chaining.

Modified files:
           xdebug/xdebug.c (version: 1.460)
           xdebug/tests/bug00173.phpt (version: 1.9)
Added files:
           xdebug/tests/bug00476-2.phpt (new version: 1.1)
           xdebug/tests/bug00476.phpt (new version: 1.1)

[FILE: /xdebug/xdebug.c]

===================================================================
RCS file: cvstemp,v
retrieving revision 1.459
retrieving revision 1.460
diff -u -r1.459 -r1.460
--- xdebug/xdebug.c:1.459 Sat Oct 17 13:52:08 2009 GMT
+++ xdebug/xdebug.c Sun Nov 22 12:43:23 2009 GMT
@@ -2012,42 +2012,39 @@
         return fname.l;
 }
 
-static char* get_printable_stack(int html, const char *error_type_str, char *buffer, const char *error_filename, const int error_lineno TSRMLS_DC)
+static void xdebug_append_error_head(xdebug_str *str, int html TSRMLS_DC)
 {
- xdebug_llist_element *le;
- function_stack_entry *i;
- int len;
- char **formats;
- xdebug_str str = {0, 0, NULL};
- char *prepend_string;
- char *append_string;
-
- if (html) {
- formats = html_formats;
- } else {
- formats = text_formats;
- }
-
- prepend_string = INI_STR("error_prepend_string");
- append_string = INI_STR("error_append_string");
+ char **formats = html ? html_formats : text_formats;
  
- xdebug_str_add(&str, prepend_string ? prepend_string : "", 0);
- xdebug_str_add(&str, formats[0], 0);
+ xdebug_str_add(str, formats[0], 0);
+}
+
+static void xdebug_append_error_description(xdebug_str *str, int html, const char *error_type_str, char *buffer, const char *error_filename, const int error_lineno TSRMLS_DC)
+{
+ char **formats = html ? html_formats : text_formats;
 
         if (strlen(XG(file_link_format)) > 0 && html) {
                 char *file_link;
 
                 create_file_link(&file_link, error_filename, error_lineno TSRMLS_CC);
- xdebug_str_add(&str, xdebug_sprintf(formats[11], error_type_str, buffer, file_link, error_filename, error_lineno), 1);
+ xdebug_str_add(str, xdebug_sprintf(formats[11], error_type_str, buffer, file_link, error_filename, error_lineno), 1);
                 xdfree(file_link);
         } else {
- xdebug_str_add(&str, xdebug_sprintf(formats[1], error_type_str, buffer, error_filename, error_lineno), 1);
+ xdebug_str_add(str, xdebug_sprintf(formats[1], error_type_str, buffer, error_filename, error_lineno), 1);
         }
+}
+
+static void xdebug_append_printable_stack(xdebug_str *str, int html TSRMLS_DC)
+{
+ xdebug_llist_element *le;
+ function_stack_entry *i;
+ int len;
+ char **formats = html ? html_formats : text_formats;
 
         if (XG(stack) && XG(stack)->size) {
                 i = XDEBUG_LLIST_VALP(XDEBUG_LLIST_HEAD(XG(stack)));
 
- xdebug_str_add(&str, formats[2], 0);
+ xdebug_str_add(str, formats[2], 0);
 
                 for (le = XDEBUG_LLIST_HEAD(XG(stack)); le != NULL; le = XDEBUG_LLIST_NEXT(le))
                 {
@@ -2059,15 +2056,15 @@
                         tmp_name = xdebug_show_fname(i->function, html, 0 TSRMLS_CC);
                         if (html) {
 #if HAVE_PHP_MEMORY_USAGE
- xdebug_str_add(&str, xdebug_sprintf(formats[3], i->level, i->time - XG(start_time), i->memory, tmp_name), 1);
+ xdebug_str_add(str, xdebug_sprintf(formats[3], i->level, i->time - XG(start_time), i->memory, tmp_name), 1);
 #else
- xdebug_str_add(&str, xdebug_sprintf(formats[3], i->level, i->time - XG(start_time), tmp_name), 1);
+ xdebug_str_add(str, xdebug_sprintf(formats[3], i->level, i->time - XG(start_time), tmp_name), 1);
 #endif
                         } else {
 #if HAVE_PHP_MEMORY_USAGE
- xdebug_str_add(&str, xdebug_sprintf(formats[3], i->time - XG(start_time), i->memory, i->level, tmp_name), 1);
+ xdebug_str_add(str, xdebug_sprintf(formats[3], i->time - XG(start_time), i->memory, i->level, tmp_name), 1);
 #else
- xdebug_str_add(&str, xdebug_sprintf(formats[3], i->time - XG(start_time), i->level, tmp_name), 1);
+ xdebug_str_add(str, xdebug_sprintf(formats[3], i->time - XG(start_time), i->level, tmp_name), 1);
 #endif
                         }
                         xdfree(tmp_name);
@@ -2078,16 +2075,16 @@
                                 int newlen;
 
                                 if (c) {
- xdebug_str_addl(&str, ", ", 2, 0);
+ xdebug_str_addl(str, ", ", 2, 0);
                                 } else {
                                         c = 1;
                                 }
 
                                 if (i->var[j].name && XG(collect_params) >= 4) {
                                         if (html) {
- xdebug_str_add(&str, xdebug_sprintf("<span>$%s = </span>", i->var[j].name), 1);
+ xdebug_str_add(str, xdebug_sprintf("<span>$%s = </span>", i->var[j].name), 1);
                                         } else {
- xdebug_str_add(&str, xdebug_sprintf("$%s = ", i->var[j].name), 1);
+ xdebug_str_add(str, xdebug_sprintf("$%s = ", i->var[j].name), 1);
                                         }
                                 }
 
@@ -2098,14 +2095,14 @@
                                                 tmp_fancy_synop_value = xdebug_get_zval_synopsis_fancy("", i->var[j].addr, &len, 0, NULL TSRMLS_CC);
                                                 switch (XG(collect_params)) {
                                                         case 1: // synopsis
- xdebug_str_add(&str, xdebug_sprintf("<span>%s</span>", tmp_fancy_synop_value), 1);
+ xdebug_str_add(str, xdebug_sprintf("<span>%s</span>", tmp_fancy_synop_value), 1);
                                                                 break;
                                                         case 2: // synopsis + full in tooltip
- xdebug_str_add(&str, xdebug_sprintf("<span title='%s'>%s</span>", tmp_fancy_value, tmp_fancy_synop_value), 1);
+ xdebug_str_add(str, xdebug_sprintf("<span title='%s'>%s</span>", tmp_fancy_value, tmp_fancy_synop_value), 1);
                                                                 break;
                                                         case 3: // full
                                                         default:
- xdebug_str_add(&str, xdebug_sprintf("<span>%s</span>", tmp_fancy_value), 1);
+ xdebug_str_add(str, xdebug_sprintf("<span>%s</span>", tmp_fancy_value), 1);
                                                                 break;
                                                 }
                                                 xdfree(tmp_value);
@@ -2123,19 +2120,19 @@
                                                                 break;
                                                 }
                                                 if (tmp_value) {
- xdebug_str_add(&str, xdebug_sprintf("%s", tmp_value), 1);
+ xdebug_str_add(str, xdebug_sprintf("%s", tmp_value), 1);
                                                         xdfree(tmp_value);
                                                 } else {
- xdebug_str_addl(&str, "???", 3, 0);
+ xdebug_str_addl(str, "???", 3, 0);
                                                 }
                                         }
                                 } else {
- xdebug_str_addl(&str, "???", 3, 0);
+ xdebug_str_addl(str, "???", 3, 0);
                                 }
                         }
 
                         if (i->include_filename) {
- xdebug_str_add(&str, xdebug_sprintf(formats[4], i->include_filename), 1);
+ xdebug_str_add(str, xdebug_sprintf(formats[4], i->include_filename), 1);
                         }
 
                         if (html) {
@@ -2144,15 +2141,15 @@
                                         char *file_link;
 
                                         create_file_link(&file_link, i->filename, i->lineno TSRMLS_CC);
- xdebug_str_add(&str, xdebug_sprintf(formats[10], i->filename, file_link, just_filename, i->lineno), 1);
+ xdebug_str_add(str, xdebug_sprintf(formats[10], i->filename, file_link, just_filename, i->lineno), 1);
                                         xdfree(file_link);
                                 } else {
                                         char *just_filename = strrchr(i->filename, DEFAULT_SLASH);
 
- xdebug_str_add(&str, xdebug_sprintf(formats[5], i->filename, just_filename, i->lineno), 1);
+ xdebug_str_add(str, xdebug_sprintf(formats[5], i->filename, just_filename, i->lineno), 1);
                                 }
                         } else {
- xdebug_str_add(&str, xdebug_sprintf(formats[5], i->filename, i->lineno), 1);
+ xdebug_str_add(str, xdebug_sprintf(formats[5], i->filename, i->lineno), 1);
                         }
                 }
 
@@ -2160,7 +2157,7 @@
                         char *tmp = xdebug_get_printable_superglobals(html TSRMLS_CC);
 
                         if (tmp) {
- xdebug_str_add(&str, tmp, 1);
+ xdebug_str_add(str, tmp, 1);
                         }
                         XG(dumped) = 1;
                 }
@@ -2176,16 +2173,38 @@
                         if (i->used_vars && i->used_vars->size) {
                                 xdebug_hash *tmp_hash;
 
- xdebug_str_add(&str, xdebug_sprintf(formats[6], scope_nr), 1);
+ xdebug_str_add(str, xdebug_sprintf(formats[6], scope_nr), 1);
                                 tmp_hash = xdebug_used_var_hash_from_llist(i->used_vars);
- xdebug_hash_apply_with_argument(tmp_hash, (void*) &html, dump_used_var_with_contents, (void *) &str);
+ xdebug_hash_apply_with_argument(tmp_hash, (void*) &html, dump_used_var_with_contents, (void *) str);
                                 xdebug_hash_destroy(tmp_hash);
                         }
                 }
-
- xdebug_str_add(&str, formats[7], 0);
- xdebug_str_add(&str, append_string ? append_string : "", 0);
         }
+}
+
+static void xdebug_append_error_footer(xdebug_str *str, int html)
+{
+ char **formats = html ? html_formats : text_formats;
+
+ xdebug_str_add(str, formats[7], 0);
+}
+
+static char *get_printable_stack(int html, const char *error_type_str, char *buffer, const char *error_filename, const int error_lineno TSRMLS_DC)
+{
+ char *prepend_string;
+ char *append_string;
+ xdebug_str str = {0, 0, NULL};
+
+ prepend_string = INI_STR("error_prepend_string");
+ append_string = INI_STR("error_append_string");
+
+ xdebug_str_add(&str, prepend_string ? prepend_string : "", 0);
+ xdebug_append_error_head(&str, html TSRMLS_CC);
+ xdebug_append_error_description(&str, html, error_type_str, buffer, error_filename, error_lineno TSRMLS_CC);
+ xdebug_append_printable_stack(&str, html TSRMLS_CC);
+ xdebug_append_error_footer(&str, html);
+ xdebug_str_add(&str, append_string ? append_string : "", 0);
+
         return str.d;
 }
 
@@ -2194,7 +2213,6 @@
         int j = 0;
         xdebug_str str = {0, 0, NULL};
         char *tmp_value;
- xdebug_var_export_options *options;
 
         if (XG(trace_format) != 0) {
                 return xdstrdup("");
@@ -2485,10 +2503,11 @@
 
 void xdebug_throw_exception_hook(zval *exception TSRMLS_DC)
 {
- zval *message, *file, *line;
+ zval *message, *file, *line, *xdebug_message_trace, *previous_exception;
         zend_class_entry *default_ce, *exception_ce;
         xdebug_brk_info *extra_brk_info;
         char *exception_trace;
+ xdebug_str tmp_str = { 0, 0, NULL };
 
         if (!exception) {
                 return;
@@ -2505,7 +2524,21 @@
                 php_error(E_ERROR, "Your exception class uses incorrect types for common properties: 'message' and 'file' need to be a string and 'line' needs to be an integer.");
         }
 
- exception_trace = get_printable_stack(PG(html_errors), exception_ce->name, Z_STRVAL_P(message), Z_STRVAL_P(file), Z_LVAL_P(line) TSRMLS_CC);
+ previous_exception = zend_read_property(default_ce, exception, "previous", sizeof("previous")-1, 1 TSRMLS_CC);
+ if (previous_exception && Z_TYPE_P(previous_exception) != IS_NULL) {
+ xdebug_message_trace = zend_read_property(default_ce, previous_exception, "xdebug_message", sizeof("xdebug_message")-1, 1 TSRMLS_CC);
+ if (xdebug_message_trace && Z_TYPE_P(xdebug_message_trace) != IS_NULL) {
+ xdebug_str_add(&tmp_str, Z_STRVAL_P(xdebug_message_trace), 0);
+ }
+ }
+ if (!PG(html_errors)) {
+ xdebug_str_addl(&tmp_str, "\n", 1, 0);
+ }
+ xdebug_append_error_description(&tmp_str, PG(html_errors), exception_ce->name, Z_STRVAL_P(message), Z_STRVAL_P(file), Z_LVAL_P(line) TSRMLS_CC);
+ xdebug_append_printable_stack(&tmp_str, PG(html_errors) TSRMLS_CC);
+ exception_trace = tmp_str.d;
+ zend_update_property_string(default_ce, exception, "xdebug_message", sizeof("xdebug_message")-1, exception_trace TSRMLS_CC);
+
         if (XG(last_exception_trace)) {
                 xdfree(XG(last_exception_trace));
         }
@@ -2545,6 +2578,7 @@
         return ZEND_USER_OPCODE_DISPATCH;
 }
 
+/* Error callback for formatting stack traces */
 void xdebug_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args)
 {
         char *buffer, *error_type_str;
@@ -2625,7 +2659,27 @@
 
                         /* We need to see if we have an uncaught exception fatal error now */
                         if (type == E_ERROR && strncmp(buffer, "Uncaught exception", 18) == 0) {
- php_printf("%s", XG(last_exception_trace));
+ xdebug_str str = {0, 0, NULL};
+ char *tmp_buf, *p;
+
+ /* find first new line */
+ p = strchr(buffer, '\n');
+ /* find last quote */
+ p = memrchr(buffer, '\'', p - buffer) + 1;
+ /* Create new buffer */
+ tmp_buf = calloc(p - buffer + 1, 1);
+ strncpy(tmp_buf, buffer, p - buffer );
+
+ /* Append error */
+ xdebug_append_error_head(&str, PG(html_errors) TSRMLS_CC);
+ xdebug_append_error_description(&str, PG(html_errors), error_type_str, tmp_buf, error_filename, error_lineno TSRMLS_CC);
+ xdebug_append_printable_stack(&str, PG(html_errors) TSRMLS_CC);
+ xdebug_str_add(&str, XG(last_exception_trace), 0);
+ xdebug_append_error_footer(&str, PG(html_errors));
+ php_printf("%s", str.d);
+
+ xdfree(str.d);
+ free(tmp_buf);
                         } else {
                                 printable_stack = get_printable_stack(PG(html_errors), error_type_str, buffer, error_filename, error_lineno TSRMLS_CC);
                                 php_printf("%s", printable_stack);

[FILE: /xdebug/tests/bug00476-2.phpt]

--TEST--
Test for bug #476: Exception chanining doesn't work
--INI--
xdebug.default_enable=1
--FILE--
<?php

function a()
{
   throw new Exception('First exception');
}

function b()
{
        try {
                a();
        } catch(Exception $e) {
           throw new Exception('Second exception', 0, $e);
        }
}

function c()
{
        try {
                b();
        } catch(Exception $e) {
           throw new Exception('Third exception', 0, $e);
        }
}

function d()
{
        try {
                c();
        } catch(Exception $e) {
           throw new Exception('Fourth exception', 0, $e);
        }
}

d();

echo "DONE\n";
?>
--EXPECTF--
Fatal error: Uncaught exception 'Exception' with message 'First exception' in %sbug00476-2.php on line 31

Exception: First exception in %sbug00476-2.php on line 5

Call Stack:
%w%f %w%d 1. {main}() %sbug00476-2.php:0
%w%f %w%d 2. d() %sbug00476-2.php:35
%w%f %w%d 3. c() %sbug00476-2.php:29
%w%f %w%d 4. b() %sbug00476-2.php:20
%w%f %w%d 5. a() %sbug00476-2.php:11

Exception: Second exception in %sbug00476-2.php on line 13

Call Stack:
%w%f %w%d 1. {main}() %sbug00476-2.php:0
%w%f %w%d 2. d() %sbug00476-2.php:35
%w%f %w%d 3. c() %sbug00476-2.php:29
%w%f %w%d 4. b() %sbug00476-2.php:20

Exception: Third exception in %sbug00476-2.php on line 22

Call Stack:
%w%f %w%d 1. {main}() %sbug00476-2.php:0
%w%f %w%d 2. d() %sbug00476-2.php:35
%w%f %w%d 3. c() %sbug00476-2.php:29

Exception: Fourth exception in %sbug00476-2.php on line 31

Call Stack:
%w%f %w%d 1. {main}() %sbug00476-2.php:0
%w%f %w%d 2. d() %sbug00476-2.php:35

[FILE: /xdebug/tests/bug00476.phpt]

--TEST--
Test for bug #476: Exception chanining doesn't work
--INI--
xdebug.default_enable=1
--FILE--
<?php
try {
   throw new Exception('First exception');
} catch(Exception $e) {
        try {
           throw new Exception('Second exception', 0, $e);
        } catch(Exception $f) {
           throw new Exception('Third exception', 0, $f);
        }
}
echo "DONE\n";
?>
--EXPECTF--
Fatal error: Uncaught exception 'Exception' with message 'First exception' in %sbug00476.php on line 8

Exception: First exception in %sbug00476.php on line 3

Call Stack:
%w%f %w%d 1. {main}() %sbug00476.php:0

Exception: Second exception in %sbug00476.php on line 6

Call Stack:
%w%f %w%d 1. {main}() %sbug00476.php:0

Exception: Third exception in %sbug00476.php on line 8

Call Stack:
%w%f %w%d 1. {main}() %sbug00476.php:0

[FILE: /xdebug/tests/bug00173.phpt]

===================================================================
RCS file: cvstemp,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- xdebug/tests/bug00173.phpt:1.8 Sun Jan 04 20:34:08 2009 GMT
+++ xdebug/tests/bug00173.phpt Sun Nov 22 12:43:23 2009 GMT
@@ -28,6 +28,8 @@
         echo "DONE\n";
 ?>
 --EXPECTF--
+Fatal error: Uncaught exception 'InvalidArgumentException' with message 'Passed variable is not an array or object, using empty array instead' in %sbug00173.php on line 3
+
 InvalidArgumentException: Passed variable is not an array or object, using empty array instead in %sbug00173.php on line 3
 
 Call Stack:
Received on Sun Nov 22 2009 - 14:43:44 GMT

This archive was generated by hypermail 2.2.0 : Sun Jun 24 2018 - 04:00:03 BST