diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php index d53c51c2fc..5b90c32660 100644 --- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php +++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php @@ -135,7 +135,16 @@ protected function prepareItem($cache, $allow_invalid) { // Unserialize and return the cached data. if ($cache->serialized) { - $cache->data = unserialize($cache->data); + $unserialized = @unserialize($cache->data); + // Make sure that corrupt items are properly identified and treated as + // cache misses. Otherwise, broken items will be treated as cache hits, + // and return a FALSE as the cached data. + if ($unserialized === FALSE) { + if ($cache->data != serialize(FALSE)) { + return FALSE; + } + } + $cache->data = $unserialized; } return $cache; diff --git a/core/tests/Drupal/KernelTests/Core/Cache/DatabaseBackendTest.php b/core/tests/Drupal/KernelTests/Core/Cache/DatabaseBackendTest.php index de8bbda553..0a5ee7e564 100644 --- a/core/tests/Drupal/KernelTests/Core/Cache/DatabaseBackendTest.php +++ b/core/tests/Drupal/KernelTests/Core/Cache/DatabaseBackendTest.php @@ -2,6 +2,7 @@ namespace Drupal\KernelTests\Core\Cache; +use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Cache\DatabaseBackend; /** @@ -48,4 +49,30 @@ public function testSetGet() { $this->assertIdentical($cached_value_short, $backend->get($cid_short)->data, "Backend contains the correct value for short, non-ASCII cache id."); } + /** + * Tests getting a FALSE when requesting a corrupt cache item. + */ + public function testCorruptCacheReturnsFalse() { + $corrupt_backend = $this->getCacheBackend('corrupt'); + // Gets the CacheTagsChecksum tag validator. + $cache_tags_checksum = $this->container->get('cache_tags.invalidator.checksum'); + + // All DatabaseBackend cache tables should be prefixed with 'cache_'. As + // specified on \Drupal\Core\Cache\DatabaseBackend::__construct. + $cid = $this->randomMachineName(); + + // We insert a corrupted cache item into the cache table. + db_insert('cache_corrupt')->fields([ + 'cid' => $cid, + 'created' => round(microtime(TRUE), 3), + 'data' => substr(serialize($this->randomObject()), 0, -5), + 'expire' => CacheBackendInterface::CACHE_PERMANENT, + 'tags' => implode(' ', []), + 'serialized' => 1, + 'checksum' => $cache_tags_checksum->getCurrentChecksum([]), + ])->execute(); + + $this->assertFalse($corrupt_backend->get($cid), "Returns a FALSE when requesting the corrupt object."); + } + }