From 925d93c71731da28bff681599004a58785be90a4 Mon Sep 17 00:00:00 2001 From: Filip Ilic Date: Wed, 11 Mar 2026 09:35:10 +0100 Subject: [PATCH] Fix infinite recursion in option access monitoring Add a recursion guard ($is_processing flag) to both monitor_option_accesses_pre_option and monitor_option_accesses_legacy to prevent re-entrant calls from causing a stack overflow. Co-Authored-By: Claude Opus 4.6 --- src/class-plugin.php | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/class-plugin.php b/src/class-plugin.php index 0caf091..7213d73 100644 --- a/src/class-plugin.php +++ b/src/class-plugin.php @@ -25,6 +25,14 @@ class Plugin { */ protected $accessed_options = []; + /** + * Whether the plugin is currently processing an option access. + * Used to prevent infinite recursion. + * + * @var bool + */ + protected $is_processing = false; + /** * Whether the plugin should reset the option_optimizer data. * @@ -101,10 +109,16 @@ public function reset( $should_reset = true ) { * @return void */ public function monitor_option_accesses_legacy( $tag ) { + if ( $this->is_processing ) { + return; + } + // Check if the tag is related to an option access. if ( str_starts_with( $tag, 'option_' ) || str_starts_with( $tag, 'default_option_' ) ) { - $option_name = preg_replace( '#^(default_)?option_#', '', $tag ); + $this->is_processing = true; + $option_name = preg_replace( '#^(default_)?option_#', '', $tag ); $this->add_option_usage( $option_name ); + $this->is_processing = false; } } @@ -117,10 +131,15 @@ public function monitor_option_accesses_legacy( $tag ) { * @return mixed */ public function monitor_option_accesses_pre_option( $pre, $option_name ) { + if ( $this->is_processing ) { + return $pre; + } // If the $pre is false the get_option() will not be short-circuited. if ( ! defined( 'WP_SETUP_CONFIG' ) && false === $pre ) { + $this->is_processing = true; $this->add_option_usage( $option_name ); + $this->is_processing = false; } return $pre;