summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-04-22 02:30:10 +0300
committerDmitry Stogov <dmitry@zend.com>2015-04-22 02:30:10 +0300
commitc61bf4bc1120a92c7525b1bc1cd0ae3e1837b3c7 (patch)
treef0c4b140ef814137762785aeb46b4b5e01952c2b
parent770cb1da71656fa0dce7dfab26e5e88cb557b639 (diff)
parent0ec3a6ff33e815f8d50d437fd00ba0f8b09bdf85 (diff)
downloadphp-git-c61bf4bc1120a92c7525b1bc1cd0ae3e1837b3c7.tar.gz
Merge branch 'master' of git.php.net:php-src
* 'master' of git.php.net:php-src: FAST_RET opcode also returns Also consider specific catches when checking for uncaught Break on uncaught exceptions in current frame in phpdbg
-rw-r--r--sapi/phpdbg/phpdbg.h1
-rw-r--r--sapi/phpdbg/phpdbg_prompt.c46
-rw-r--r--sapi/phpdbg/phpdbg_utils.c38
-rw-r--r--sapi/phpdbg/phpdbg_utils.h2
4 files changed, 75 insertions, 12 deletions
diff --git a/sapi/phpdbg/phpdbg.h b/sapi/phpdbg/phpdbg.h
index 6de6e9e2b8..2cb588d086 100644
--- a/sapi/phpdbg/phpdbg.h
+++ b/sapi/phpdbg/phpdbg.h
@@ -233,6 +233,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
HashTable registered; /* registered */
HashTable seek; /* seek oplines */
zend_execute_data *seek_ex; /* call frame of oplines to seek to */
+ zend_object *handled_exception; /* last handled exception (prevent multiple handling of same exception) */
phpdbg_frame_t frame; /* frame */
uint32_t last_line; /* last executed line */
diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c
index ac3fb67dbd..621fc1e318 100644
--- a/sapi/phpdbg/phpdbg_prompt.c
+++ b/sapi/phpdbg/phpdbg_prompt.c
@@ -24,6 +24,7 @@
#include "zend_compile.h"
#include "zend_exceptions.h"
#include "zend_vm.h"
+#include "zend_generators.h"
#include "phpdbg.h"
#include "phpdbg_help.h"
@@ -485,6 +486,7 @@ int phpdbg_skip_line_helper() /* {{{ */ {
while (++opline < op_array->opcodes + op_array->last) {
if (opline->lineno != EG(current_execute_data)->opline->lineno
|| opline->opcode == ZEND_RETURN
+ || opline->opcode == ZEND_FAST_RET
|| opline->opcode == ZEND_GENERATOR_RETURN
|| opline->opcode == ZEND_EXIT
|| opline->opcode == ZEND_YIELD
@@ -528,11 +530,12 @@ static void phpdbg_seek_to_end(void) /* {{{ */ {
while (++opline < op_array->opcodes + op_array->last) {
switch (opline->opcode) {
case ZEND_RETURN:
+ case ZEND_FAST_RET:
case ZEND_GENERATOR_RETURN:
case ZEND_EXIT:
case ZEND_YIELD:
zend_hash_index_update_ptr(&PHPDBG_G(seek), (zend_ulong) opline, (void *) opline);
- return;
+ return;
}
}
}
@@ -647,6 +650,7 @@ PHPDBG_COMMAND(run) /* {{{ */
} else {
zend_rebuild_symbol_table();
}
+ PHPDBG_G(handled_exception) = NULL;
/* clean seek state */
PHPDBG_G(flags) &= ~PHPDBG_SEEK_MASK;
@@ -1376,7 +1380,12 @@ void phpdbg_clean(zend_bool full) /* {{{ */
}
} /* }}} */
+/* code may behave weirdly if EG(exception) is set */
#define DO_INTERACTIVE(allow_async_unsafe) do { \
+ if (exception) { \
+ ++GC_REFCOUNT(exception); \
+ zend_clear_exception(); \
+ } \
if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) { \
const char *file_char = zend_get_executed_filename(); \
zend_string *file = zend_string_init(file_char, strlen(file_char), 0); \
@@ -1385,6 +1394,13 @@ void phpdbg_clean(zend_bool full) /* {{{ */
} \
\
switch (phpdbg_interactive(allow_async_unsafe)) { \
+ zval zv; \
+ default: \
+ if (exception) { \
+ Z_OBJ(zv) = exception; \
+ zend_throw_exception_internal(&zv); \
+ } \
+ /* fallthrough */ \
case PHPDBG_LEAVE: \
case PHPDBG_FINISH: \
case PHPDBG_UNTIL: \
@@ -1408,6 +1424,8 @@ void phpdbg_execute_ex(zend_execute_data *execute_data) /* {{{ */
PHPDBG_G(in_execution) = 1;
while (1) {
+ zend_object *exception = EG(exception);
+
if ((PHPDBG_G(flags) & PHPDBG_BP_RESOLVE_MASK)) {
/* resolve nth opline breakpoints */
phpdbg_resolve_op_array_breaks(&execute_data->func->op_array);
@@ -1419,6 +1437,28 @@ void phpdbg_execute_ex(zend_execute_data *execute_data) /* {{{ */
}
#endif
+ /* check for uncaught exceptions */
+ if (exception && PHPDBG_G(handled_exception) != exception) {
+ zend_execute_data *prev_ex = execute_data;
+
+ do {
+ prev_ex = zend_generator_check_placeholder_frame(prev_ex);
+ /* assuming that no internal functions will silently swallow exceptions ... */
+ if (!prev_ex->func || !ZEND_USER_CODE(prev_ex->func->common.type)) {
+ continue;
+ }
+
+ if (phpdbg_check_caught_ex(prev_ex, exception)) {
+ goto ex_is_caught;
+ }
+ } while ((prev_ex = prev_ex->prev_execute_data));
+
+ PHPDBG_G(handled_exception) = exception;
+ phpdbg_error("exception", "name=\"%s\"", "Uncaught exception %s", exception->ce->name->val);
+ DO_INTERACTIVE(1);
+ }
+ex_is_caught:
+
/* allow conditional breakpoints and
initialization to access the vm uninterrupted */
if ((PHPDBG_G(flags) & PHPDBG_IN_COND_BP) ||
@@ -1436,7 +1476,7 @@ void phpdbg_execute_ex(zend_execute_data *execute_data) /* {{{ */
goto next;
}
-#define INDEX_EXISTS_CHECK (zend_hash_index_exists(&PHPDBG_G(seek), address) || (EG(exception) && phpdbg_check_caught_ex(execute_data) == 0))
+#define INDEX_EXISTS_CHECK (zend_hash_index_exists(&PHPDBG_G(seek), address) || (exception && phpdbg_check_caught_ex(execute_data, exception) == 0))
/* run to next line */
if (PHPDBG_G(flags) & PHPDBG_IN_UNTIL) {
@@ -1540,6 +1580,7 @@ next:
/* only if *not* interactive and while executing */
void phpdbg_force_interruption(void) /* {{{ */ {
+ zend_object *exception = EG(exception);
zend_execute_data *data = EG(current_execute_data); /* should be always readable if not NULL */
PHPDBG_G(flags) |= PHPDBG_IN_SIGNAL_HANDLER;
@@ -1581,4 +1622,3 @@ PHPDBG_COMMAND(eol) /* {{{ */
return SUCCESS;
} /* }}} */
-
diff --git a/sapi/phpdbg/phpdbg_utils.c b/sapi/phpdbg/phpdbg_utils.c
index e1f6c59502..9d63fcf727 100644
--- a/sapi/phpdbg/phpdbg_utils.c
+++ b/sapi/phpdbg/phpdbg_utils.c
@@ -713,24 +713,46 @@ head_done:
} phpdbg_end_try_access();
}
-PHPDBG_API zend_bool phpdbg_check_caught_ex(zend_execute_data *ex) {
+PHPDBG_API zend_bool phpdbg_check_caught_ex(zend_execute_data *execute_data, zend_object *exception) {
const zend_op *op;
+ zend_op *cur;
uint32_t op_num, i;
- zend_op_array *op_array = &ex->func->op_array;
+ zend_op_array *op_array = &execute_data->func->op_array;
- if (ex->opline >= EG(exception_op) && ex->opline < EG(exception_op) + 3) {
+ if (execute_data->opline >= EG(exception_op) && execute_data->opline < EG(exception_op) + 3) {
op = EG(opline_before_exception);
} else {
- op = ex->opline;
+ op = execute_data->opline;
}
op_num = op - op_array->opcodes;
- for (i = 0; i < op_array->last_try_catch && op_array->try_catch_array[i].try_op > op_num; i++) {
- if (op_num < op_array->try_catch_array[i].catch_op || op_num < op_array->try_catch_array[i].finally_op) {
- return 1;
+ for (i = 0; i < op_array->last_try_catch && op_array->try_catch_array[i].try_op < op_num; i++) {
+ uint32_t catch = op_array->try_catch_array[i].catch_op, finally = op_array->try_catch_array[i].finally_op;
+ if (op_num <= catch || op_num <= finally) {
+ if (finally && finally < catch) {
+ return 0;
+ }
+
+ do {
+ zend_class_entry *ce;
+ cur = &op_array->opcodes[catch];
+
+ if (!(ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(cur->op1))))) {
+ ce = zend_fetch_class_by_name(Z_STR_P(EX_CONSTANT(cur->op1)), EX_CONSTANT(cur->op1) + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD);
+ CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(cur->op1)), ce);
+ }
+
+ if (ce == exception->ce || (ce && instanceof_function(exception->ce, ce))) {
+ return 1;
+ }
+
+ catch = cur->extended_value;
+ } while (!cur->result.num);
+
+ return 0;
}
}
- return 0;
+ return op->opcode == ZEND_CATCH;
}
diff --git a/sapi/phpdbg/phpdbg_utils.h b/sapi/phpdbg/phpdbg_utils.h
index 5ed2353987..dcf713e05b 100644
--- a/sapi/phpdbg/phpdbg_utils.h
+++ b/sapi/phpdbg/phpdbg_utils.h
@@ -94,7 +94,7 @@ int phpdbg_is_auto_global(char *name, int len);
PHPDBG_API void phpdbg_xml_var_dump(zval *zv);
-PHPDBG_API zend_bool phpdbg_check_caught_ex(zend_execute_data *ex);
+PHPDBG_API zend_bool phpdbg_check_caught_ex(zend_execute_data *ex, zend_object *exception);
#ifdef ZTS
#define PHPDBG_OUTPUT_BACKUP_DEFINES() \