Compare commits

...

13 Commits

Author SHA1 Message Date
Nicolas Grekas
a9844f3cd2 bug #20519 [Debug] Remove GLOBALS from exception context to avoid endless recursion (Seldaek)
This PR was merged into the 2.7 branch.

Discussion
----------

[Debug] Remove GLOBALS from exception context to avoid endless recursion

| Q             | A
| ------------- | ---
| Branch?       | 2.7
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| License       | MIT

This fixes a endless recursion as seen in https://github.com/felixfbecker/php-language-server/pull/137 - it only happens if you trigger an error in the global context so it's kinda hard to write a test for, but hopefully the fix can be accepted.

Commits
-------

1bb95ac [Debug] Remove GLOBALS from exception context to avoid endless recursion
2016-11-15 07:52:31 -05:00
Jordi Boggiano
0a8d55717a [Debug] Remove GLOBALS from exception context to avoid endless recursion 2016-11-15 13:37:17 +01:00
Dariusz Ruminski
6945a0d019 CS: apply rules 2016-11-03 08:44:53 +01:00
Yonel Ceruto
659f346c4a Code enhancement and cleanup 2016-09-06 09:26:07 +02:00
Nicolas Grekas
aec192ddd4 [Debug][HttpKernel][VarDumper] Prepare for committed 7.2 changes 2016-08-22 19:42:59 +02:00
Dionysis Arvanitis
a3a850315e Exception details break the layout 2016-08-18 21:55:40 +03:00
Vyacheslav Pavlov
31106b58d5 Minor fixes 2016-07-30 03:17:26 -04:00
Vyacheslav Pavlov
13ebf897a8 Fixed bugs in names of classes and methods. 2016-07-26 06:40:54 +02:00
Fabien Potencier
d9e18587ad removed dots at the end of @param and @return 2016-06-28 08:24:06 +02:00
Nicolas Grekas
00f654c530 [Debug] Fix context dependent test 2016-06-06 13:49:15 +02:00
Filip Procházka
dfaa39d719 Catch \Throwable 2016-05-19 15:58:47 +02:00
Nicolas Grekas
5fe2066e79 [Debug] Fix fatal error handlers on PHP 7 2016-05-09 15:05:29 -05:00
Nicolas Grekas
3b97c83b47 [Debug] Fix case sensitivity checks 2016-03-30 11:14:15 +02:00
12 changed files with 78 additions and 38 deletions

View File

@@ -51,15 +51,25 @@ class DebugClassLoader
}
if (!isset(self::$caseCheck)) {
if(!file_exists(strtolower(__FILE__))) {
$file = file_exists(__FILE__) ? __FILE__ : rtrim(realpath('.'), DIRECTORY_SEPARATOR);
$i = strrpos($file, DIRECTORY_SEPARATOR);
$dir = substr($file, 0, 1 + $i);
$file = substr($file, 1 + $i);
$test = strtoupper($file) === $file ? strtolower($file) : strtoupper($file);
$test = realpath($dir.$test);
if (false === $test || false === $i) {
// filesystem is case sensitive
self::$caseCheck = 0;
} elseif(realpath(strtolower(__FILE__)) === __FILE__) {
// filesystem is not case sensitive
} elseif (substr($test, -strlen($file)) === $file) {
// filesystem is case insensitive and realpath() normalizes the case of characters
self::$caseCheck = 1;
} else {
// filesystem is not case sensitive AND realpath() fails to normalize case
} elseif (false !== stripos(PHP_OS, 'darwin')) {
// on MacOSX, HFS+ is case insensitive but realpath() doesn't normalize the case of characters
self::$caseCheck = 2;
} else {
// filesystem case checks failed, fallback to disabling them
self::$caseCheck = 0;
}
}
}
@@ -165,6 +175,10 @@ class DebugClassLoader
} catch (\Exception $e) {
ErrorHandler::unstackErrors();
throw $e;
} catch (\Throwable $e) {
ErrorHandler::unstackErrors();
throw $e;
}

View File

@@ -349,12 +349,14 @@ class ErrorHandler
/**
* Handles errors by filtering then logging them according to the configured bit fields.
*
* @param int $type One of the E_* constants
* @param int $type One of the E_* constants
* @param string $message
* @param string $file
* @param int $line
* @param array $context
* @param array $backtrace
*
* @return bool Returns false when no handling happens so that the PHP engine can handle the error itself.
* @return bool Returns false when no handling happens so that the PHP engine can handle the error itself
*
* @throws \ErrorException When $this->thrownErrors requests so
*
@@ -371,7 +373,7 @@ class ErrorHandler
return $type && $log;
}
if (PHP_VERSION_ID < 50400 && isset($context['GLOBALS']) && ($this->scopedErrors & $type)) {
if (isset($context['GLOBALS']) && ($this->scopedErrors & $type)) {
$e = $context; // Whatever the signature of the method,
unset($e['GLOBALS'], $context); // $context is always a reference in 5.3
$context = $e;
@@ -447,6 +449,10 @@ class ErrorHandler
} catch (\Exception $e) {
$this->isRecursive = false;
throw $e;
} catch (\Throwable $e) {
$this->isRecursive = false;
throw $e;
}
}
@@ -469,7 +475,7 @@ class ErrorHandler
}
$type = $exception instanceof FatalErrorException ? $exception->getSeverity() : E_ERROR;
if ($this->loggedErrors & $type) {
if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) {
$e = array(
'type' => $type,
'file' => $exception->getFile(),
@@ -496,9 +502,9 @@ class ErrorHandler
} else {
$message = 'Uncaught Exception: '.$exception->getMessage();
}
if ($this->loggedErrors & $e['type']) {
$this->loggers[$e['type']][0]->log($this->loggers[$e['type']][1], $message, $e);
}
}
if ($this->loggedErrors & $type) {
$this->loggers[$type][0]->log($this->loggers[$type][1], $message, $e);
}
if ($exception instanceof FatalErrorException && !$exception instanceof OutOfMemoryException && $error) {
foreach ($this->getFatalErrorHandlers() as $handler) {
@@ -555,6 +561,8 @@ class ErrorHandler
}
} catch (\Exception $exception) {
// Handled below
} catch (\Throwable $exception) {
// Handled below
}
if ($error && $error['type'] &= E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR) {

View File

@@ -27,7 +27,7 @@ class FatalThrowableError extends FatalErrorException
$message = 'Type error: '.$e->getMessage();
$severity = E_RECOVERABLE_ERROR;
} else {
$message = 'Fatal error: '.$e->getMessage();
$message = $e->getMessage();
$severity = E_ERROR;
}

View File

@@ -263,7 +263,10 @@ class FlattenException extends LegacyFlattenException
if (++$count > 1e4) {
return array('array', '*SKIPPED over 10000 entries*');
}
if (is_object($value)) {
if ($value instanceof \__PHP_Incomplete_Class) {
// is_object() returns false on PHP<=7.1
$result[$key] = array('incomplete-object', $this->getClassNameFromIncomplete($value));
} elseif (is_object($value)) {
$result[$key] = array('object', get_class($value));
} elseif (is_array($value)) {
if ($level > 10) {
@@ -277,9 +280,6 @@ class FlattenException extends LegacyFlattenException
$result[$key] = array('boolean', $value);
} elseif (is_resource($value)) {
$result[$key] = array('resource', get_resource_type($value));
} elseif ($value instanceof \__PHP_Incomplete_Class) {
// Special case of object, is_object will return false
$result[$key] = array('incomplete-object', $this->getClassNameFromIncomplete($value));
} else {
$result[$key] = array('string', (string) $value);
}

View File

@@ -94,7 +94,7 @@ class ExceptionHandler
*
* @param string $format The format for links to source files
*
* @return string The previous file link format.
* @return string The previous file link format
*/
public function setFileLinkFormat($format)
{
@@ -319,6 +319,7 @@ EOF;
border-bottom:1px solid #ccc;
border-right:1px solid #ccc;
border-left:1px solid #ccc;
word-wrap: break-word;
}
.sf-reset .block_exception { background-color:#ddd; color: #333; padding:20px;
-webkit-border-top-left-radius: 16px;

View File

@@ -1,14 +1,14 @@
--TEST--
Test symfony_zval_info API
--SKIPIF--
<?php if (!extension_loaded("symfony_debug")) print "skip"; ?>
<?php if (!extension_loaded('symfony_debug')) print 'skip'; ?>
--FILE--
<?php
$int = 42;
$float = 42.42;
$str = "foobar";
$object = new StdClass;
$str = 'foobar';
$object = new StdClass();
$array = array('foo', 'bar');
$resource = tmpfile();
$null = null;
@@ -17,15 +17,17 @@ $bool = true;
$anotherint = 42;
$refcount2 = &$anotherint;
$var = array('int' => $int,
'float' => $float,
'str' => $str,
'object' => $object,
'array' => $array,
'resource' => $resource,
'null' => $null,
'bool' => $bool,
'refcount' => &$refcount2);
$var = array(
'int' => $int,
'float' => $float,
'str' => $str,
'object' => $object,
'array' => $array,
'resource' => $resource,
'null' => $null,
'bool' => $bool,
'refcount' => &$refcount2,
);
var_dump(symfony_zval_info('int', $var));
var_dump(symfony_zval_info('float', $var));

View File

@@ -1,7 +1,7 @@
--TEST--
Test symfony_debug_backtrace in case of fatal error
--SKIPIF--
<?php if (!extension_loaded("symfony_debug")) print "skip"; ?>
<?php if (!extension_loaded('symfony_debug')) print 'skip'; ?>
--FILE--
<?php
@@ -18,7 +18,6 @@ function foo()
function bt()
{
print_r(symfony_debug_backtrace());
}
register_shutdown_function('bt');

View File

@@ -1,7 +1,7 @@
--TEST--
Test symfony_debug_backtrace in case of non fatal error
--SKIPIF--
<?php if (!extension_loaded("symfony_debug")) print "skip"; ?>
<?php if (!extension_loaded('symfony_debug')) print 'skip'; ?>
--FILE--
<?php
@@ -13,7 +13,6 @@ function bar()
function bt()
{
print_r(symfony_debug_backtrace());
}
bar();

View File

@@ -1,7 +1,7 @@
--TEST--
Test ErrorHandler in case of fatal error
--SKIPIF--
<?php if (!extension_loaded("symfony_debug")) print "skip"; ?>
<?php if (!extension_loaded('symfony_debug')) print 'skip'; ?>
--FILE--
<?php

View File

@@ -13,12 +13,11 @@ namespace Symfony\Component\Debug\Tests;
use Symfony\Component\Debug\DebugClassLoader;
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\Debug\Exception\ContextErrorException;
class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase
{
/**
* @var int Error reporting level before running tests.
* @var int Error reporting level before running tests
*/
private $errorReporting;

View File

@@ -413,6 +413,24 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
}
}
/**
* @requires PHP 7
*/
public function testHandleErrorException()
{
$exception = new \Error("Class 'Foo' not found");
$handler = new ErrorHandler();
$handler->setExceptionHandler(function () use (&$args) {
$args = func_get_args();
});
$handler->handleException($exception);
$this->assertInstanceOf('Symfony\Component\Debug\Exception\ClassNotFoundException', $args[0]);
$this->assertStringStartsWith("Attempted to load class \"Foo\" from the global namespace.\nDid you forget a \"use\" statement", $args[0]->getMessage());
}
public function testHandleFatalErrorOnHHVM()
{
try {

View File

@@ -13,7 +13,7 @@ namespace Symfony\Component\Debug\Tests;
use Symfony\Component\Debug\ExceptionHandler;
class MockExceptionHandler extends Exceptionhandler
class MockExceptionHandler extends ExceptionHandler
{
public $e;