This is a well known (long standing) issue. Documented in the code base in commit eea02be70ee37b845f2719b3c08e5baf4b6f51f6.

Countless intermittent sanitizer warnings can be attributed to it.
* @param[in]   pfrom           The node which we have received messages from.
    * @param[in]   interrupt       Interrupt condition for processing threads
    */
    bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override;
    /**
    * Send queued protocol messages to be sent to a give node.
    *
    * @param[in]   pto             The node which we are sending messages to.
    * @return                      True if there is more work to be done
    */
    bool SendMessages(CNode* pto) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing);
    
    void ConsiderEviction(CNode *pto, int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
    
    void CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams);
    
    void EvictExtraOutboundPeers(int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
private:
    int64_t m_stale_tip_check_time; 
};
struct CNodeStateStats {
    int nMisbehavior = 0;
    int nSyncHeight = -1;
    int nCommonHeight = -1;
    std::vector<int> vHeightInFlight;
};
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
void RelayTransaction(const uint256&, const CConnman& connman);
#endif