I just ran into this issue again:
http://stackoverflow.com/questions/2429642/why-its-impossible-to-throw-exception-from-tostring
Instead of throwing some nonsense "you're not allowed to throw from here"
error-message, how about actually unwinding the stack and passing the
exception to the global exception-handler?
I understand there's a technical limitation making it difficult/impossible
to handle exceptions during __toString() - and it looks like you can still
try {...} catch (Exception $e) in __toString() just fine, but then what?
You have the exception, but you have no way to pass it to the standard
global exception-handler.
If the script has to terminate either way, why not terminate the same way
an unhandled exception would normally cause the script to terminate?
E.g. output the actual error-message, or pass it to whatever was registered
with register_exception_handler() so it can be output or handled in the
usual way?
On Fri, May 10, 2013 at 12:00 AM, Rasmus Schultz me@rasmus-schultz.comwrote:
I just ran into this issue again:
http://stackoverflow.com/questions/2429642/why-its-impossible-to-throw-exception-from-tostring
Instead of throwing some nonsense "you're not allowed to throw from here"
error-message, how about actually unwinding the stack and passing the
exception to the global exception-handler?I understand there's a technical limitation making it difficult/impossible
to handle exceptions during __toString() - and it looks like you can still
try {...} catch (Exception $e) in __toString() just fine, but then what?
You have the exception, but you have no way to pass it to the standard
global exception-handler.If the script has to terminate either way, why not terminate the same way
an unhandled exception would normally cause the script to terminate?E.g. output the actual error-message, or pass it to whatever was registered
with register_exception_handler() so it can be output or handled in the
usual way?
The reason is that toString can be triggered from a lot of internal places.
If an exception is thrown and caught within toString, it's not a problem.
The problem is if the exception escapes toString, because it thus means
that the code invoking toString must be interrupted.
We in fact have no guarantee that all those internal places will work
consistently/correctly in the presence of an exception, and if the engine
will remain in a state that allows executing code afterward.
Not executing code means we need to bypass error handlers as well.
Handling an exception from internal code is a "manual" procedure, and code
written that relies on conversions to strings may not have been written
with support for exceptions in mind.
I guess the alternative approach is to allow exceptions, review the code
(i.e. a lot of work), and eventually fix reports as they come in.
Best,
--
Etienne Kneuss
I've heard the technical explanation before, and while it probably doesn't
make sense to go through all that effort to fix this... well... take this
example:
class Foo
{
public function __toString()
{
try {
return $this->bar();
} catch (Exception $e) {
trigger_error(E_USER_ERROR, $e->__toString());
}
}
protected function bar()
{
throw new RuntimeException('ouch');
}
}
$test = new Foo();
echo $test;
This is OK in theory, but just rather odd, and won't work with many
frameworks and error-handlers, if errors are caught and thrown as the
built-in ErrorException - the natural expectation would be that this should
be enough:
public function __toString()
{
return $this->bar();
}
What if that basically did the same thing? An implicit try/catch inside
__toString() as above, but instead of passing the error to trigger_error()
and triggering the error-handler, pass it to the built-in
exception-handler, or whatever was configured with set_exception_handler()
That way, we would at least get a meaningful error message, even if it's
still not possible for exceptions to bubble up through implicit calls made
to __toString() internally.
Wouldn't that at least suck less? :-)
On Fri, May 10, 2013 at 12:00 AM, Rasmus Schultz me@rasmus-schultz.comwrote:
I just ran into this issue again:
http://stackoverflow.com/questions/2429642/why-its-impossible-to-throw-exception-from-tostring
Instead of throwing some nonsense "you're not allowed to throw from here"
error-message, how about actually unwinding the stack and passing the
exception to the global exception-handler?I understand there's a technical limitation making it difficult/impossible
to handle exceptions during __toString() - and it looks like you can still
try {...} catch (Exception $e) in __toString() just fine, but then what?
You have the exception, but you have no way to pass it to the standard
global exception-handler.If the script has to terminate either way, why not terminate the same way
an unhandled exception would normally cause the script to terminate?E.g. output the actual error-message, or pass it to whatever was
registered
with register_exception_handler() so it can be output or handled in the
usual way?The reason is that toString can be triggered from a lot of internal
places.
If an exception is thrown and caught within toString, it's not a problem.
The problem is if the exception escapes toString, because it thus means
that the code invoking toString must be interrupted.We in fact have no guarantee that all those internal places will work
consistently/correctly in the presence of an exception, and if the engine
will remain in a state that allows executing code afterward.
Not executing code means we need to bypass error handlers as well.Handling an exception from internal code is a "manual" procedure, and code
written that relies on conversions to strings may not have been written
with support for exceptions in mind.I guess the alternative approach is to allow exceptions, review the code
(i.e. a lot of work), and eventually fix reports as they come in.Best,
--
Etienne Kneuss
On Fri, May 10, 2013 at 12:00 AM, Rasmus Schultz <me@rasmus-schultz.com
wrote:
I just ran into this issue again:
http://stackoverflow.com/questions/2429642/why-its-impossible-to-throw-exception-from-tostring
Instead of throwing some nonsense "you're not allowed to throw from here"
error-message, how about actually unwinding the stack and passing the
exception to the global exception-handler?I understand there's a technical limitation making it
difficult/impossible
to handle exceptions during __toString() - and it looks like you can
still
try {...} catch (Exception $e) in __toString() just fine, but then what?
You have the exception, but you have no way to pass it to the standard
global exception-handler.If the script has to terminate either way, why not terminate the same way
an unhandled exception would normally cause the script to terminate?E.g. output the actual error-message, or pass it to whatever was
registered
with register_exception_handler() so it can be output or handled in the
usual way?The reason is that toString can be triggered from a lot of internal places.
If an exception is thrown and caught within toString, it's not a problem.
The problem is if the exception escapes toString, because it thus means
that the code invoking toString must be interrupted.We in fact have no guarantee that all those internal places will work
consistently/correctly in the presence of an exception, and if the engine
will remain in a state that allows executing code afterward.
Not executing code means we need to bypass error handlers as well.Handling an exception from internal code is a "manual" procedure, and code
written that relies on conversions to strings may not have been written
with support for exceptions in mind.I guess the alternative approach is to allow exceptions, review the code
(i.e. a lot of work), and eventually fix reports as they come in.Best,
--
Etienne Kneuss
if somebody thinks that these kind of vulnerabilities are hypotetical, we
had a bunch of Interruption Vulnerabilities in the past and this could
potentionally introduce a lot more, but I think that this is something that
we have to resolve sooner or later, otherwise a whole bunch of proposed
features can never be introduced (for example accepting ArrayObjects
everywhere where array is accepted).
--
Ferenc Kovács
@Tyr43l - http://tyrael.hu