使用Rust调用Win32 EnumProcesses时向量未更新引发越界问题
问题原因
你遇到的核心问题是Rust的Vec与Win32 API的内存模型不兼容:
- EnumProcesses需要预先分配一块可写入的内存缓冲区来存储进程ID,但如果你初始化的
a_processes是空Vec,它的内存空间为0,函数无法写入任何数据,只会通过cb_needed返回所需的总字节数。 - Win32 API直接操作底层内存,不会自动更新Rust
Vec的len字段——哪怕函数成功写入了数据,Vec的长度仍会保持初始值(0),后续访问自然触发索引越界。
解决方法
1. 预先分配足够的缓冲区
先创建一个拥有足够内存空间的Vec作为缓冲区,避免因空间不足导致无法写入进程ID。
2. 手动更新Vec的有效长度
调用成功后,通过cb_needed计算实际写入的进程ID数量,手动截断Vec到有效长度,确保后续访问不会越界。
示例代码
use windows::Win32::System::ProcessStatus::{EnumProcesses, GetLastError}; use windows::Win32::Foundation::DWORD; fn main() { // 预先分配可容纳1024个进程ID的缓冲区(每个DWORD占4字节,共4096字节) let mut a_processes = vec![0u32; 1024]; let mut cb_needed = 0; // 调用EnumProcesses,注意unsafe块(直接操作内存的Win32 API需要unsafe) let result = unsafe { EnumProcesses( a_processes.as_mut_ptr(), (a_processes.len() * std::mem::size_of::<DWORD>()) as u32, &mut cb_needed, ) }; if result.as_bool() { // 计算实际获取到的进程ID数量(总字节数 / 单个DWORD的字节数) let process_count = (cb_needed / std::mem::size_of::<DWORD>() as u32) as usize; // 截断Vec,只保留有效的进程ID数据 a_processes.truncate(process_count); println!("找到{}个进程:", process_count); for pid in &a_processes { if *pid != 0 { // 过滤可能存在的空进程ID println!("{}", pid); } } } else { eprintln!("EnumProcesses调用失败,错误码:{}", unsafe { GetLastError() }); } }
关键细节说明
- 如果你不确定初始缓冲区的大小,可以先调用一次EnumProcesses获取
cb_needed,再根据该值分配精确大小的缓冲区:let mut cb_needed = 0; // 第一次调用获取所需字节数 unsafe { EnumProcesses(std::ptr::null_mut(), 0, &mut cb_needed) }; let process_count = (cb_needed / std::mem::size_of::<DWORD>() as u32) as usize; let mut a_processes = vec![0u32; process_count]; // 第二次调用获取实际进程ID unsafe { EnumProcesses(a_processes.as_mut_ptr(), cb_needed, &mut cb_needed) }; - 必须使用
unsafe块调用EnumProcesses,因为该函数直接操作原始指针,Rust无法保证内存安全。
内容的提问来源于stack exchange,提问作者Tushar Saurabh
相关产品推荐
相关产品推荐

