Backtraces for DatabaseExceptionWrappers, lacking a previous Exception, cause a Fatal Error, due to a method call on a non-object.

Fatal error: Call to a member function getTrace() on a non-object in ../core/lib/Drupal/Core/Controller/ExceptionController.php on line 332

The method, ExceptionController::decodeException(), has a refactoring @todo, but I can't find anything else addressing it currently.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

xtfer’s picture

Status: Active » Needs review
FileSize
1.89 KB

Simple wrap in is_object().

xtfer’s picture

Assigned: Unassigned » xtfer

Status: Needs review » Needs work

The last submitted patch, 2003654-1-fatal-error-for-DatabaseExceptionWrapper.diff, failed testing.

glennpratt’s picture

Status: Needs work » Needs review
larowlan’s picture

Minor nit

+++ b/core/lib/Drupal/Core/Controller/ExceptionController.phpundefined
@@ -329,7 +329,22 @@ protected function decodeException(FlattenException $exception) {
+        // The first element in the stack is the call, the second element gives us the caller.
+        // We skip calls that occurred in one of the classes of the database layer

Should wrap at 80 chars

Any way you can replicate this in a test?

xtfer’s picture

Title: Backtraces for DatabaseExceptionWrappers lacking a previous Exception cause a Fatal Error » DatabaseExceptionWrapper::decodeException() depends on an optional previous Exception
Status: Needs review » Needs work

Further investigation has shown that this is caused by \Drupal\views\Plugin\views\query\Sql() not properly passing the Exception through to the DatabaseExceptionWrapper, but not passing the original Exception. This is an implementation detail where the caller doesn't have sufficient information to pass the parameters correctly.

This suggest the fix is two-fold:

- Fix \Drupal\views\Plugin\views\query\Sql() to pass the $e correctly
- Refactor DatabaseExceptionWrapper so that it contains the correct logic to avoid this situation in future.

xtfer’s picture

Status: Needs work » Needs review
FileSize
9.85 KB

This patch does the following:

- Tidies up ExceptionController::decodeException().
- Adds a new exception type, ExceptionWrapper, which forces the previous Exception to be injected.
- Bases DatabaseExceptionWrapper of ExceptionWrapper
- Includes a test for ExceptionWrapper to ensure the dependency is set.
- Updates \Drupal\views\Plugin\views\query\Sql() to set the previous Exception correctly.

In addition, I corrected a spelling mistake in DatabaseExceptionWrapperTest.

The potential issue I can see currently is that ExceptionController never gets the actual Exception, just a flattened Symfony FlattenException object, which seems a bit odd to me. This makes it hard to check what type of Exception you've actually got. There seem to be two potential solutions to this problem, mocking a new exception object in decodeException(), which is what Ive done, or adding the original exception back into a new DrupalFlattenException object (which seems to defeat the purpose, but should be doable).

larowlan’s picture

I like this approach

Some minor phpcs nitpicks

+++ b/core/lib/Drupal/Core/Utility/WrapperException.phpundefined
@@ -0,0 +1,37 @@
+ * Definition of Drupal\Core\Utility\WrapperException

new syntax is Contains \Drupal\Core\Utility\WrapperException

+++ b/core/lib/Drupal/Core/Utility/WrapperException.phpundefined
@@ -0,0 +1,37 @@
+use RuntimeException;

no need to use root-level objects, use \RuntimeException instead

+++ b/core/lib/Drupal/Core/Utility/WrapperException.phpundefined
@@ -0,0 +1,37 @@
+class WrapperException extends RuntimeException {

\RuntimeException once use statement is gone

+++ b/core/modules/system/lib/Drupal/system/Tests/Utility/WrapperExceptionTest.phpundefined
@@ -0,0 +1,54 @@
+ * Contains Drupal\system\Tests\Utility\WrapperExceptionTest.

needs leading \

I think the answer might be no, but I know the question will be asked - can we use UnitTestCase instead of UnitTestBase aka Php unit here instead for the test? Would require mock objects.

xtfer’s picture

Updated as per cs standards, and changed the test to PHPUnit.

larowlan’s picture

+++ b/core/tests/Drupal/Tests/Core/Utility/WrapperExceptionTest.phpundefined
@@ -0,0 +1,38 @@
+    $this->assertEquals('Exception', get_class($stub->getPrevious()));

is it worth making it new \Exception('Something went wrong') and then adding another assert such as

$this->assertEquals($stub->getPrevious()->getMessage(), 'Something went wrong');

?

Other than that RTBC imo

larowlan’s picture

+++ b/core/tests/Drupal/Tests/Core/Utility/WrapperExceptionTest.phpundefined
@@ -0,0 +1,38 @@
+    $stub = $this->getMockBuilder('\Drupal\Core\Utility\WrapperException')
+      ->setConstructorArgs(array('Test exception', 0, new \Exception()))

is there a reason why we can just go $stub = new WrapperException('Test Exception', 0, new \Exception');?
Would need a use at the top of the file obviously - I don't think we need the mock in this case because its a simple class?

xtfer’s picture

Its not worth checking the message since all we want to know is that the Exception has been set. What might be useful is a test which fails, i.e. where the Exception is not set.

As for the $stub object, it appears there is no need for it. I was just following on the examples you pointed me at. ;)

It works as it stands though, so as those two changes don't appear to be deal breakers I'd like to leave them as they are.

Status: Needs review » Needs work

The last submitted patch, 2003654-chained-exceptions-9.patch, failed testing.

larowlan’s picture

I know you're probably getting tired of my feedback........but

+++ b/core/lib/Drupal/Core/Database/DatabaseExceptionWrapper.phpundefined
@@ -7,13 +7,13 @@
+class DatabaseExceptionWrapper extends WrapperException implements DatabaseException {

Is there a reason why we need the extra class (WrapperException) can't we just make the $previous argument required on DatabaseExceptionWrapper? Then we can write a unit test for decodeException method, mocking FlattenException - but that would require changing use of check_plain something else.

xtfer’s picture

Is there a reason why we need the extra class (WrapperException) can't we just make the $previous argument required on DatabaseExceptionWrapper? Then we can write a unit test for decodeException method, mocking FlattenException - but that would require changing use of check_plain something else.

It seemed to make more sense to me to create a base for chained exceptions rather than simply put that functionality into the DatabaseExceptionWrapper. The final result is effectively the same, however.

The archicture of the so-called "ExceptionController" is problematic, though. Its actually a Logger, not a controller, which is why it gets the FlattenedException in the first place. All a bit screwy if you ask me. Its impossible to sub-class it, so we end up having to play "guess the exception class" inside of it in decodeException.

So I agree a test for decodeException would be good, but thats separate to whether we have a WrapperException or not.

xtfer’s picture

Assigned: xtfer » Unassigned
mgifford’s picture

Issue summary: View changes
Priority: Normal » Major
Status: Needs work » Needs review
FileSize
8.54 KB

I was just mucking about with Views trying to track down an exposed filter problem when I got:

PHP Fatal error: Call to a member function getTrace() on a non-object in /DRUPAL8/core/lib/Drupal/Core/Controller/ExceptionController.php on line 451

By trying to access /admin/content

Really, this should never happen with a D8 Core install. You should have to extend it somehow before seeing stuff like this. That's why I'm marking this major.

This is just a re-roll, but it didn't seem to resolve the problem, just seemed to change it.

PHP Fatal error: Class 'Drupal\Core\Database\WrapperException' not found in /DRUPAL8/core/lib/Drupal/Core/Database/DatabaseExceptionWrapper.php on line 15

Status: Needs review » Needs work

The last submitted patch, 17: 2003654-chained-exceptions-17.patch, failed testing.

mgifford’s picture

Status: Needs work » Needs review
FileSize
6.38 KB

core/lib/Drupal/Core/Utility/WrapperException.php already exists.

Other than that just a re-roll

Status: Needs review » Needs work

The last submitted patch, 19: 2003654-chained-exceptions-19.patch, failed testing.

mgifford’s picture

Status: Needs work » Needs review
FileSize
8.54 KB

hmm...

Status: Needs review » Needs work

The last submitted patch, 21: 2003654-chained-exceptions-21.patch, failed testing.

jhedstrom’s picture

Status: Needs work » Postponed (maintainer needs more info)
Issue tags: +Needs issue summary update

The ExceptionController was removed/refactored in #2323759: Modularize kernel exception handling, not sure if this is still relevant.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

pameeela’s picture

Status: Postponed (maintainer needs more info) » Closed (cannot reproduce)
Issue tags: +Bug Smash Initiative

Thanks everyone who contributed to this issue.

Based on #2323759: Modularize kernel exception handling and after consulting with xtfer we have determined this issue is no longer relevant.