summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xZend/tests/bug26166.phpt67
-rw-r--r--Zend/zend.c6
-rw-r--r--Zend/zend_object_handlers.c9
-rw-r--r--Zend/zend_operators.c10
4 files changed, 86 insertions, 6 deletions
diff --git a/Zend/tests/bug26166.phpt b/Zend/tests/bug26166.phpt
new file mode 100755
index 0000000000..46a8e3a614
--- /dev/null
+++ b/Zend/tests/bug26166.phpt
@@ -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
diff --git a/Zend/zend.c b/Zend/zend.c
index 2e5d37cfc8..fe0070d4aa 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -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);
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index a371ebfce8..56d212f387 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -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;
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c
index f95a6f6aeb..453f1f0f5c 100644
--- a/Zend/zend_operators.c
+++ b/Zend/zend_operators.c
@@ -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);