RTC_DCHECK_IS_ON 时 WebRTC std::deque 迭代器异常

WebRTC std::deque iterator exception when RTC_DCHECK_IS_ON

最近,自从 lib-WebRTC 的 M83 和 M84 版本发布以来,当我在 Windows x64 调试配置 (RTC_DCHECK_IS_ON) 中 运行 我的主机程序时,我遇到了一个奇怪的错误 Visual Studio :

当在 WebRTC 库中创建视频频道时,出现异常

_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;
}

因为 _Myoff 为 NULL ...

此 ++ 运算符是从 WebRTC 库中的 rtc_base/thread.cc 调用的:

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());
    }

    ... 

它来自 std::deque< rtc::Thread* >

的 ++it

我不太明白可能是什么问题,但迭代器似乎有问题。

也许我在编译的 webrtc.lib 和我的项目之间存在某种配置不匹配,但例如 WebRTC M79 或 M81 没有任何问题。 而且,由于 WebRTC 确实是一个巨大的项目,我不知道从哪里开始调查。

有什么想法吗?

请注意,我也向 WebRTC 团队报告了这个错误:https://bugs.chromium.org/p/webrtc/issues/detail?id=11746

问题出在 rtc_base/thread.cc 文件的 RegisterSendAndCheckForCycles 函数

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());
}

当 all_targets.insert 被调用时,“it”变得无效,因为内存分配在 all_targets 中发生了变化,所以下一个 ++it 会产生一个断言失败。使用索引解决问题

这是固定版本:

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);
}

我会在几天内直接向 WebRTC 团队提出补丁

这基本上是已接受答案的延续...

如果您遵循 Microsoft 的教程 (https://docs.microsoft.com/en-us/winrtc/getting-started),他们会让您使用 M84 版本(截至 2022 年 5 月发布)。然后,他们告诉您应用他们放在一起的一堆 git 补丁。对于 运行 那些,他们让您首先定义一个名为 WEBRTCM84_ROOT 的环境变量,它是 webrtc\src 目录的绝对路径。如果您没有做所有这些,只需在命令提示符 window 中执行此操作(填写您的实际路径):

set WEBRTCM84_ROOT=C:\abs\path\to\webrtc\src

现在,在某处创建一个git补丁文件,包含以下内容。我只是假设你把它放在直接 adjacent 到 webrtc 存储库的路径上。

ThreadManager.patch

diff --git a/rtc_base/thread.cc b/rtc_base/thread.cc
index 0fb2e813e0..a8cb022fa9 100644
--- a/rtc_base/thread.cc
+++ b/rtc_base/thread.cc
@@ -168,8 +168,8 @@ void ThreadManager::RegisterSendAndCheckForCycles(Thread* source,
   // 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];
+  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)

然后,像这样应用它:

pushd "%WEBRTCM84_ROOT%"
git apply "..\..\ThreadManager.patch"
git commit -a -m "Applied ThreadManager patch."
popd

Note: I'm still experiencing some other bad behaviors in debug mode, that aren't present in release, but SamT's solution got me beyond this particular issue.