fix(concurrency): serialize Win32 clipboard access and test env vars to prevent STATUS_HEAP_CORRUPTION

This commit is contained in:
Riz Ashraf committed 2026-10-07 22:30:36 +01:00
1 parent 35c802c1b8
commit 64857f9d5e
2 files changed
+13 -1

No files matched your search

+5
View File
@@ -9,7 +9,10 @@ use std::borrow::Cow;
use std::sync::Arc; use std::sync::Arc;
static CLIPBOARD_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
pub fn get_native_clipboard_text() -> Option<String> { pub fn get_native_clipboard_text() -> Option<String> {
let _guard = CLIPBOARD_LOCK.lock().unwrap_or_else(|e| e.into_inner());
for _ in 0..3 { for _ in 0..3 {
if let Ok(mut clipboard) = arboard::Clipboard::new() if let Ok(mut clipboard) = arboard::Clipboard::new()
&& let Ok(text) = clipboard.get_text() && let Ok(text) = clipboard.get_text()
@@ -65,6 +68,7 @@ fn get_windows_png_clipboard_image() -> Option<image::DynamicImage> {
None None
} }
pub fn get_native_clipboard_image() -> Option<image::DynamicImage> { pub fn get_native_clipboard_image() -> Option<image::DynamicImage> {
let _guard = CLIPBOARD_LOCK.lock().unwrap_or_else(|e| e.into_inner());
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
if let Some(img) = get_windows_png_clipboard_image() { if let Some(img) = get_windows_png_clipboard_image() {
return Some(img); return Some(img);
@@ -173,6 +177,7 @@ impl McpTool for ClipboardHandler {
let text_opt = req.text; let text_opt = req.text;
let image_path_opt = req.image_path; let image_path_opt = req.image_path;
let res = tokio::task::spawn_blocking(move || { let res = tokio::task::spawn_blocking(move || {
let _guard = CLIPBOARD_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let mut msgs = Vec::new(); let mut msgs = Vec::new();
if let Some(text) = &text_opt { if let Some(text) = &text_opt {
+8 -1
View File
@@ -332,7 +332,10 @@ pub async fn run_server(state: Arc<MemoryState>) -> Result<(), Box<dyn std::erro
} }
let (tech_debts, adrs) = if let Some(ref f) = payload.file { let (tech_debts, adrs) = if let Some(ref f) = payload.file {
crate::api::telemetry::find_projected_knowledge(&nvim_udp_state.handler.state, f) crate::api::telemetry::find_projected_knowledge(
&nvim_udp_state.handler.state,
f,
)
} else { } else {
(Vec::new(), Vec::new()) (Vec::new(), Vec::new())
}; };
@@ -678,8 +681,11 @@ mod tests {
} }
} }
static ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
#[test] #[test]
fn test_init_logging_helper() { fn test_init_logging_helper() {
let _lock = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let temp_dir = tempfile::tempdir().unwrap(); let temp_dir = tempfile::tempdir().unwrap();
unsafe { unsafe {
std::env::set_var("MCP_MEMORY_STORE_DIR", temp_dir.path().to_str().unwrap()); std::env::set_var("MCP_MEMORY_STORE_DIR", temp_dir.path().to_str().unwrap());
@@ -711,6 +717,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn test_run_server_graceful_shutdown() { async fn test_run_server_graceful_shutdown() {
let _lock = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let temp_dir = tempfile::tempdir().unwrap(); let temp_dir = tempfile::tempdir().unwrap();
let state = Arc::new(MemoryState::new(temp_dir.path().to_str().unwrap())); let state = Arc::new(MemoryState::new(temp_dir.path().to_str().unwrap()));