1 、概述
最近在研究一个游戏的自由相机MOD,在运行的时候程序抛出了如下错误:
thread ‘main’ panicked at 'No string found: Utf8Error
本文主要是记录解决这个错误的过程与思路。
2、分析过程
2.1 错误提示分析
thread ‘main’ panicked at 'No string found: Utf8Error
从抛出的错误内容上来看,像是一个字符格式的错误,有可能是ASCII和UTF8的问题,例如中文和英文的问题。
2.2 源码分析
2.2.1 应用逻辑
由于作者把这个模块开源了,所以可以从源码层面上进一步定位问题。
let p = loop {
if let Ok(p) = Process::new("Cemu.exe") {
break p;
}
println!("NO Game found");
std::thread::sleep(std::time::Duration::from_secs(5));
};
调试发现,在调用这一行时,程序崩溃掉。
let Ok(p) = Process::new("Cemu.exe")
从字符上看,这里不存在特殊字符或者中文字符,因此大概率不是字符格式的问题。
2.2.2 依赖库逻辑
Process::new 函数来自一个外部库,所以应该跳转到外部库对应的函数实现中进一步分析。
use memory_rs::external::process::Process;
在外部库中直接搜索错误抛出的字符串 “No string found”,可以定位到如下位置:
let current_name =
CStr::from_ptr(process_entry.szExeFile.as_ptr())
.to_str()
.expect("No string found ");
这个代码块的含义为:通过process_entry获取进程的名称属性,如果为空则抛出异常“No string found”,进一步分析 process_entry 这个变量的声明和初始化
let mut process_entry = tlhelp32::PROCESSENTRY32 {
dwSize: mem::size_of::<tlhelp32::PROCESSENTRY32>() as u32,
..Default::default()
};
发现这里调用了一个Windows API “PROCESSENTRY32 ”
2.2.3 WIN API
进一步查询这个Win API的详细内容 PROCESSENTRY32 ,发现它被定义在 tlhelp32.h 这个头文件中,含义为描述创建快照时驻留在系统地址空间中的进程的列表中的条目。
目标平台 | Windows |
---|---|
标头 | tlhelp32.h |
Library | Kernel32.lib |
DLL | Kernel32.dll |
2.3 系统库
在上一步的分析中,问题被定位在Windows的系统API上,那么有可能是系统更新导致某些函数的调用方式发生了变更。因此为了排除是否是操作系统的问题,我将程序拷贝到一台装有Win10的工控机上运行,发现程序可以正常运行。
3. 解决问题
3.1 思路
现在可以确认软件逻辑没有问题,而是操作系统层面的问题。那么问题来了,这个Bug要怎么解决呢?
- 一个容易想到的思路是动态链接库的替换,直接将别的电脑上的Kernel32.dll拷贝到我的电脑上。但是替换时发现这个文件被占用了。因为这个是Windows的内核库,在Windows启动时候就被载入内存,因此想替换它还是比较困难的,而且就算能替换也不知道这个操作会不会导致系统运行不稳定,有一定风险。
- 此时陷入了僵局,直到我发现了我电脑右下角的测试模式。之前为了解决某软件的证书验证问题,将电脑切换到了测试模式下,一直忘了切回去。那么有可能是测试模式下,系统API的调用问题。
通过如下指令把测试模式关闭后,程序运行正常。
bcdedit /set testsigning off
3.2 原因
猜测测试模式下操作系统会屏蔽掉某些信息,导致调用系统API时结构体里面缺少相应的信息,所以抛出来了找不到字符的错误。
thread ‘main’ panicked at 'No string found: Utf8Error