Problem/Motivation
SchemaCache is prone to persistent cache corruption.
protected function resolveCacheMiss($offset) {
$complete_schema = drupal_get_complete_schema();
$value = isset($complete_schema[$offset]) ? $complete_schema[$offset] : NULL;
$this->storage[$offset] = $value;
$this->persist($offset);
return $value;
}
If drupal_get_complete_schema() returns NULL (which is a valid case thats handled in that function) then the bad values are persisted.
This can be reproduced by calling e.g. entity_get_info('node') before DRUPAL_BOOTSTRAP_FULL and e.g. a corrupted module implements cache can lead to that. (see also
🐛
module_implements() cache can be polluted by module_invoke_all() being called (in)directly prior to full bootstrap completion
RTBC
)
Proposed resolution
Lets harden this for the most obvious corruption:
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index 0b81dc0..e843997 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -2972,17 +2972,34 @@ class SchemaCache extends DrupalCacheArray {
}
/**
+ * Whether the cache should be persisted.
+ */
+ protected $persistable;
+
+ /**
* Overrides DrupalCacheArray::resolveCacheMiss().
*/
protected function resolveCacheMiss($offset) {
$complete_schema = drupal_get_complete_schema();
$value = isset($complete_schema[$offset]) ? $complete_schema[$offset] : NULL;
- $this->storage[$offset] = $value;
- $this->persist($offset);
+ if ($this->persistable() && !empty($complete_schema)) {
+ $this->storage[$offset] = $value;
+ $this->persist($offset);
+ }
return $value;
}
}
+ /**
+ * Whether the cache should be persisted.
+ */
+ function persistable() {
+ // Try until we have reached full bootstrap level.
+ if (empty($this->persistable)) {
+ $this->persistable = drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL;
+ }
+ return $this->persistable;
+ }
+
/**
* Gets the whole database schema.
*
Note: Do not apply this patch to a site lower than Drupal 7.33, because there drupal_get_bootstrap_phase() was just fixed.
Remaining tasks
<!-- See https://drupal.org/core-mentoring/novice-tasks for tips on identifying novice tasks. Delete or add "Novice" from the Novice? column in the table below as appropriate. Uncomment tasks as the issue advances. Update the Complete? column to indicate when they are done, and maybe reference the comment number where they were done. -->
User interface changes
API changes