Search code examples
c++webrtcdeque

WebRTC std::deque iterator exception when RTC_DCHECK_IS_ON


Recently, since M83 and M84 releases of lib-WebRTC, I face a strange error when I run my host program in Windows x64 Debug configuration (RTC_DCHECK_IS_ON) on Visual Studio :

When a video channel is creating in WebRTC library I get an exception on

_Deque_const_iterator& operator++() {
        #if _ITERATOR_DEBUG_LEVEL != 0
            const auto _Mycont = static_cast<const _Mydeque*>(this->_Getcont());
            _STL_VERIFY(_Mycont, "cannot increment value-initialized deque iterator");
here---->   _STL_VERIFY(this->_Myoff < _Mycont->_Myoff + _Mycont->_Mysize, "cannot increment deque iterator past end");**
        #endif // _ITERATOR_DEBUG_LEVEL != 0

        ++_Myoff;
        return *this;
}

Because _Myoff is NULL ...

This ++operator is called from rtc_base/thread.cc in WebRTC library here :

void ThreadManager::RegisterSendAndCheckForCycles(Thread* source,
                                              Thread* target) {
    CritScope cs(&crit_);
    std::deque<Thread*> all_targets({target});
        // We check the pre-existing who-sends-to-who graph for any path from target
        // to source. This loop is guaranteed to terminate because per the send graph
        // invariant, there are no cycles in the graph.
    for (auto it = all_targets.begin(); it != all_targets.end(); ++it) {
        const auto& targets = send_graph_[*it];
        all_targets.insert(all_targets.end(), targets.begin(), targets.end());
    }

    ... 

It comes from the ++it from a std::deque< rtc::Thread* >

I don't really see what might be the problem, but it seems that the iterator has an issue.

Visual Studio debug

Perhaps I have a kind of mismatch of configurations between the compiled webrtc.lib and my project but there wasn't any problem with WebRTC M79 or M81 for exemple. And, as WebRTC is really a huge project, I don't know where to start my investigations.

Any idea ?

Please note that I also reported this bug to WebRTC team : https://bugs.chromium.org/p/webrtc/issues/detail?id=11746


Solution

  • The problem is from the function RegisterSendAndCheckForCycles of rtc_base/thread.cc file

    for (auto it = all_targets.begin(); it != all_targets.end(); ++it) {
        const auto& targets = send_graph_[*it];
        all_targets.insert(all_targets.end(), targets.begin(), targets.end());
    }
    

    When all_targets.insert is called, the "it" gets invalid because the memory allocation changed in all_targets, so the next ++it generate an assertion failure. Working with indexes solves the problem

    Here's the fixed version:

    void ThreadManager::RegisterSendAndCheckForCycles(Thread* source,Thread* target) {
    
        CritScope cs(&crit_);
        std::deque<Thread*> all_targets({target});
        // We check the pre-existing who-sends-to-who graph for any path from target
        // to source. This loop is guaranteed to terminate because per the send graph
        // invariant, there are no cycles in the graph.
        for (size_t i = 0; i < all_targets.size(); i++) {
            const auto& targets = send_graph_[all_targets[i]];
            all_targets.insert(all_targets.end(), targets.begin(), targets.end());
        }
    
        RTC_CHECK_EQ(absl::c_count(all_targets, source), 0)
            << " send loop between " << source->name() << " and " << target->name();
    
        // We may now insert source -> target without creating a cycle, since there
        // was no path from target to source per the prior CHECK.
        send_graph_[source].insert(target);
    }
    

    I will propose a patch directly to WebRTC team in a few days