Skip to content

Commit

Permalink
bug #40065 [ErrorHandler] fix handling messages with null bytes from …
Browse files Browse the repository at this point in the history
…anonymous classes (nicolas-grekas)

This PR was merged into the 4.4 branch.

Discussion
----------

[ErrorHandler] fix handling messages with null bytes from anonymous classes

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

PHP truncates error messages at null bytes before calling userland error handlers (known behavior in PHP, marked as "won't fix".)

This doesn't play well with anonymous classes.

This PR works around the issue by getting the message from the stack trace.

Commits
-------

ac94746 [ErrorHandler] fix handling messages with null bytes from anonymous classes
  • Loading branch information
nicolas-grekas committed Feb 4, 2021
2 parents 75e7fb6 + ac94746 commit 6ce4d38
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 12 deletions.
23 changes: 18 additions & 5 deletions src/Symfony/Component/ErrorHandler/ErrorHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -422,11 +422,7 @@ public function handleError(int $type, string $message, string $file, int $line)
return false;
}

if (false !== strpos($message, "@anonymous\0")) {
$logMessage = $this->parseAnonymousClass($message);
} else {
$logMessage = $this->levels[$type].': '.$message;
}
$logMessage = $this->levels[$type].': '.$message;

if (null !== self::$toStringException) {
$errorAsException = self::$toStringException;
Expand Down Expand Up @@ -455,6 +451,23 @@ public function handleError(int $type, string $message, string $file, int $line)
return true;
}
} else {
if (false !== strpos($message, '@anonymous')) {
$backtrace = debug_backtrace(false, 5);

for ($i = 1; isset($backtrace[$i]); ++$i) {
if (isset($backtrace[$i]['function'], $backtrace[$i]['args'][0])
&& ('trigger_error' === $backtrace[$i]['function'] || 'user_error' === $backtrace[$i]['function'])
) {
if ($backtrace[$i]['args'][0] !== $message) {
$message = $this->parseAnonymousClass($backtrace[$i]['args'][0]);
$logMessage = $this->levels[$type].': '.$message;
}

break;
}
}
}

$errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line);

if ($throw || $this->tracedErrors & $type) {
Expand Down
12 changes: 5 additions & 7 deletions src/Symfony/Component/ErrorHandler/Tests/ErrorHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -368,22 +368,20 @@ public function testHandleUserError()

public function testHandleErrorWithAnonymousClass()
{
$anonymousObject = new class() extends \stdClass {
};

$handler = ErrorHandler::register();
$handler->throwAt(3, true);
try {
$handler->handleError(3, 'foo '.\get_class(new class() extends \stdClass {
}).' bar', 'foo.php', 12);
trigger_error('foo '.\get_class($anonymousObject).' bar', \E_USER_WARNING);
$this->fail('Exception expected.');
} catch (\ErrorException $e) {
} finally {
restore_error_handler();
restore_exception_handler();
}

$this->assertSame('foo stdClass@anonymous bar', $e->getMessage());
$this->assertSame(3, $e->getSeverity());
$this->assertSame('foo.php', $e->getFile());
$this->assertSame(12, $e->getLine());
$this->assertSame('User Warning: foo stdClass@anonymous bar', $e->getMessage());
}

public function testHandleDeprecation()
Expand Down

0 comments on commit 6ce4d38

Please sign in to comment.