`RewindBlockIndex` reads `chainActive` (via `ChainActive()`) without holding `cs_main`:

https://github.com/bitcoin/bitcoin/blob/b2a6b0216192b6e8428f1a80b47f5178fccb961a/src/validation.cpp#L4314-L4331

(Please note that callers of `RewindBlockIndex` are _not_ allowed to hold `cs_main` since `RewindBlockIndex` indirectly calls `LimitValidationInterfaceQueue`.)
* In any case D3 will also be marked as BLOCK_FAILED_CHILD at restart
         * in LoadBlockIndex.
         */
        if (!pindexPrev->IsValid(BLOCK_VALID_SCRIPTS)) {
            
            
            
            
            for (const CBlockIndex* failedit : m_failed_blocks) {
                if (pindexPrev->GetAncestor(failedit->nHeight) == failedit) {
                    assert(failedit->nStatus & BLOCK_FAILED_VALID);
                    CBlockIndex* invalid_walk = pindexPrev;
                    while (invalid_walk != failedit) {
                        invalid_walk->nStatus |= BLOCK_FAILED_CHILD;
                        setDirtyBlockIndex.insert(invalid_walk);
                        invalid_walk = invalid_walk->pprev;
                    }
                    return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
                }
            }
        }
    }
    if (pindex == nullptr)
        pindex = AddToBlockIndex(block);
    if (ppindex)
        *ppindex = pindex;
    CheckBlockIndex(chainparams.GetConsensus());
    return true;
}
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex, CBlockHeader *first_invalid)