]> granicus.if.org Git - php/commitdiff
Merge branch 'PHP-5.6' into PHP-7.0
authorXinchen Hui <laruence@gmail.com>
Fri, 20 Nov 2015 08:38:00 +0000 (16:38 +0800)
committerXinchen Hui <laruence@gmail.com>
Fri, 20 Nov 2015 08:38:00 +0000 (16:38 +0800)
Conflicts:
Zend/zend_exceptions.c

1  2 
Zend/tests/bug70944.phpt
Zend/zend_exceptions.c

index 0000000000000000000000000000000000000000,d189d9eab430b4c8a061f5ba1c93afb98526916d..f14af651660376f06cbe8d720a707eecaaa53a46
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,16 +1,16 @@@
 -Fatal error: Uncaught exception 'Exception' with message 'Bar' in %sbug70944.php:%d
+ --TEST--
+ Bug #70944 (try{ } finally{} can create infinite chains of exceptions)
+ --FILE--
+ <?php
+ $e = new Exception("Bar");
+ try {
+         throw new Exception("Foo", 0, $e);
+ } finally {
+         throw $e;
+ }
+ ?>
+ --EXPECTF--
++Fatal error: Uncaught Exception: Bar in %sbug70944.php:%d
+ Stack trace:
+ #0 {main}
+   thrown in %sbug70944.php on line %d
index 002f519bc6e38e9623c8017607f88052d88871fd,d1aa6fe9f17f98ea56c3ea15eb7dfdf7fe7cc31f..dd137dfb951bab16920e2453a1139c58e83d9b09
  #include "zend_exceptions.h"
  #include "zend_vm.h"
  #include "zend_dtrace.h"
 +#include "zend_smart_str.h"
 +
 +ZEND_API zend_class_entry *zend_ce_throwable;
 +ZEND_API zend_class_entry *zend_ce_exception;
 +ZEND_API zend_class_entry *zend_ce_error_exception;
 +ZEND_API zend_class_entry *zend_ce_error;
 +ZEND_API zend_class_entry *zend_ce_parse_error;
 +ZEND_API zend_class_entry *zend_ce_type_error;
 +ZEND_API zend_class_entry *zend_ce_arithmetic_error;
 +ZEND_API zend_class_entry *zend_ce_division_by_zero_error;
 +
 +ZEND_API void (*zend_throw_exception_hook)(zval *ex);
  
 -static zend_class_entry *default_exception_ce;
 -static 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_exception_set_previous(zval *exception, zval *add_previous TSRMLS_DC)
 +/* {{{ zend_implement_throwable */
 +static int zend_implement_throwable(zend_class_entry *interface, zend_class_entry *class_type)
 +{
 +      if (instanceof_function(class_type, zend_ce_exception) || instanceof_function(class_type, zend_ce_error)) {
 +              return SUCCESS;
 +      }
 +      zend_error_noreturn(E_ERROR, "Class %s cannot implement interface %s, extend %s or %s instead",
 +              ZSTR_VAL(class_type->name),
 +              ZSTR_VAL(interface->name),
 +              ZSTR_VAL(zend_ce_exception->name),
 +              ZSTR_VAL(zend_ce_error->name));
 +      return FAILURE;
 +}
 +/* }}} */
 +
 +static inline zend_class_entry *i_get_exception_base(zval *object)
 +{
 +      return instanceof_function(Z_OBJCE_P(object), zend_ce_exception) ? zend_ce_exception : zend_ce_error;
 +}
 +
 +ZEND_API zend_class_entry *zend_get_exception_base(zval *object)
 +{
 +      return i_get_exception_base(object);
 +}
 +
 +void zend_exception_set_previous(zend_object *exception, zend_object *add_previous)
  {
-     zval tmp, *previous, zv, *pzv, rv;
 -      zval *previous, *ancestor;
++    zval *previous, *pzv;
++      zval tmp, zv, rv;
 +      zend_class_entry *base_ce;
  
        if (exception == add_previous || !add_previous || !exception) {
                return;
        }
 -      if (Z_TYPE_P(add_previous) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(add_previous), default_exception_ce TSRMLS_CC)) {
 -              zend_error(E_ERROR, "Cannot set non exception as previous exception");
 +      ZVAL_OBJ(&tmp, add_previous);
 +      if (!instanceof_function(Z_OBJCE(tmp), zend_ce_throwable)) {
 +              zend_error_noreturn(E_CORE_ERROR, "Previous exception must implement Throwable");
                return;
        }
 -      ancestor = zend_read_property(default_exception_ce, add_previous, "previous", sizeof("previous")-1, 1 TSRMLS_CC);
 -      while (Z_TYPE_P(ancestor) == IS_OBJECT) { 
 -              if (Z_OBJ_HANDLE_P(ancestor) == Z_OBJ_HANDLE_P(exception)) {
++      pzv = zend_read_property(i_get_exception_base(&tmp), &tmp, "previous", sizeof("previous")-1, 1, &rv);
++      while (Z_TYPE_P(pzv) == IS_OBJECT) { 
++              if (Z_OBJ_P(pzv) == exception) {
+                       return;
+               }
 -              ancestor = zend_read_property(default_exception_ce, ancestor, "previous", sizeof("previous")-1, 1 TSRMLS_CC);
++              pzv = zend_read_property(i_get_exception_base(pzv), pzv, "previous", sizeof("previous")-1, 1, &rv);
+       }
 -      while (exception && exception != add_previous && Z_OBJ_HANDLE_P(exception) != Z_OBJ_HANDLE_P(add_previous)) {
 -              previous = zend_read_property(default_exception_ce, exception, "previous", sizeof("previous")-1, 1 TSRMLS_CC);
 +      ZVAL_OBJ(&zv, exception);
 +      pzv = &zv;
 +      do {
 +              base_ce = i_get_exception_base(pzv);
 +              previous = zend_read_property(base_ce, pzv, "previous", sizeof("previous")-1, 1, &rv);
                if (Z_TYPE_P(previous) == IS_NULL) {
 -                      zend_update_property(default_exception_ce, exception, "previous", sizeof("previous")-1, add_previous TSRMLS_CC);
 -                      Z_DELREF_P(add_previous);
 +                      zend_update_property(base_ce, pzv, "previous", sizeof("previous")-1, &tmp);
 +                      GC_REFCOUNT(add_previous)--;
                        return;
                }
 -              exception = previous;
 -      }
 +              pzv = previous;
 +      } while (pzv && Z_OBJ_P(pzv) != add_previous);
  }
  
 -void zend_exception_save(TSRMLS_D) /* {{{ */
 +void zend_exception_save(void) /* {{{ */
  {
        if (EG(prev_exception)) {
 -              zend_exception_set_previous(EG(exception), EG(prev_exception) TSRMLS_CC);
 +              zend_exception_set_previous(EG(exception), EG(prev_exception));
        }
        if (EG(exception)) {
                EG(prev_exception) = EG(exception);