]> granicus.if.org Git - php/commitdiff
Handle exceptions in casting more gracefully.
authorMarcus Boerger <helly@php.net>
Sat, 8 Nov 2003 14:06:08 +0000 (14:06 +0000)
committerMarcus Boerger <helly@php.net>
Sat, 8 Nov 2003 14:06:08 +0000 (14:06 +0000)
This fixes bug #26166

Zend/tests/bug26166.phpt [new file with mode: 0755]
Zend/zend.c
Zend/zend_object_handlers.c
Zend/zend_operators.c

diff --git a/Zend/tests/bug26166.phpt b/Zend/tests/bug26166.phpt
new file mode 100755 (executable)
index 0000000..46a8e3a
--- /dev/null
@@ -0,0 +1,67 @@
+--TEST--
+Bug #26166: __toString() crash when no values returned
+--FILE--
+<?php
+class Foo
+{
+    function __toString()
+    {
+        return "Hello World!\n";
+    }
+}
+
+class Bar
+{
+    private $obj;
+
+    function __construct()
+    {
+        $this->obj = new Foo();
+    }
+
+    function __toString()
+    {
+        return $this->obj->__toString();
+    }
+}
+
+$o = new Bar;
+echo $o;
+
+echo "===THROW===\n";
+
+class Error 
+{
+       function __toString() {
+               throw new Exception("This is an error!");
+       }
+}
+
+$o = new Error;
+try {
+       echo $o;
+}
+catch (Exception $e) {
+       echo "Got the exception\n";
+}
+
+echo "===NONE===\n";
+
+class None
+{
+       function __toString() {
+       }
+}
+
+$o = new None;
+echo $o;
+
+?>
+===DONE===
+--EXPECTF--
+Hello World!
+===THROW===
+Got the exception
+===NONE===
+
+Fatal error: Method none::__toString() must return a string value in %sbug26166.php on line %d
index 2e5d37cfc8775c6538341a8740c6b7bbe0181544..fe0070d4aae3e71508e83078a6f801e41b56fe02 100644 (file)
@@ -230,6 +230,12 @@ ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_cop
                                if (expr->value.obj.handlers->cast_object(expr, expr_copy, IS_STRING, 0 TSRMLS_CC) == SUCCESS) {
                                        break;
                                }
+                               if (EG(exception)) {
+                                       zval_dtor(expr_copy);
+                                       expr_copy->value.str.len = 0;
+                                       expr_copy->value.str.val = empty_string;
+                                       break;
+                               }
                        }
                        expr_copy->value.str.val = (char *) emalloc(sizeof("Object id #")-1 + MAX_LENGTH_OF_LONG);
                        expr_copy->value.str.len = sprintf(expr_copy->value.str.val, "Object id #%ld", (long)expr->value.obj.handle);
index a371ebfce8dbe004281857e6fdc65d337da21f3e..56d212f387e5223bd0c90b1364d5c3f4c70a5a0b 100644 (file)
@@ -869,8 +869,13 @@ int zend_std_cast_object(zval *readobj, zval *writeobj, int type, int should_fre
        case IS_STRING:
                ZVAL_STRING(&fname, "__tostring", 0);
                if (call_user_function_ex(NULL, &readobj, &fname, &retval, 0, NULL, 0, NULL TSRMLS_CC) == SUCCESS) {
-                       if (Z_TYPE_P(retval) != IS_STRING) {
-                               zend_error(E_ERROR, "Method %s::__toString() must return a string value", Z_OBJCE_P(readobj)->name);
+                       if (retval) {
+                               if (Z_TYPE_P(retval) != IS_STRING) {
+                                       zend_error(E_ERROR, "Method %s::__toString() must return a string value", Z_OBJCE_P(readobj)->name);
+                               }
+                       } else {
+                               MAKE_STD_ZVAL(retval);
+                               ZVAL_STRINGL(retval, empty_string, 0, 0);
                        }
                        REPLACE_ZVAL_VALUE(&writeobj, retval, 0);
                        return SUCCESS;
index f95a6f6aeb2322b06be2a45021f2ff67ef5df503..453f1f0f5c326c39628429f7fc4a65598e1d0ab1 100644 (file)
@@ -445,7 +445,6 @@ ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC)
 {
        long lval;
        double dval;
-       TSRMLS_FETCH();
 
        switch (op->type) {
                case IS_NULL:
@@ -465,6 +464,7 @@ ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC)
                        break;
                case IS_RESOURCE: {
                        long tmp = op->value.lval;
+                       TSRMLS_FETCH();
 
                        zend_list_delete(op->value.lval);
                        op->value.str.val = (char *) emalloc(sizeof("Resource id #")-1 + MAX_LENGTH_OF_LONG);
@@ -478,6 +478,7 @@ ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC)
                        op->value.str.len = zend_sprintf(op->value.str.val, "%ld", lval);  /* SAFE */
                        break;
                case IS_DOUBLE: {
+                       TSRMLS_FETCH();
                        dval = op->value.dval;
                        op->value.str.val = (char *) emalloc_rel(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
                        op->value.str.len = zend_sprintf(op->value.str.val, "%.*G", (int) EG(precision), dval);  /* SAFE */
@@ -490,11 +491,11 @@ ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC)
                        op->value.str.val = estrndup_rel("Array", sizeof("Array")-1);
                        op->value.str.len = sizeof("Array")-1;
                        break;
-               case IS_OBJECT:
+               case IS_OBJECT: {
+                       TSRMLS_FETCH();
                        if (op->value.obj.handlers->cast_object) {
                                zval tmp;
-                               TSRMLS_FETCH();
-                               if (op->value.obj.handlers->cast_object(op, &tmp, IS_STRING, 1 TSRMLS_CC) == SUCCESS) {
+                               if (op->value.obj.handlers->cast_object(op, &tmp, IS_STRING, 1 TSRMLS_CC) == SUCCESS && tmp.type == IS_STRING) {
                                        zval_dtor(op);
                                        *op = tmp;
                                        break;
@@ -507,6 +508,7 @@ ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC)
                        op->value.str.val = estrndup_rel("Object", sizeof("Object")-1);
                        op->value.str.len = sizeof("Object")-1;
                        break;
+               }
                default:
                        zval_dtor(op);
                        ZVAL_BOOL(op, 0);