Skip to content

Infinite loop in Query Monitor when handling translations causing XDebug stack overflow #972

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
mralaminahamed opened this issue Apr 19, 2025 · 1 comment

Comments

@mralaminahamed
Copy link

Description

Query Monitor is triggering an infinite recursion loop during translation loading, causing XDebug to abort script execution after reaching the maximum stack depth of 512 frames.

Issue Details

  • Error: PHP Fatal error: Uncaught Error: Xdebug has detected a possible infinite loop, and aborted your script with a stack depth of '512' frames
  • WordPress Version: 6.7.0 (based on error message)
  • Environment: Local development with XDebug enabled
  • Reproduction Path: Plugin attempts to load translations for the 'query-monitor' text domain

Steps to Reproduce

  1. Use the latest WordPress (6.7.0+)
  2. Ensure XDebug is installed and enabled on your development environment
  3. Deactivate the Query Monitor plugin
  4. Reactivate the Query Monitor plugin
  5. The error should occur immediately after reactivation

Stack Trace Analysis

The error occurs in a circular dependency between WordPress translation functions and Query Monitor capability checks. The stack trace shows a repeating pattern where:

  • WordPress tries to load translations for Query Monitor
  • This triggers capability checks via Query Monitor's hooks
  • These capability checks attempt to get more translations
  • This leads to an infinite recursion

Possible Causes

  1. Query monitor removed the 'view_query_monitor' capability on deactivation https://github.com/johnbillion/query-monitor/blob/develop/classes/Activation.php#L56-L62
  2. Query Monitor hooks into capability checks that run during translation loading
  3. The QM_Collector_Doing_It_Wrong->maybe_prevent_doing_it_wrong_error() method seems to be in the recursion path https://github.com/johnbillion/query-monitor/blob/develop/collectors/doing_it_wrong.php#L96-L102
  4. Translation loading for Query Monitor's text domain is occurring before the plugin is fully initialized

Impact

This issue causes sites with XDebug enabled to crash during plugin activation, making debugging difficult and potentially affecting development environments.

Screenshots

Image

@doiftrue
Copy link

doiftrue commented Apr 26, 2025

More details about this issue.

If xDebug disabled we get memory limit fatal error:

Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 20480 bytes) in /var/app/wp-kama.dev/public_html/core/wp-includes/functions.php on line 7230

Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 20480 bytes) in /var/app/wp-kama.dev/public_html/core/wp-includes/class-wp-fatal-error-handler.php on line 76

The issue arises due to a recursive loop: \QM_Collector_Doing_It_Wrong::maybe_prevent_doing_it_wrong_error() calls the current_user_can() function, which internally invokes the __() function. This, in turn, triggers \QM_Collector_Doing_It_Wrong::maybe_prevent_doing_it_wrong_error() again. As a result, the process repeats, leading to an infinite loop.

Image

Image

The trace maybe will be helpfull:

doing_it_wrong.php:100, QM_Collector_Doing_It_Wrong->maybe_prevent_doing_it_wrong_error()
class-wp-hook.php:324, WP_Hook->apply_filters()
plugin.php:205, apply_filters()
functions.php:6023, _doing_it_wrong()
l10n.php:1371, _load_textdomain_just_in_time()
l10n.php:1409, get_translations_for_domain()
l10n.php:195, translate()
l10n.php:307, __()
Util.php:246, QM_Util::get_file_component()
Backtrace.php:283, QM_Backtrace::get_frame_component()
Backtrace.php:214, QM_Backtrace->get_component()
caps.php:156, QM_Collector_Caps->filter_user_has_cap()
class-wp-hook.php:326, WP_Hook->apply_filters()
plugin.php:205, apply_filters()
class-wp-user.php:815, WP_User->has_cap()
capabilities.php:1018, user_can()
QueryMonitor.php:121, QueryMonitor->filter_user_has_cap()
class-wp-hook.php:324, WP_Hook->apply_filters()
plugin.php:205, apply_filters()
class-wp-user.php:815, WP_User->has_cap()
capabilities.php:1018, user_can()
capabilities.php:911, current_user_can()
doing_it_wrong.php:104, QM_Collector_Doing_It_Wrong->maybe_prevent_doing_it_wrong_error()
class-wp-hook.php:324, WP_Hook->apply_filters()
plugin.php:205, apply_filters()
functions.php:6023, _doing_it_wrong()
l10n.php:1371, _load_textdomain_just_in_time()
l10n.php:1409, get_translations_for_domain()
l10n.php:195, translate()
l10n.php:307, __()
Util.php:200, QM_Util::get_file_component()
Backtrace.php:283, QM_Backtrace::get_frame_component()
Backtrace.php:214, QM_Backtrace->get_component()
caps.php:156, QM_Collector_Caps->filter_user_has_cap()
class-wp-hook.php:326, WP_Hook->apply_filters()
plugin.php:205, apply_filters()
class-wp-user.php:815, WP_User->has_cap()
capabilities.php:1018, user_can()
capabilities.php:911, current_user_can()
Plugin.php:104, DemocracyPoll\Plugin->set_access_caps()
Plugin.php:48, DemocracyPoll\Plugin->basic_init()
Plugin.php:54, DemocracyPoll\Plugin->init()
democracy.php:36, DemocracyPoll\init()
class-wp-hook.php:324, WP_Hook->apply_filters()
class-wp-hook.php:348, WP_Hook->do_action()
plugin.php:517, do_action()
wp-settings.php:578, require_once()
wp-config.php:42, require_once()
wp-load.php:55, require_once()
admin.php:35, require_once()
plugins.php:10, {main}()

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

No branches or pull requests

2 participants