The RequiresIndexStage is responsible for causing query execution to terminate on yield recovery if an index being used by the query has been dropped. This is implemented by keeping a weak_ptr to the relevant IndexCatalogEntry, and attempting to lock the weak_ptr on yield recovery.
Currently, RequiresIndexStage holds a shared_ptr to the IndexCatalogEntry when the stage is active, relinquishing its refcount on either destruction or saveState(). This subtly requires users of a PlanExecutor to either delete the PlanExecutor or save it prior to releasing locks. Should this invariant be violated, an index drop could proceed while queries still hold reference counts to the index. The consequence is that an index drop can complete without fully cleaning up the index catalog state, since the outstanding refcount to the IndexCatalogEntry prevents it from being destroyed.
DocumentSourceCursor::loadBatch() indeed violates this invariant, as its AutoGetCollectionForRead can go out of scope without us either deleting the PlanExecutor or saving it.
The easiest fix for this problem would be to change RequiresIndexStage so that it accesses the IndexCatalogEntry by raw pointer rather than shared_ptr. This will prevent it from holding reference counts for too long. Access to the raw pointer should always be valid, as they are protected by lock manager locks.