From 12eb3bb119212ee868275ffa5277b5bd7bdf7375 Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 5 Sep 2025 04:22:23 +0530 Subject: [PATCH 1/6] Apply the latest patch --- src/wp-includes/class-wp-object-cache.php | 30 +++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/wp-includes/class-wp-object-cache.php b/src/wp-includes/class-wp-object-cache.php index cda63e66d49ef..5654fb8f55983 100644 --- a/src/wp-includes/class-wp-object-cache.php +++ b/src/wp-includes/class-wp-object-cache.php @@ -313,6 +313,8 @@ public function set( $key, $data, $group = 'default', $expire = 0 ) { if ( is_object( $data ) ) { $data = clone $data; + } elseif ( is_array( $data ) ) { + $data = $this->deep_copy( $data ); } $this->cache[ $group ][ $key ] = $data; @@ -641,4 +643,32 @@ public function stats() { } echo ''; } + + /** + * Performs a deep copy of an item to ensure that arrays of objects + * are properly duplicated + * + * @param mixed $data The data to be duplicated + * @return mixed copy of the data + */ + public function deep_copy( $data ) { + if ( is_object( $data ) ) { + return clone $data; + } elseif ( is_array( $data ) ) { + $new = array(); + foreach ( $data as $key => $value ) { + if ( is_object( $value ) ) { + $new[ $key ] = clone $value; + } elseif ( is_array( $value ) ) { + $new[ $key ] = $this->deep_copy( $value ); + } else { + $new[ $key ] = $value; + } + } + + return $new; + } else { + return $data; + } + } } From e340151aed095eb0907e4321916c06e884c58fc1 Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 5 Sep 2025 04:26:17 +0530 Subject: [PATCH 2/6] Cache: Test array with deep and primitive objects --- tests/phpunit/tests/cache.php | 48 +++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/phpunit/tests/cache.php b/tests/phpunit/tests/cache.php index 1f345652b1fd9..30a165a6ca33a 100644 --- a/tests/phpunit/tests/cache.php +++ b/tests/phpunit/tests/cache.php @@ -250,6 +250,54 @@ public function test_object_refs() { $this->assertSame( 'bravo', $object_a->foo ); } + /** + * + * @ticket 30430 + */ + public function test_array_with_objects_deep_copy() { + if ( wp_using_ext_object_cache() ) { + $this->markTestSkipped( 'This test requires that an external object cache is not in use.' ); + } + + $key = __FUNCTION__; + + $shallow_object = new stdClass(); + $shallow_object->foo = 'alpha'; + + $deep_object = new stdClass(); + $deep_object->value = 'deep_original'; + + $array_with_objects = array( + 'shallow_obj' => $shallow_object, + 'string' => 'gamma', + 'nested' => array( + 'level2' => array( + 'deep_obj' => $deep_object, + 'primitive' => 'unchanged' + ) + ) + ); + + $this->cache->set( $key, $array_with_objects ); + + $shallow_object->foo = 'modified_alpha'; + $deep_object->value = 'deep_modified'; + + $cached_array = $this->cache->get( $key ); + + $this->assertSame( 'alpha', $cached_array['shallow_obj']->foo, 'Shallow cached object should not be affected by changes to original object' ); + $this->assertSame( 'deep_original', $cached_array['nested']['level2']['deep_obj']->value, 'Deep cached object should not be affected by changes to original object' ); + $this->assertSame( 'gamma', $cached_array['string'], 'String values should remain unchanged' ); + $this->assertSame( 'unchanged', $cached_array['nested']['level2']['primitive'], 'Primitive values should remain unchanged' ); + + $cached_array['shallow_obj']->foo = 'modified_from_cache'; + $cached_array['nested']['level2']['deep_obj']->value = 'modified_from_cache'; + + $cached_array_again = $this->cache->get( $key ); + $this->assertSame( 'alpha', $cached_array_again['shallow_obj']->foo, 'Cached data should not be affected by modifications to retrieved objects' ); + $this->assertSame( 'deep_original', $cached_array_again['nested']['level2']['deep_obj']->value, 'Deep cached data should not be affected by modifications to retrieved objects' ); + } + public function test_incr() { $key = __FUNCTION__; From d8bbc294bc3a56f5b16db0461070a651b8d9b58d Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 5 Sep 2025 04:27:47 +0530 Subject: [PATCH 3/6] Cache: Test primitive arrays should be cached correctly --- tests/phpunit/tests/cache.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/phpunit/tests/cache.php b/tests/phpunit/tests/cache.php index 30a165a6ca33a..7d301ec9ee700 100644 --- a/tests/phpunit/tests/cache.php +++ b/tests/phpunit/tests/cache.php @@ -298,6 +298,30 @@ public function test_array_with_objects_deep_copy() { $this->assertSame( 'deep_original', $cached_array_again['nested']['level2']['deep_obj']->value, 'Deep cached data should not be affected by modifications to retrieved objects' ); } + /** + * + * @ticket 30430 + */ + public function test_primitive_arrays_unchanged() { + $key = __FUNCTION__; + + $primitive_array = array( + 'string' => 'test', + 'number' => 123, + 'boolean' => false, + 'nested' => array( + 'nested_string' => 'nested_test', + 'nested_number' => 456 + ) + ); + + $this->cache->set( $key, $primitive_array ); + + $cached_array = $this->cache->get( $key ); + + $this->assertSame( $primitive_array, $cached_array, 'Primitive arrays should be cached correctly' ); + } + public function test_incr() { $key = __FUNCTION__; From 4ca740d4fe42c5975220ec39662bca1da947697d Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 5 Sep 2025 04:28:57 +0530 Subject: [PATCH 4/6] Cache: Fix get() method to deep copy arrays on retrieval --- src/wp-includes/class-wp-object-cache.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wp-includes/class-wp-object-cache.php b/src/wp-includes/class-wp-object-cache.php index 5654fb8f55983..7951d4a79a251 100644 --- a/src/wp-includes/class-wp-object-cache.php +++ b/src/wp-includes/class-wp-object-cache.php @@ -379,6 +379,8 @@ public function get( $key, $group = 'default', $force = false, &$found = null ) $this->cache_hits += 1; if ( is_object( $this->cache[ $group ][ $key ] ) ) { return clone $this->cache[ $group ][ $key ]; + } elseif ( is_array( $this->cache[ $group ][ $key ] ) ) { + return $this->deep_copy( $this->cache[ $group ][ $key ] ); } else { return $this->cache[ $group ][ $key ]; } From 69cf58dc606b9fec32298ede5a84ed49592b4ae2 Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 5 Sep 2025 04:30:13 +0530 Subject: [PATCH 5/6] Tests: Add helper comment --- tests/phpunit/tests/cache.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/phpunit/tests/cache.php b/tests/phpunit/tests/cache.php index 7d301ec9ee700..0cd53bffd6e41 100644 --- a/tests/phpunit/tests/cache.php +++ b/tests/phpunit/tests/cache.php @@ -293,6 +293,7 @@ public function test_array_with_objects_deep_copy() { $cached_array['shallow_obj']->foo = 'modified_from_cache'; $cached_array['nested']['level2']['deep_obj']->value = 'modified_from_cache'; + // Retreiving again should not affect the cached data $cached_array_again = $this->cache->get( $key ); $this->assertSame( 'alpha', $cached_array_again['shallow_obj']->foo, 'Cached data should not be affected by modifications to retrieved objects' ); $this->assertSame( 'deep_original', $cached_array_again['nested']['level2']['deep_obj']->value, 'Deep cached data should not be affected by modifications to retrieved objects' ); From 770030d9317dee65f3ff812f88ba30a913ef929a Mon Sep 17 00:00:00 2001 From: himanshupathak95 Date: Fri, 5 Sep 2025 04:30:57 +0530 Subject: [PATCH 6/6] Fix whitespace linting --- tests/phpunit/tests/cache.php | 40 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/phpunit/tests/cache.php b/tests/phpunit/tests/cache.php index 0cd53bffd6e41..a6c56f7deb682 100644 --- a/tests/phpunit/tests/cache.php +++ b/tests/phpunit/tests/cache.php @@ -251,7 +251,7 @@ public function test_object_refs() { } /** - * + * * @ticket 30430 */ public function test_array_with_objects_deep_copy() { @@ -260,28 +260,28 @@ public function test_array_with_objects_deep_copy() { } $key = __FUNCTION__; - - $shallow_object = new stdClass(); + + $shallow_object = new stdClass(); $shallow_object->foo = 'alpha'; - - $deep_object = new stdClass(); + + $deep_object = new stdClass(); $deep_object->value = 'deep_original'; $array_with_objects = array( 'shallow_obj' => $shallow_object, - 'string' => 'gamma', - 'nested' => array( + 'string' => 'gamma', + 'nested' => array( 'level2' => array( - 'deep_obj' => $deep_object, - 'primitive' => 'unchanged' - ) - ) + 'deep_obj' => $deep_object, + 'primitive' => 'unchanged', + ), + ), ); $this->cache->set( $key, $array_with_objects ); $shallow_object->foo = 'modified_alpha'; - $deep_object->value = 'deep_modified'; + $deep_object->value = 'deep_modified'; $cached_array = $this->cache->get( $key ); @@ -290,7 +290,7 @@ public function test_array_with_objects_deep_copy() { $this->assertSame( 'gamma', $cached_array['string'], 'String values should remain unchanged' ); $this->assertSame( 'unchanged', $cached_array['nested']['level2']['primitive'], 'Primitive values should remain unchanged' ); - $cached_array['shallow_obj']->foo = 'modified_from_cache'; + $cached_array['shallow_obj']->foo = 'modified_from_cache'; $cached_array['nested']['level2']['deep_obj']->value = 'modified_from_cache'; // Retreiving again should not affect the cached data @@ -300,20 +300,20 @@ public function test_array_with_objects_deep_copy() { } /** - * + * * @ticket 30430 */ public function test_primitive_arrays_unchanged() { $key = __FUNCTION__; - + $primitive_array = array( - 'string' => 'test', - 'number' => 123, + 'string' => 'test', + 'number' => 123, 'boolean' => false, - 'nested' => array( + 'nested' => array( 'nested_string' => 'nested_test', - 'nested_number' => 456 - ) + 'nested_number' => 456, + ), ); $this->cache->set( $key, $primitive_array );