fix(c,go): 修复 cagent SIGSEGV 崩溃 + 崩溃后终端 raw mode 恢复#70
Merged
Conversation
…GSEGV 崩溃 Bug 1 (SIGSEGV at 0x18): SubAgent mq_push(NULL display_queue) - agent_handle_sub_agent/process_sub_result 直接调 mq_push 绕过 NULL 检查 - SubAgent display_queue=NULL, 交互模式下 mq_push 解引用偏移 0x18 段错误 - 修复: mq_push 前增加 display_queue != NULL 条件 Bug 2 (SIGSEGV at 0x0): json_parse_root(NULL) 解引用空指针 - tool call input_json.data 为 NULL 时 skip_ws 段错误 - 修复: json_parse_root 入口增加 NULL 检查 防御性修复: - mq_push/mq_pop/mq_try_pop 增加队列 NULL 检查 - crash signal handler 恢复终端 raw mode 防崩溃后终端错乱
Go 版本使用 CGo linenoise 进入终端 raw mode,但崩溃/panic 时没有恢复机制, 导致终端残留在 raw mode(无回显、无换行处理),需要手动 stty sane 修复。 与 C 版本的修复保持一致: - main(): defer recover() 捕获主 goroutine panic,恢复终端后退出 - main(): signal.Notify 捕获 SIGSEGV/SIGABRT/SIGBUS/SIGFPE,恢复终端后重新发出信号 - readline loop(): defer recover() 捕获 readline goroutine panic - linenoise.RestoreTerminal(): 公开 Go 绑定,调用 C 版 linenoiseRestoreTerminal() 注:Go 版本不存在 C 版本的两个 SIGSEGV bug(Bug 1: SubAgent 用 silent TermDisplay 而非 nil channel;Bug 2: encoding/json 对空输入返回 error 而非 panic)。 本次修复纯粹是终端恢复加固。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
cagent 在 SubAgent 嵌套调用场景下发生 SIGSEGV 崩溃(4 份 macOS crash log),
崩溃后终端残留在 raw mode,输出完全错乱,需手动
stty sane恢复。Bug 1: SubAgent NULL display_queue → SIGSEGV (addr=0x18) — C 版本
触发条件: SubAgent(display_queue=NULL)内部 LLM 调用 SubAgent 工具(嵌套),
主 agent 为 human 输出模式。
根因:
agent_handle_sub_agent/agent_process_sub_result直接调mq_push,绕过了已有 NULL 检查的
push_display辅助函数。SubAgent display_queue=NULL →mq_push解引用 NULL 偏移 0x18(pthread_mutex_t.mutex)→ 段错误。Bug 2: json_parse_root(NULL) → SIGSEGV (addr=0x0) — C 版本
根因: tool call 的
input_json.data为 NULL 时,json_parse_root未做 NULL 检查,skip_ws(NULL, &pos)解引用空指针。终端排版错乱 — C + Go 版本
linenoise readline 线程将终端设为 raw mode(禁用 OPOST/ONLCR)。进程崩溃后
atexit不触发,raw mode 残留。修复
Commit 1: C 版本(2 bugs + 终端恢复)
c/agent.cagent_handle_sub_agent/agent_process_sub_result的mq_push前增加display_queue != NULL条件c/json.cjson_parse_root入口增加if (!src) return make_errc/msgqueue.cmq_push/mq_pop/mq_try_pop防御性 NULL 检查c/cagent.cSIGSEGV/SIGABRT/SIGBUS/SIGFPEsignal handler,恢复终端后重新发出信号vendor/linenoise/linenoise.{c,h}linenoiseRestoreTerminal()函数Commit 2: Go 版本(终端恢复加固)
Go 版本不存在 Bug 1 和 Bug 2(语言层面天然保护:nil channel send 会 block 而非 crash;
encoding/json对空输入返回 error 而非 panic)。但 Go 同样使用 CGo linenoise 进入 raw mode,缺少崩溃恢复机制。
go/cmd/goagent/main.godefer recover()+signal.Notify(SIGSEGV/SIGABRT/SIGBUS/SIGFPE)恢复终端go/cmd/goagent/readline.godefer recover()恢复终端go/linenoise/linenoise.goRestoreTerminal()Go 绑定,调用 C 版linenoiseRestoreTerminal()Rust 版本
已有
std::panic::set_hook→crossterm::terminal::disable_raw_mode(),无需修改。测试
make build-c+AGENT=./dist/cagent bash tests/test.sh— 201 passed, 0 failedmake build-go+AGENT=./dist/goagent bash tests/test.sh— 201 passed, 0 failed