mirror of
https://github.com/LHY0125/PathEditor.git
synced 2026-05-10 02:09:46 +08:00
3bc2f00cb1
- 在备份失败时显示具体原因(如无法获取AppData路径、创建备份目录失败等) - 改进备份函数的错误处理,添加详细的日志记录 - 备份失败时允许用户选择是否继续保存操作 - 修复备份目录创建失败时的错误码返回 - 添加备份过程的详细文档说明
9.5 KiB
9.5 KiB
PathEditor 代码审查修复日志
审查日期:2026-04-28 审查范围:全项目代码质量审查 修复状态:29/29 已完成
一、高严重度问题(7 项)
1.1 add_string_list 中 realloc 失败导致内存泄漏
- 文件:
src/utils/string_ext.c - 问题:
realloc返回 NULL 时,原list->items指针被覆盖为 NULL,导致原有数组及其中所有字符串指针永久泄漏 - 修复:使用临时变量保存
realloc结果,失败时保留原数据不变
// 修复前
list->items = (char **)realloc(list->items, list->capacity * sizeof(char *));
// 修复后
char **new_items = (char **)realloc(list->items, new_capacity * sizeof(char *));
if (!new_items)
return; // 失败时保留原数据
list->items = new_items;
1.2 add_string_list 中 _strdup 失败未检查
- 文件:
src/utils/string_ext.c - 问题:
_strdup可能返回 NULL,但代码未检查就存入数组并递增 count,后续字符串操作会崩溃 - 修复:检查
_strdup返回值,失败时不递增 count
1.3 string_list_set 中先 free 后 strdup 导致数据丢失
- 文件:
src/utils/string_ext.c - 问题:先释放旧字符串,然后
_strdup可能失败,导致旧数据丢失且无法恢复 - 修复:先调用
_strdup获取新字符串,成功后再释放旧字符串
1.4 wcsftime 缓冲区大小以字节而非宽字符数传入
- 文件:
src/utils/os_env.c - 问题:
sizeof(timestamp)返回字节数(128),而wcsftime期望宽字符数(64),可能导致栈缓冲区溢出 - 修复:改用
sizeof(timestamp) / sizeof(timestamp[0])
// 修复前
wcsftime(timestamp, sizeof(timestamp), L"%Y%m%d_%H%M%S", tm_info);
// 修复后
wcsftime(timestamp, sizeof(timestamp) / sizeof(timestamp[0]), L"%Y%m%d_%H%M%S", &tm_info);
1.5 load_single_path 在 malloc 失败时仍返回 ERR_OK
- 文件:
src/core/registry_service.c - 问题:
malloc失败时跳过数据读取,但仍返回ERR_OK,调用者认为加载成功 - 修复:
malloc失败时返回ERR_OUT_OF_MEMORY
1.6 导入数据内存泄漏
- 文件:
src/controller/callbacks_io.c - 问题:
btn_import_cb中ExportData imported的system和user从未调用clear_string_list释放 - 修复:在函数所有返回路径前调用
clear_string_list释放导入数据
1.7 JSON 导入解析器完全失效
- 文件:
src/core/import_export.c - 问题:键名检测逻辑被
in_string状态翻转拦截,"system"和"user"的检测永远无法触发 - 修复:重写 JSON 解析器,在字符串结束时检测键名,合并重复的数组解析逻辑
二、中严重度问题(9 项)
2.1 backup_registry 部分备份成功时错误报告为完全成功
- 文件:
src/utils/os_env.c - 修复:分别跟踪系统和用户 PATH 的备份状态
2.2 btn_ok_cb 未检查 backup_registry 返回值
- 文件:
src/controller/callbacks_sys.c - 修复:检查返回值,备份失败时提示用户是否继续保存
// 修复后
ErrorCode backup_result = backup_registry();
if (backup_result != ERR_OK)
{
int choice = IupAlarm("警告", "备份失败!是否继续保存?",
"继续保存", "取消", NULL);
if (choice != 1)
return IUP_DEFAULT;
}
2.3 TABTITLE 设置在 Dialog 而非 Tabs 控件上
- 文件:
src/ui/main_window.c - 问题:
TABTITLE0和TABTITLE1是IupTabs属性,不是IupDialog属性,导致语言切换后选项卡标题不更新 - 修复:先获取 Tabs 控件句柄,再设置 TABTITLE
2.4 list_dropfiles_cb 使用 ANSI 版本 API
- 文件:
src/controller/callbacks_search.c - 问题:
GetFileAttributesA无法正确处理中文等 Unicode 字符路径 - 修复:改用
utf8_to_wide+GetFileAttributesW
2.5 load_all_paths 用户路径加载失败时未通知用户
- 文件:
src/controller/callbacks_sys.c - 修复:添加 else 分支,在用户路径加载失败时弹出提示
2.6 escape_json_string 未处理所有控制字符
- 文件:
src/core/import_export.c - 问题:只处理了
\\、"、\n、\r、\t,其他 0x00-0x1F 控制字符未转义 - 修复:添加
\b、\f处理,其他控制字符使用\uXXXX格式
2.7 CreateDirectoryW 不创建中间目录
- 文件:
src/utils/os_env.c - 修复:改用
SHCreateDirectoryExW递归创建目录
2.8 ExportData 浅拷贝隐患
- 文件:
include/core/import_export.h - 修复:添加文档注释说明只读语义,防止误用
clear_string_list
2.9 export_paths_to_file 未检查 fprintf 返回值
- 文件:
src/core/import_export.c - 修复:在
fclose后检查ferror(fp),发现错误时返回ERR_FAILED
三、低严重度问题(13 项)
3.1 JSON 解析器代码重复
- 文件:
src/core/import_export.c - 修复:合并 system/user 数组解析逻辑为统一的键名检测机制
3.2 get_app_context_from_dlg 依赖指针到字符串的不安全转换
- 状态:保留现状(IUP 框架标准用法)
3.3 putenv 使用字符串字面量的可移植性问题
- 文件:
src/main.c - 修复:改用
_wputenv_s
3.4 path_manager_clean 时间复杂度为 O(n³)
- 文件:
src/core/path_manager.c - 修复:使用标记+批量删除优化为 O(n²)
3.5 全局日志状态非线程安全
- 状态:保留现状(当前是单线程 GUI 应用)
3.6 localtime 返回静态缓冲区指针,非线程安全
- 文件:
src/utils/os_env.c、src/core/import_export.c - 修复:改用
localtime_s
3.7 JSON 解析器原地修改输入缓冲区
- 修复:重写解析器时已解决,不再修改原始缓冲区
3.8 JSON 解析器对 \\" 场景处理错误
- 修复:重写解析器时已解决,使用
is_quote_escaped检查连续反斜杠
3.9 TXT 格式导入只能导入到系统路径
- 文件:
src/controller/callbacks_io.c - 修复:添加选择对话框,允许用户选择导入到系统变量或用户变量
3.10 trim_whitespace 未检查 NULL 输入
- 文件:
src/core/import_export.c - 修复:添加防御性 NULL 检查
3.11 is_json_file 使用 strcasecmp 限制可移植性
- 文件:
src/core/import_export.c - 修复:改用
_stricmp(MSVC/MinGW 都支持)
3.12 localtime 可能返回 NULL
- 修复:改用
localtime_s,无需 NULL 检查
3.13 main.c 中 _() 嵌套调用可能崩溃
- 文件:
src/main.c - 问题:
_(lua_config_get_string(...))嵌套调用,若配置键不存在,gettext(NULL)行为未定义 - 修复:先将结果保存到临时变量并检查非 NULL
// 修复前
IupMessage(_("Warning"), _(lua_config_get_string("status", "admin_warning")));
// 修复后
const char *admin_msg = lua_config_get_string("status", "admin_warning");
IupMessage(_("Warning"), admin_msg ? _(admin_msg) : "需要管理员权限才能编辑环境变量");
四、第一轮修复(原10条锐评)
| # | 问题 | 状态 |
|---|---|---|
| 1 | core层用了iup.h(架构矛盾) | ✅ 已修复 |
| 2 | main.c管理员权限检测代码灾难 | ✅ 已修复 |
| 3 | refresh_main_window_ui重复代码 | ✅ 已修复 |
| 4 | 字符串溢出风险(buffer不统一) | ✅ 已修复 |
| 5 | 错误码乱用(ERR_NULL_PTR误用) | ✅ 已修复 |
| 6 | 硬编码字符串满天飞 | ✅ 已修复 |
| 7 | backup_registry未实现 | ✅ 已修复 |
| 8 | callbacks.c 600行回调地狱 | ✅ 已拆分 |
| 9 | StringList封装不透明 | ✅ 已修复 |
| 10 | refresh_single_list_style黑盒 | ✅ 已修复 |
五、修改文件清单
| 文件 | 修改类型 |
|---|---|
include/utils/string_ext.h |
添加访问器函数声明 |
include/utils/ui_constants.h |
新建,控件名称常量 |
include/core/import_export.h |
添加文档注释 |
include/controller/callbacks_internal.h |
新建,内部辅助函数声明 |
src/utils/string_ext.c |
修复 realloc/strdup 安全性 |
src/utils/os_env.c |
修复 wcsftime、localtime、目录创建 |
src/core/registry_service.c |
修复 malloc 错误处理 |
src/core/import_export.c |
重写 JSON 解析器、修复转义函数 |
src/core/path_manager.c |
优化清理算法、修复错误码 |
src/main.c |
修复 putenv、_() 嵌套调用 |
src/ui/main_window.c |
修复 TABTITLE 设置位置 |
src/controller/callbacks.c |
拆分后只保留辅助函数 |
src/controller/callbacks_basic.c |
新建,基础 CRUD 回调 |
src/controller/callbacks_nav.c |
新建,导航回调 |
src/controller/callbacks_search.c |
新建,搜索/拖拽回调 |
src/controller/callbacks_io.c |
新建,导入导出回调 |
src/controller/callbacks_sys.c |
新建,系统操作回调 |
CMakeLists.txt |
添加新源文件 |
六、编译验证
cmake -B build -G "MinGW Makefiles"
cmake --build build
结果:编译通过,无错误,无警告。
七、剩余已知问题(设计决策,非 Bug)
| 问题 | 原因 | 建议 |
|---|---|---|
| IUP 指针存储模式 | IUP 框架标准用法 | 保持现状 |
| 日志线程安全 | 当前是单线程应用 | 多线程时再处理 |
| localtime 线程安全 | 已改用 localtime_s | 已修复 |
审查完成于 2026-04-28