10 KiB
10 KiB
功能变更 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() constControlText::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。
- 调用方应使用稳定
全量缺陷修复矩阵
| 严重度 | 问题 | 根因与修复 | 主要验证 |
|---|---|---|---|
| 高 | 回调删除当前控件导致 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/。
- 2026-09-29 执行
- 关联 BUG / Fix:[可选]
- 历史重绘和 Tab 相关记录见
开发记录/BUG、开发记录/Fix目录。 - 本次新增内容以本记录的严重度矩阵统一收口,避免为同一批次重复创建 14 组 BUG/Fix 文档。
- 历史重绘和 Tab 相关记录见
- Commit:
- 当前工作区未提交
- PR:[可选]
- 发布版本:[可选]
- 备注:[可选]
- 当前
Render入口复用 UI Fixture,尚未形成完全独立的进程内 Native Render 测试类别。 - GUI 仍限定在主线程,字符集仍为 MBCS。
- 当前