From 9c28cd2ab237154efa9955c3dfd04af7e72b7bf2 Mon Sep 17 00:00:00 2001 From: dijunkun Date: Fri, 26 Jun 2026 14:44:30 +0800 Subject: [PATCH] [fix] fix crash when switching monitors due to race condition and missing bounds checks in screen capturer --- .../windows/screen_capturer_dxgi.cpp | 14 ++++++++++++-- src/screen_capturer/windows/screen_capturer_dxgi.h | 1 + .../windows/screen_capturer_gdi.cpp | 9 ++++++++- .../windows/screen_capturer_wgc.cpp | 2 +- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/screen_capturer/windows/screen_capturer_dxgi.cpp b/src/screen_capturer/windows/screen_capturer_dxgi.cpp index e55e118..479727f 100644 --- a/src/screen_capturer/windows/screen_capturer_dxgi.cpp +++ b/src/screen_capturer/windows/screen_capturer_dxgi.cpp @@ -111,6 +111,7 @@ int ScreenCapturerDxgi::Resume(int monitor_index) { } int ScreenCapturerDxgi::SwitchTo(int monitor_index) { + std::lock_guard lock(switch_mutex_); if (monitor_index < 0 || monitor_index >= (int)display_info_list_.size()) { LOG_ERROR("DXGI: invalid monitor index {}", monitor_index); return -1; @@ -121,6 +122,7 @@ int ScreenCapturerDxgi::SwitchTo(int monitor_index) { if (!CreateDuplicationForMonitor(monitor_index_)) { LOG_ERROR("DXGI: create duplication failed for monitor {}", monitor_index_.load()); + paused_ = false; // Reset paused_ on failure return -2; } paused_ = false; @@ -130,6 +132,7 @@ int ScreenCapturerDxgi::SwitchTo(int monitor_index) { } int ScreenCapturerDxgi::ResetToInitialMonitor() { + std::lock_guard lock(switch_mutex_); if (display_info_list_.empty()) return -1; int target = initial_monitor_index_; if (target < 0 || target >= (int)display_info_list_.size()) return -1; @@ -245,6 +248,7 @@ bool ScreenCapturerDxgi::CreateDuplicationForMonitor(int monitor_index) { } bool ScreenCapturerDxgi::RecreateDuplicationForCurrentMonitor() { + std::lock_guard lock(switch_mutex_); ReleaseDuplication(); int current_monitor = monitor_index_.load(); if (CreateDuplicationForMonitor(current_monitor)) { @@ -374,8 +378,14 @@ void ScreenCapturerDxgi::CaptureLoop() { even_width, even_width, even_height); if (callback_) { - callback_(nv12_frame_, nv12_size, even_width, even_height, - display_info_list_[monitor_index_].name.c_str()); + int idx = monitor_index_.load(); + if (idx >= 0 && idx < static_cast(display_info_list_.size())) { + callback_(nv12_frame_, nv12_size, even_width, even_height, + display_info_list_[idx].name.c_str()); + } else { + LOG_ERROR("DXGI: CaptureLoop invalid monitor_index {} (list size {})", + idx, display_info_list_.size()); + } } d3d_context_->Unmap(staging_.Get(), 0); diff --git a/src/screen_capturer/windows/screen_capturer_dxgi.h b/src/screen_capturer/windows/screen_capturer_dxgi.h index 5c4db83..6db23c1 100644 --- a/src/screen_capturer/windows/screen_capturer_dxgi.h +++ b/src/screen_capturer/windows/screen_capturer_dxgi.h @@ -72,6 +72,7 @@ class ScreenCapturerDxgi : public ScreenCapturer { std::thread thread_; int fps_ = 60; cb_desktop_data callback_ = nullptr; + std::mutex switch_mutex_; unsigned char* nv12_frame_ = nullptr; int nv12_width_ = 0; diff --git a/src/screen_capturer/windows/screen_capturer_gdi.cpp b/src/screen_capturer/windows/screen_capturer_gdi.cpp index 7ee0b4e..aa13499 100644 --- a/src/screen_capturer/windows/screen_capturer_gdi.cpp +++ b/src/screen_capturer/windows/screen_capturer_gdi.cpp @@ -148,7 +148,14 @@ void ScreenCapturerGdi::CaptureLoop() { continue; } - const auto& di = display_info_list_[monitor_index_]; + int idx = monitor_index_.load(); + if (idx < 0 || idx >= static_cast(display_info_list_.size())) { + LOG_ERROR("GDI: CaptureLoop invalid monitor_index {} (list size {})", + idx, display_info_list_.size()); + std::this_thread::sleep_for(std::chrono::milliseconds(interval_ms)); + continue; + } + const auto& di = display_info_list_[idx]; int left = di.left; int top = di.top; int width = di.width & ~1; diff --git a/src/screen_capturer/windows/screen_capturer_wgc.cpp b/src/screen_capturer/windows/screen_capturer_wgc.cpp index d8634cc..dda1d28 100644 --- a/src/screen_capturer/windows/screen_capturer_wgc.cpp +++ b/src/screen_capturer/windows/screen_capturer_wgc.cpp @@ -306,7 +306,7 @@ int ScreenCapturerWgc::SwitchTo(int monitor_index) { return 0; } - if (monitor_index >= display_info_list_.size()) { + if (monitor_index < 0 || monitor_index >= static_cast(display_info_list_.size())) { LOG_ERROR("Invalid monitor index: {}", monitor_index); return -1; }