Skip to content

Fix: always restore error handler in object cache Redis _connect() (finally + \Throwable)#1014

Open
vbakkenes wants to merge 1 commit into
litespeedtech:masterfrom
vbakkenes:fix/oc-redis-connect-restore-error-handler
Open

Fix: always restore error handler in object cache Redis _connect() (finally + \Throwable)#1014
vbakkenes wants to merge 1 commit into
litespeedtech:masterfrom
vbakkenes:fix/oc-redis-connect-restore-error-handler

Conversation

@vbakkenes

Copy link
Copy Markdown

Problem

Object_Cache::_connect() registers set_error_handler( 'litespeed_exception_handler' ) around the Redis connection, but only catches \Exception / \ErrorException and calls restore_error_handler() after the try/catch. If a \Error (e.g. a TypeError/ValueError on PHP 8.x) escapes the connect path, both catch blocks are skipped, restore_error_handler() never runs, and litespeed_exception_handler stays registered for the rest of the request.

Since that handler rethrows every PHP error as an ErrorException, any later unrelated PHP 8.1+ deprecation — e.g. Gravity Forms dirname(null) or Wordfence strrpos(null) — becomes a fatal Uncaught ErrorException, white-screening the whole site even with WP_DEBUG off. The stack trace points at the other plugin, so it's very hard to trace back to the object cache.

Also, the catch ( \ErrorException $e ) after catch ( \Exception $e ) was unreachable — \ErrorException extends \Exception.

Fix

Catch \Throwable (covers \Error too, and folds in the previously-unreachable \ErrorException branch) and move restore_error_handler() into a finally so the handler is always restored.

Notes

  • \Throwable / finally are PHP 7.0+, within the plugin's Requires PHP: 7.2.
  • Behaviour on a genuine connection failure is unchanged: $failed = true and fall back as before.

Fixes #1013

_connect() sets litespeed_exception_handler around the Redis connection but
only caught \Exception/\ErrorException and called restore_error_handler()
after the try/catch. A \Error escaping the connect path (e.g. a TypeError on
PHP 8.x) skipped both catches and the restore, leaking the handler for the
rest of the request. It then rethrew every later unrelated PHP deprecation
(Gravity Forms dirname(null), Wordfence strrpos(null), ...) as a fatal
ErrorException, white-screening the whole site even with WP_DEBUG off.

Catch \Throwable (also removes the unreachable \ErrorException catch, since
\ErrorException extends \Exception) and move restore_error_handler() into a
finally so the handler is always restored.

Fixes litespeedtech#1013

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Object cache Redis _connect() leaks litespeed_exception_handler; later PHP deprecations become fatals on PHP 8.1+

1 participant