From 864ae35cb0bd80507c733de2c4c0a46ecd06279d Mon Sep 17 00:00:00 2001 From: Yuki Date: Fri, 3 Jul 2026 11:07:57 +0800 Subject: [PATCH] =?UTF-8?q?[2022]=20=E4=BF=AE=E5=A4=8D=E5=8F=8C=E5=87=BB?= =?UTF-8?q?=20.tmu=20=E5=86=B7=E5=90=AF=E5=8A=A8=E5=B4=A9=E6=BA=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TeXmacs/progs/texmacs/texmacs/tm-files.scm | 6 +- devel/2022.md | 88 ++++++++++++++++++++++ 2 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 devel/2022.md diff --git a/TeXmacs/progs/texmacs/texmacs/tm-files.scm b/TeXmacs/progs/texmacs/texmacs/tm-files.scm index 10c68c12c9..1e21172d2b 100644 --- a/TeXmacs/progs/texmacs/texmacs/tm-files.scm +++ b/TeXmacs/progs/texmacs/texmacs/tm-files.scm @@ -322,9 +322,11 @@ (tm-define current-save-source (url-none)) (tm-define current-save-target (url-none)) -(define (buffer-notify-recent name) +(tm-define (buffer-notify-recent name) + ;; 用 tm-define 导出:init_texmacs.cpp 用 eval_scheme 在 user_env 跨模块调用本过程, + ;; 若用 define(模块私有)会触发 unbound-variable 并在 s7 错误处理中崩溃。 (learn-interactive 'recent-buffer (list (cons "0" (url->system name)))) -) ;define +) ;tm-define (define (has-faithful-format? name) (in? (url-suffix name) '("tm" "ts" "tp" "stm" "scm" "tmu" "stem")) diff --git a/devel/2022.md b/devel/2022.md new file mode 100644 index 0000000000..f9f9c3e0ad --- /dev/null +++ b/devel/2022.md @@ -0,0 +1,88 @@ +# [2022] 修复双击 .tmu 冷启动崩溃(buffer-notify-recent 未导出,Linux/Windows) + +## 1 相关文档 +- [dddd.md](dddd.md) - 任务文档模板 +- [2020.md](2020.md) - 双击 .tmu 在已有窗口以新标签页打开(本崩溃最初在该任务打包测试时暴露) + +## 2 任务相关的代码文件 +- `TeXmacs/progs/texmacs/texmacs/tm-files.scm` - `buffer-notify-recent` 定义点(修复点) +- `src/System/Boot/init_texmacs.cpp` - `TeXmacs_main` 命令行首文件分支用 `eval_scheme` 跨模块调用 `buffer-notify-recent`(崩溃触发点,行 911) +- `moebius/Scheme/S7/s7_tm.cpp` - `eval_scheme` 用 `user_env`(全局环境)求值 +- `TeXmacs/progs/kernel/texmacs/tm-dialogue.scm` - `learn-interactive`/`recent-buffer-json`(`buffer-notify-recent` 调用链) + +## 3 如何测试 + +### 3.1 确定性测试(崩溃复现) +```bash +xmake b stem +# 必须用绝对路径文件参数 + 不开 -d(DEBUG_FLAG_STD 会改变 s7 错误处理路径,掩盖崩溃) +TEXMACS_PATH=$(pwd)/TeXmacs ./build/linux/x86_64/releasedbg/moganstem ~/Downloads/cheatsheet.tmu +# 修复前:exit 139(SIGSEGV),打印到 "Booting TeXmacs kernel functionality" 后崩溃 +# 修复后:exit 0(被 timeout 正常结束),顺利通过 kernel boot +``` + +### 3.2 非确定性测试(GUI 验证) +```bash +xmake r stem ~/Downloads/cheatsheet.tmu # xmake 注入 -d,正常打开(修复前后都不崩) +``` +真实复现需 OS 双击或裸命令行带文件参数(见 3.1)。`xmake r` 因注入 `-d` 掩盖了该 bug。 + +## 4 如何提交 + +```bash +gf fmt --changed-since=main # .scm 不在该工具范围内,仅 C++ 排查痕迹需还原 +xmake b stem # 主程序编译 +TEXMACS_PATH=$(pwd)/TeXmacs ./build/linux/x86_64/releasedbg/moganstem ~/Downloads/cheatsheet.tmu # 崩溃复现验证 +``` + +## 5 What + +将 `tm-files.scm` 中的 `buffer-notify-recent` 从 `define` 改为 `tm-define`,使其导出到全局环境。 + +## 6 Why + +**平台表现**:在 Linux(GNOME,已实测;KDE 未测)下双击 `.tmu`、或命令行 +`moganstem file.tmu` 冷启动打开文件会 SIGSEGV(exit 139)。 + +- **macOS 不受影响**:双击由 Qt 派发 `QFileOpenEvent`,在 `QTMGuiHelper::eventFilter` + 里走 `load-buffer`,**不经过** `TeXmacs_main` 的命令行首文件分支,自然不会命中崩溃点。 +- **Windows 未测**:双击同样把文件作 argv 传给新进程,走与 Linux 相同的 `TeXmacs_main` + 首文件分支,**理论上也会崩**,待实测确认。 +- **根因本身平台无关**:`eval_scheme("(buffer-notify-recent …)")` 在 `user_env` 找不到 + 模块私有符号是 s7 层的问题,只是 macOS 的双击路径恰好绕开了它。 + +堆栈(Linux 实测): + +``` +levenshtein +unbound_variable_error_nr +unbound_variable +eval / s7_eval +s7_eval_c_string_with_environment +eval_scheme(string) ← init_texmacs.cpp:911 +TeXmacs_main +``` + +`TeXmacs_main` 在命令行首文件加载后调用 `eval_scheme("(buffer-notify-recent …)")`。 +`eval_scheme` 用 **全局 `user_env`** 求值,而 `buffer-notify-recent` 原本是模块私有的 +`define`(仅在 `(texmacs texmacs tm-files)` 模块内部可见),跨模块求值时为 unbound variable。 +s7 报错时调用 `levenshtein` 找"最相似的已绑定符号"做提示,遍历过程中崩溃。 + +> 注:`xmake r stem`(注入 `-d`/`-debug-bench`)不会复现——DEBUG_FLAG_STD 改变了 s7 的 +> 错误处理路径,掩盖了该 bug。这也是它长期未被发现的原因。 + +## 7 How + +`tm-files.scm` 内绝大多数对外过程都用 `tm-define`(如 `switch-to-buffer*`、`buffer-copy` +等),`buffer-notify-recent` 用 `define` 是疏漏——它被 C++ 侧 `eval_scheme` 跨模块调用, +本就该导出。改回 `tm-define` 与文件内既有约定一致,最小改动。 + +### 7.1 排查路径(备查) + +1. `moganstem.sym` + `addr2line` 把 stripped 崩溃栈解析到 `eval_scheme` / `TeXmacs_main`。 +2. 设 `TEXMACS_PATH` 裸跑本地 `releasedbg` 二进制复现 SIGSEGV(`xmake r` 因注入 `-d` 不可复现)。 +3. 在 `eval_scheme` 临时打印求值字符串,定位到最后一条 `(buffer-notify-recent "…")`。 +4. gdb 在 `levenshtein` 断点抓入参:一边是 `"buffer-notify-recent"`,确认是它在 user_env 中未绑定。 +5. 查 `tm-files.scm`:`buffer-notify-recent` 是 `define`(模块私有),同文件其它过程多为 `tm-define`。 + +排查用的临时调试代码(`s7_tm.cpp` 的 `fprintf`)已还原,不在提交内。