At least major, potentially critical.

Citing @catch in #2451679-51: Validate cache contexts (+ cache contexts in some views plugins wrong):

+++ b/core/lib/Drupal/Core/Cache/CacheContexts.php
@@ -221,4 +221,54 @@ public static function parseTokens(array $context_tokens) {
+        throw new \LogicException('"' . $context_id . '" is not a valid cache context ID.');

Slightly concerned about the following scenario:

1. Enable a module that provides a cache context
2. Some stuff gets cached using that cache context
3. The module is uninstalled
4. The stuff is still cached and this condition gets hit when it's returned from cache.

We're moving towards selectively clearing caches when modules are uninstalled, so this feels not impossible to hit as a condition.

Is this worth thinking about more? If it's worth thinking about, I'd suggest making the exception a trigger_error() call instead, then opening a follow-up to make it an exception. That situation is something a real site could very possibly run into, and a developer probably wouldn't.

Comments

wim leers’s picture

Title: Uninstalling modules containing cache contexts may break Drupal if they are cached somewhere » Uninstalling modules containing cache contexts or #post_render_cache callbacks may break Drupal if they are cached somewhere

From #2451679-54: Validate cache contexts (+ cache contexts in some views plugins wrong):

Now that I think about it, there's another reason that not clearing the render cache after uninstalling a module is problematic: render cache items may include #post_render_cache callbacks… which may live in uninstalled modules.

catch’s picture

Priority: Major » Critical

Bumping to critical for now, we can always bump it down later but this feels like unrecoverable site-breakage if it happens (at least not without drush).

wim leers’s picture

Status: Active » Needs review
Issue tags: +Needs tests
StatusFileSize
new992 bytes

Simplest patch possible.

catch’s picture

There's also the possibility that a module code update renames or removes one of these as well as uninstall. Suggested trigger_error() in the other issue - we may need to make this a non-fatal.

wim leers’s picture

module code update

But we cannot possibly detect that? So… renames basically mean all you can do is write an update hook…?

catch’s picture

Yes we can't detect that, that's why I suggested non-fatal.

So:

1. Validation - trigger_error() instead of throwing an exception.
2. Before calling the service check if it exists, if it doesn't, trigger_error() and treat the cache item as invalid.

Something like this.

fabianx’s picture

I like #6 and using trigger_error, once we have an assertion and not do the check at run-time at all, this will be a similar "fault".

berdir’s picture

Note that uninstalling modules explicitly clears all caches I don't think you will be able to write tests for that scenario, it shouldn't happen.

Yes, where it could happen is when modules are updated/changed, but then you're supposed to run a cache clear/update.php anyway, anything could be broken then.

Not sure this is critical, I'd say demote unless we have a test case that it can happen on an easy to reproduce scenario?

wim leers’s picture

Note that uninstalling modules explicitly clears all caches I don't think you will be able to write tests for that scenario, it shouldn't happen.

Are you sure? Unless I made a mistake, that's not actually true!

berdir’s picture

Pretty sure :)

#2359369: Render cache is not cleared when module is uninstalled

    // Flush all persistent caches.
    // Any cache entry might implicitly depend on the uninstalled modules,
    // so clear all of them explicitly.
    $this->moduleHandler->invokeAll('cache_flush');
    foreach (Cache::getBins() as $service_id => $cache_backend) {
      $cache_backend->deleteAll();
    }

at the end of uninstall().

mpdonadio’s picture

ModuleInstaller::uninstall() has this at the end

    // Flush all persistent caches.
    // Any cache entry might implicitly depend on the uninstalled modules,
    // so clear all of them explicitly.
    $this->moduleHandler->invokeAll('cache_flush');
    foreach (Cache::getBins() as $service_id => $cache_backend) {
      $cache_backend->deleteAll();
    }

I think #2359369: Render cache is not cleared when module is uninstalled restored this.

wim leers’s picture

#11: that links to this issue :)

berdir’s picture

Haha, that code is broken :) But the same exists in drupal_flush_all_caches(), so that is broken too?
This should use Cache::getBins().

I'm stupid, that should work fine. Being able to read code would be a huge advantage.

mpdonadio’s picture

#12: Bad copy paste searching for that issue. Also edited it before I saw your comment. Gotta love multiple cross posts...

larowlan’s picture

So it this an issue or not? Seems to be consensus that uninstall == cache clear == problem solved?

wim leers’s picture

Status: Needs review » Closed (fixed)
Issue tags: -Needs tests

So it this an issue or not? Seems to be consensus that uninstall == cache clear == problem solved?

AFAICT: indeed, this is not a problem. The code cited in #11 does ensure the render cache (and all other caches) are cleared.

Regarding the rename problem that catch pointed at in #4 (i.e. what if a module renames a cache context?), that's already taken care of by #2451679: Validate cache contexts (+ cache contexts in some views plugins wrong).

Which means that no problems remain!

(This is one of those rare times that we can close a critical within a week, without a patch :))

wim leers’s picture

Also, I still remember testing this and indeed not seeing the cache_render DB table being emptied. I really wonder what I did wrong back then, because clearly, that does happen. PEBKAC, of course.