Handle exceptions in casting more gracefully.

This fixes bug #26166
This commit is contained in:
Marcus Boerger 2003-11-08 14:06:08 +00:00
parent ed45157047
commit 316854323d
4 changed files with 86 additions and 6 deletions

67
Zend/tests/bug26166.phpt Executable file
View file

@ -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

View 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);

View file

@ -869,9 +869,14 @@ 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 (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;
}

View 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);