Issue #2293163 by Wim Leers, pwolanin: Fixed MemoryBackend's cache entries may be modified unintentionally thanks to object references.

8.0.x
Nathaniel Catchpole 2014-07-01 10:56:37 +01:00
parent 4ab1724827
commit 6383bb2aa6
2 changed files with 33 additions and 4 deletions

View File

@ -73,6 +73,9 @@ class MemoryBackend implements CacheBackendInterface {
*
* @param object $cache
* An item loaded from cache_get() or cache_get_multiple().
* @param bool $allow_invalid
* (optional) If TRUE, cache items may be returned even if they have expired
* or been invalidated.
*
* @return mixed
* The item with data as appropriate or FALSE if there is no
@ -82,15 +85,22 @@ class MemoryBackend implements CacheBackendInterface {
if (!isset($cache->data)) {
return FALSE;
}
// The object passed into this function is the one stored in $this->cache.
// We must clone it as part of the preparation step so that the actual
// cache object is not affected by the unserialize() call or other
// manipulations of the returned object.
$prepared = clone $cache;
$prepared->data = unserialize($prepared->data);
// Check expire time.
$cache->valid = $cache->expire == Cache::PERMANENT || $cache->expire >= REQUEST_TIME;
$prepared->valid = $prepared->expire == Cache::PERMANENT || $prepared->expire >= REQUEST_TIME;
if (!$allow_invalid && !$cache->valid) {
if (!$allow_invalid && !$prepared->valid) {
return FALSE;
}
return $cache;
return $prepared;
}
/**
@ -99,7 +109,7 @@ class MemoryBackend implements CacheBackendInterface {
public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = array()) {
$this->cache[$cid] = (object) array(
'cid' => $cid,
'data' => $data,
'data' => serialize($data),
'created' => REQUEST_TIME,
'expire' => $expire,
'tags' => $this->flattenTags($tags),

View File

@ -188,6 +188,25 @@ abstract class GenericCacheBackendUnitTestBase extends DrupalUnitTestBase {
$cached = $backend->get('test6');
$this->assert(is_object($cached), "Backend returned an object for cache id test6.");
$this->assertIdentical($with_variable, $cached->data);
// Make sure that a cached object is not affected by changing the original.
$data = new \stdClass();
$data->value = 1;
$data->obj = new \stdClass();
$data->obj->value = 2;
$backend->set('test7', $data);
$expected_data = clone $data;
// Add a property to the original. It should not appear in the cached data.
$data->this_should_not_be_in_the_cache = TRUE;
$cached = $backend->get('test7');
$this->assert(is_object($cached), "Backend returned an object for cache id test7.");
$this->assertEqual($expected_data, $cached->data);
$this->assertFalse(isset($cached->data->this_should_not_be_in_the_cache));
// Add a property to the cache data. It should not appear when we fetch
// the data from cache again.
$cached->data->this_should_not_be_in_the_cache = TRUE;
$fresh_cached = $backend->get('test7');
$this->assertFalse(isset($fresh_cached->data->this_should_not_be_in_the_cache));
}
/**