Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions TeXmacs/progs/texmacs/texmacs/tm-files.scm
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Expand Down
88 changes: 88 additions & 0 deletions devel/2022.md
Original file line number Diff line number Diff line change
@@ -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`)已还原,不在提交内。
Loading