[fix] fix crash when switching monitors due to race condition and missing bounds checks in screen capturer

This commit is contained in:
dijunkun
2026-06-26 14:44:30 +08:00
parent 3c4000bdbb
commit 9c28cd2ab2
4 changed files with 22 additions and 4 deletions
@@ -111,6 +111,7 @@ int ScreenCapturerDxgi::Resume(int monitor_index) {
} }
int ScreenCapturerDxgi::SwitchTo(int monitor_index) { int ScreenCapturerDxgi::SwitchTo(int monitor_index) {
std::lock_guard<std::mutex> lock(switch_mutex_);
if (monitor_index < 0 || monitor_index >= (int)display_info_list_.size()) { if (monitor_index < 0 || monitor_index >= (int)display_info_list_.size()) {
LOG_ERROR("DXGI: invalid monitor index {}", monitor_index); LOG_ERROR("DXGI: invalid monitor index {}", monitor_index);
return -1; return -1;
@@ -121,6 +122,7 @@ int ScreenCapturerDxgi::SwitchTo(int monitor_index) {
if (!CreateDuplicationForMonitor(monitor_index_)) { if (!CreateDuplicationForMonitor(monitor_index_)) {
LOG_ERROR("DXGI: create duplication failed for monitor {}", LOG_ERROR("DXGI: create duplication failed for monitor {}",
monitor_index_.load()); monitor_index_.load());
paused_ = false; // Reset paused_ on failure
return -2; return -2;
} }
paused_ = false; paused_ = false;
@@ -130,6 +132,7 @@ int ScreenCapturerDxgi::SwitchTo(int monitor_index) {
} }
int ScreenCapturerDxgi::ResetToInitialMonitor() { int ScreenCapturerDxgi::ResetToInitialMonitor() {
std::lock_guard<std::mutex> lock(switch_mutex_);
if (display_info_list_.empty()) return -1; if (display_info_list_.empty()) return -1;
int target = initial_monitor_index_; int target = initial_monitor_index_;
if (target < 0 || target >= (int)display_info_list_.size()) return -1; if (target < 0 || target >= (int)display_info_list_.size()) return -1;
@@ -245,6 +248,7 @@ bool ScreenCapturerDxgi::CreateDuplicationForMonitor(int monitor_index) {
} }
bool ScreenCapturerDxgi::RecreateDuplicationForCurrentMonitor() { bool ScreenCapturerDxgi::RecreateDuplicationForCurrentMonitor() {
std::lock_guard<std::mutex> lock(switch_mutex_);
ReleaseDuplication(); ReleaseDuplication();
int current_monitor = monitor_index_.load(); int current_monitor = monitor_index_.load();
if (CreateDuplicationForMonitor(current_monitor)) { if (CreateDuplicationForMonitor(current_monitor)) {
@@ -374,8 +378,14 @@ void ScreenCapturerDxgi::CaptureLoop() {
even_width, even_width, even_height); even_width, even_width, even_height);
if (callback_) { if (callback_) {
int idx = monitor_index_.load();
if (idx >= 0 && idx < static_cast<int>(display_info_list_.size())) {
callback_(nv12_frame_, nv12_size, even_width, even_height, callback_(nv12_frame_, nv12_size, even_width, even_height,
display_info_list_[monitor_index_].name.c_str()); 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); d3d_context_->Unmap(staging_.Get(), 0);
@@ -72,6 +72,7 @@ class ScreenCapturerDxgi : public ScreenCapturer {
std::thread thread_; std::thread thread_;
int fps_ = 60; int fps_ = 60;
cb_desktop_data callback_ = nullptr; cb_desktop_data callback_ = nullptr;
std::mutex switch_mutex_;
unsigned char* nv12_frame_ = nullptr; unsigned char* nv12_frame_ = nullptr;
int nv12_width_ = 0; int nv12_width_ = 0;
@@ -148,7 +148,14 @@ void ScreenCapturerGdi::CaptureLoop() {
continue; continue;
} }
const auto& di = display_info_list_[monitor_index_]; int idx = monitor_index_.load();
if (idx < 0 || idx >= static_cast<int>(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 left = di.left;
int top = di.top; int top = di.top;
int width = di.width & ~1; int width = di.width & ~1;
@@ -306,7 +306,7 @@ int ScreenCapturerWgc::SwitchTo(int monitor_index) {
return 0; return 0;
} }
if (monitor_index >= display_info_list_.size()) { if (monitor_index < 0 || monitor_index >= static_cast<int>(display_info_list_.size())) {
LOG_ERROR("Invalid monitor index: {}", monitor_index); LOG_ERROR("Invalid monitor index: {}", monitor_index);
return -1; return -1;
} }