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

10 KiB
Raw Permalink Blame History

功能变更 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。

全量缺陷修复矩阵

严重度 问题 根因与修复 主要验证
高 回调删除当前控件导致 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。

相关文档