Files
StellarX-kaifa/开发记录/功能变更/Feature-20260915-0001-全量缺陷修复与API调整.md
T

138 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 功能变更 ID: Feature-20260915-0001
> 适用场景:记录小到中等规模的功能、接口、行为、默认值或配置变化。
> 不适用场景:新增核心模块、重大模块重构、架构级设计,请使用“新增功能模块”模板。
## 基本信息
- ID: Feature-20260915-0001
- 标题: 全量缺陷修复与 API 调整
- 状态:非 UI 与人工 UI 已验证,待提交
- 类型:修改 / 删除 / 重命名
- 级别:L3 重大
- 模块: Control / Window / Canvas / Dialog / TabControl / Table / SxLogger / Test
- 版本 / 分支: 当前工作区
- 环境: Windows + Visual Studio 2022 + MSVC v143 + EasyX
- 负责人: Codex 协作修改
## 变更背景
- 背景:
- 代码审查发现控件回调期间所有权变化、空 TabControl、快照尺寸、几何残影、Dialog 关闭、Table coverage、日志滚动、MBCS 文本、Tooltip 和事件循环等问题。
- 原有测试主要依赖 `KEY` 场景和手工观察,缺少不创建窗口的逻辑验证、ASan 验证以及可重复的外部 UI 断言。
- 目标:
- 修复高、中、低严重度缺陷,消除明确的 UAF、越界、残影、数据截断和所有权丢失风险。
- 通过稳定句柄和延迟变更事务收口控件容器生命周期。
- 建立可重复的逻辑、像素不变量和真实 UI 回归验证。
- 明确破坏性 API 的迁移方式。
- 不做什么:[可选]
- 不迁移 Unicode,继续使用 MBCS/GBK 风格字符处理。
- 不把 GUI 改造成多线程模型。
- 不在本次将 `StellarX.Core` 改为 DLL,也不处理安装包制作。
## 变更内容
- 变更摘要:
- 修复 14 项高、中、低严重度问题。
- 将核心框架独立为 `StellarX.Core` 静态库,并让应用、单元测试和 UI Fixture 共用该实现。
- 新增 Native Unit Test、ASan、EasyX UI Fixture 和 PowerShell 自动化入口。
- 新增项:[可选]
- `StellarX::ControlHandle` 及受控控件所有权接口。
- `MutationTransaction` 延迟变更机制。
- `SxEventLoopInternal.h` 和 `SxTextInternal.h` 内部测试辅助。
- `StellarX.Tests`、`StellarX.UiFixture` 和 `scripts/test.ps1`。
- 修改项:[可选]
- Button/Label/TextBox/Canvas/Table/TabControl 的 geometry、snapshot、coverage 和绘制提交逻辑。
- Dialog 关闭和 overlay 收口逻辑。
- SxLogger sink 配置和滚动逻辑。
- Tooltip tick、MBCS 密码掩码和事件循环批处理。
- 删除 / 废弃项:[可选]
- 删除 `Window::getControls()` 和 `Canvas::getControls()` 的 mutable 容器入口。
- 删除 `Canvas::clearAllControls()`。
- `ControlText::lpszFace` 废弃并替换为 `faceName`。
- 旧的按文本/旧参数添加 Tab 控件方式不再作为首选接口。
- 受影响的文件 / 类 / 函数:
- 工程:`StellarX.Core.vcxproj`、`imGui-easyX.vcxproj`、`imGui-easyX.sln`。
- 所有权和事务:`CoreTypes.h`、`Control.h/.cpp`、`Window.h/.cpp`、`Canvas.h/.cpp`。
- 控件和重绘:`Button.h/.cpp`、`Label.h/.cpp`、`TextBox.cpp`、`Table.cpp`、`Dialog.cpp`、`TabControl.h/.cpp`。
- 日志:`SxLog.h/.cpp`。
- 示例入口:`z-testDome.cpp`。
- 测试:`tests/StellarXTests.cpp`、`tests/UiFixture.cpp`、`scripts/test.ps1`、`scripts/run-ui-tests.ps1`。
- 对外 API / 属性变化:[可选]
- `ControlHandle addControl(std::unique_ptr<Control>)`
- `bool removeControl(ControlHandle)`、`void clearControls()`
- `Control* findControl(ControlHandle)`、`std::vector<ControlHandle> getControlHandles() const`
- `ControlText::faceName` 替代 `lpszFace`。
- `bool SxLogger::setConfig(const SxLogConfig&)`。
- `size_t TabControl::addTab(...)`、`bool setActiveIndex(int)`、`tryAddToPage(...)`。
## 行为对照
- 变更前:
- 回调中直接删除当前或兄弟控件可能使遍历中的裸指针失效。
- 空 TabControl 激活和绘制路径可能访问不存在的页签。
- 控件几何变化、Tooltip、Dialog 和 Table 的局部 coverage 可能留下旧像素或污染快照。
- 日志滚动失败时可能截断原日志;字体名可能引用悬空内存;密码掩码可能按字节而非逻辑字符生成。
- 事件循环每轮只处理一条消息并固定休眠,消息积压时响应和重绘收口不稳定。
- 变更后:
- 控件增删清空在最外层遍历事务结束后提交,回调期间不会释放正在使用的遍历对象。
- 空页签路径安全返回,待激活索引在首个页签加入后应用,非法运行期索引返回 `false`。
- 几何 setter 先恢复旧 coverage,再登记旧新区域并集;快照、绘制和 coverage 使用一致的矩形语义。
- 日志 sink 候选打开成功后才原子替换,滚动重命名失败时继续 append 原文件。
- MBCS 文本按逻辑字符处理,Tooltip 由 tick 链驱动到期和清除。
- 兼容性说明:不兼容
- 迁移说明:[可选]
- 调用方应使用稳定 `ControlHandle`,不再保存可变控件容器引用。
- 将 `lpszFace` 改为 `faceName`,将旧 Tab 添加路径迁移到索引 API。
- 具体示例见 [`MIGRATION.md`](D:/programming/imGUI-easyX/imGui-easyX/开发记录/MIGRATION.md)。
## 全量缺陷修复矩阵
| 严重度 | 问题 | 根因与修复 | 主要验证 |
|---|---|---|---|
| 高 | 回调删除当前控件导致 UAF | 引入稳定 `ControlHandle` 和 `MutationTransaction`;事件、绘制、按钮回调期间的 Add/Remove/Clear 延迟提交。 | self/sibling/remove/clear/add 回调测试;x64 ASan |
| 高 | 空 TabControl 激活索引越界 | 空容器绘制不访问末元素;待激活索引延迟到首个页签加入后应用;非法索引返回 `false`。 | 空容器设置 0/大索引并绘制;随后新增页签 |
| 中 | Button 快照尺寸恒不匹配 | 提取统一快照矩形计算,比较、保存和 coverage 使用相同宽高。 | hover/click/redraw/hide 像素不变量 |
| 中 | 运行时几何 setter 遗留旧像素 | setter 记录旧 coverage、恢复并释放旧快照,再更新矩形并登记旧新区域并集。 | Button/Label/TextBox/Canvas/Table/Tab 移动、缩放、隐藏 |
| 中 | Dialog 清理触发额外全量重绘 | `Close()` 统一登记 overlay 关闭,清理只释放对象和快照,Window 在 sweep 后统一重绘。 | 两层异步 Dialog 关闭上层后下层可见、可交互 |
| 中 | Table 宽度、列宽和 coverage 不一致 | 计算最小宽度并夹紧请求值;列宽总和严格等于有效内容宽;按 MBCS 边界省略文本。 | 极窄 Table、多列长文本、分页按钮和 coverage |
| 中 | 日志滚动失败截断原日志 | 滚动名加入毫秒和递增序号;检查 rename 错误;失败时重新 append 原文件,不执行 trunc。 | 同毫秒滚动、同名文件、无效路径 |
| 中 | ControlText 字体名悬空和地址比较 | 使用拥有型 `std::string faceName`;EasyX/GDI 调用使用 `.c_str()`;比较按字符串内容。 | 临时字符串析构、相同内容不同地址、内容变化测量 |
| 中 | `setConfig()` 不同步文件 sink | 锁内构造并打开候选 sink,成功后替换;禁用、路径、append 和 rotate 变化同步重开。 | 启用/禁用、切换文件、无效路径和输出一致性 |
| 中 | 同名页签可同时激活 | 通过索引排除当前页签,不按标题排除;允许重复标题但只保留一个激活页。 | 两个同名页签来回切换 |
| 低 | Tooltip 静止时不会到期显示 | 增加 Control tick 链,Window 传入单调时钟;到期时置脏并登记重绘;禁用和移出统一 hide。 | 假时钟、静止鼠标、到期显示和移出清除 |
| 低 | 密码掩码按字节生成 | 复用 MBCS 字符边界遍历,每个逻辑字符生成一个 `*`,非法尾字节仍保证前进。 | ASCII、GBK 双字节、非法尾字节 |
| 低 | 事件循环每轮只处理一条消息并固定 Sleep | 提取批处理器,每轮最多 128 条;活动轮不休眠,空闲轮 `Sleep(1)`;批次尾统一收口 resize/重绘。 | 一次注入 1000 条消息;关闭和 resize 顺序 |
| 低 | 按文本添加页控件失败时静默销毁 | `tryAddToPage` 失败原样返还 `unique_ptr`;索引重载为首选,文本重载只匹配首个同名页签。 | 不存在标题、非法索引和同名标题 |
## 验证与落地
- 验证方式:
- 使用 VS Native Unit Test 对所有权、Tab、文本、Tooltip、事件循环和日志逻辑进行测试。
- 使用 Debug x64 ASan 对回调生命周期和核心逻辑进行内存安全验证。
- 使用真实 EasyX UI Fixture 和 Win32 `SendInput`、`SetWindowPos` 驱动窗口。
- 使用 JSON 状态、关键像素、后备缓冲 PNG 和 Fixture 日志进行断言。
- 验证结果:
- 2026-09-29 执行 `scripts/test.ps1 -Suite NonUI`,Debug x64、Debug x64 ASan、Release x64、Debug Win32 均为 15/15 通过。
- x64 ASan 未报告内存错误;KEY1 至 KEY6 均编译、链接通过。
- 2026-09-30 为 `scripts/test.ps1` 补充 UTF-8 BOM 后,使用 Windows PowerShell 5.1 重跑 `NonUI`,结果保持通过。
- 本轮按约定未启动自动 UI Fixture;用户于 2026-09-30 按 `TESTING.md` 手工完成 KEY1 至 KEY6,暂未发现明显问题。
- 2026-07-22 的 UI 六类场景连续三轮通过记录保留为历史证据;当前快照以 2026-09-30 的人工验收结果为准。
- TRX 等诊断产物位于未跟踪的 `TestResults/`。
- 关联 BUG / Fix:[可选]
- 历史重绘和 Tab 相关记录见 `开发记录/BUG`、`开发记录/Fix` 目录。
- 本次新增内容以本记录的严重度矩阵统一收口,避免为同一批次重复创建 14 组 BUG/Fix 文档。
- Commit:
- 当前工作区未提交
- PR:[可选]
- 发布版本:[可选]
- 备注:[可选]
- 当前 `Render` 入口复用 UI Fixture,尚未形成完全独立的进程内 Native Render 测试类别。
- GUI 仍限定在主线程,字符集仍为 MBCS。
## 相关文档
- [`Module-20260915-0001-StellarX核心库与自动化测试基础设施.md`](D:/programming/imGUI-easyX/imGui-easyX/开发记录/模块/Module-20260915-0001-StellarX核心库与自动化测试基础设施.md)
- [`MIGRATION.md`](D:/programming/imGUI-easyX/imGui-easyX/开发记录/MIGRATION.md)
- [`TESTING.md`](D:/programming/imGUI-easyX/imGui-easyX/开发记录/TESTING.md)