Skip to content

fix(windows): do not panic when transitioning from Destroyed - #1188

Open
thomaseizinger wants to merge 4 commits into
tauri-apps:devfrom
thomaseizinger:fix/no-panic-destroyed
Open

fix(windows): do not panic when transitioning from Destroyed#1188
thomaseizinger wants to merge 4 commits into
tauri-apps:devfrom
thomaseizinger:fix/no-panic-destroyed

Conversation

@thomaseizinger

Copy link
Copy Markdown
Contributor

We are seeing crash reports from Tauri applications caused by this particular panic. I am not sure what they are caused by but it seems save to just remove the panic, log a message and leave the state in Destroyed instead.

Resolves: #1180

@thomaseizinger
thomaseizinger requested a review from a team as a code owner February 19, 2026 03:29
@github-actions

github-actions Bot commented Feb 20, 2026

Copy link
Copy Markdown
Contributor

Package Changes Through 8962da6

There are 1 changes which include tao with patch

Planned Package Versions

The following package releases are the planned based on the context of changes in this pull request.

package current next
tao 0.34.5 0.34.6

Add another change file through the GitHub UI by following this link.


Read about change files or the docs at github.com/jbolda/covector

@Legend-Master Legend-Master left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am in favor of this, maybe we could discuss with the winit maintainers about the reasoning behind this before merging though (or we should identify the reason we reached this line if this is an internal state error that should not happen and the panic is the right thing to do)

Comment thread src/platform_impl/windows/event_loop/runner.rs Outdated
@Legend-Master

Copy link
Copy Markdown
Contributor

After a closer look at the current code, we only ever move the state to destroyed on run_return ends (which has a reset call follows it immediately) and on WM_ENDSESSION

For the run_return case, it seems to me that it's impossible to trigger this panic since we only receive events on the main thread and since we reset the states immediately, this should not happen
For the WM_ENDSESSION case, the fix should be #1157 instead of this

@thomaseizinger

Copy link
Copy Markdown
Contributor Author

For the run_return case, it seems to me that it's impossible to trigger this panic since we only receive events on the main thread and since we reset the states immediately, this should not happen

We are using run_return in our application FWIW.

@Legend-Master

Copy link
Copy Markdown
Contributor

We are using run_return in our application FWIW.

run also uses run_return internally, since the state is reset to Uninitialized in literally next line, I don't think it's possible to hit (unless we did some other violations like calling move_state_to in another thread)

mkdir700 added a commit to UniClipboard/UniClipboard that referenced this pull request May 19, 2026
…ore_send

Windows 退出时 tao 0.35.x 的事件循环状态机硬 panic:
`(Destroyed, _) => panic!("cannot move state from Destroyed")`
触发场景是 `app_handle.exit(0)` 把 EventLoop 推进 Destroyed 之后,Windows
还派发了一条 paint message,runner 试图再迁移状态就炸。栈上没有任何
uc_* 帧,daemon 已在 panic 前 graceful 关掉、`Application exiting`
日志也落定,功能影响为零,纯 Sentry 噪音。

上游已有 issue/PR 但都 open:
- tauri-apps/tao#1180 (issue)
- tauri-apps/tao#1188 (PR,把 panic 软化成 debug log)

在上游 release 修复之前,在 `before_send` 里用
(panic value + 栈含 tao runner 的 frame) 双重匹配精确 drop 这条事件,
避免它继续污染 fatal-issue 面板。匹配规则集中到 `known_upstream_panic`
helper,每条规则带 `<crate>#<issue>` tracker tag,回收时直接 grep 找到
对应 match arm。

附 3 个单元测试覆盖:
- 命中规则 → drop
- panic message 相同但栈不在 tao → 不 drop (防误吞)
- 栈在 tao 但 panic message 不同 → 不 drop (防误吞)

受影响 Sentry: UNICLIPBOARD-RUST-P (4 events / 2 users, Windows
0.7.0→0.10.0)。
mkdir700 added a commit to UniClipboard/UniClipboard that referenced this pull request May 21, 2026
…817)

* fix(observability): cap netwatch::udp at debug to avoid divide-by-zero panic

netwatch 0.16/0.17/main 在 `UdpSocket::poll_recv_noq` 的 trace! 字段里直接做
`meta.len / meta.stride`,而 `noq_udp::RecvMeta.stride` 在 GRO/GSO 边界 (空
datagram、内核回退到非分段路径) 允许为 0,触发 divide-by-zero panic 并终止
宿主进程。

panic 在第三方 crate 的 trace! 求值阶段触发,我们栈上没有任何 uc_* 帧,
唯一可靠的本地拦截点就是在 EnvFilter 阶段把该 target 截到 debug,让 trace
永远不评估。同步在 `rust_log_override()` 路径上追加同条 directive,保证用户
设了 RUST_LOG=trace 也不绕过。

受影响 Sentry issue (同根因被按 OS 拆组):
- UNICLIPBOARD-RUST-18 (Windows 11 24H2, 0.10.0)
- UNICLIPBOARD-RUST-S  (macOS 15.4 / 26.x, 0.9.0 起多版本)

合计 6 个 fatal panic 跨 2 系统多设备,从 alpha 起持续出现。上游 net-tools
暂无对应 issue,本仓库准备另起 PR/issue 推动修复;在上游 release 前由该
EnvFilter 兜底。

(cherry picked from commit d9dccfd)

* docs(observability): link netwatch::udp mitigation to upstream issue #148

跟踪 n0-computer/net-tools#148 — 已在上游提了 divide-by-zero 的 issue,
把本地注释从「上游无对应 issue」改成具体跟踪链接,方便上游修好后定位回
收 mitigation。

(cherry picked from commit 0678e09)

* fix(observability): mute tao#1180 Destroyed-state panic in Sentry before_send

Windows 退出时 tao 0.35.x 的事件循环状态机硬 panic:
`(Destroyed, _) => panic!("cannot move state from Destroyed")`
触发场景是 `app_handle.exit(0)` 把 EventLoop 推进 Destroyed 之后,Windows
还派发了一条 paint message,runner 试图再迁移状态就炸。栈上没有任何
uc_* 帧,daemon 已在 panic 前 graceful 关掉、`Application exiting`
日志也落定,功能影响为零,纯 Sentry 噪音。

上游已有 issue/PR 但都 open:
- tauri-apps/tao#1180 (issue)
- tauri-apps/tao#1188 (PR,把 panic 软化成 debug log)

在上游 release 修复之前,在 `before_send` 里用
(panic value + 栈含 tao runner 的 frame) 双重匹配精确 drop 这条事件,
避免它继续污染 fatal-issue 面板。匹配规则集中到 `known_upstream_panic`
helper,每条规则带 `<crate>#<issue>` tracker tag,回收时直接 grep 找到
对应 match arm。

附 3 个单元测试覆盖:
- 命中规则 → drop
- panic message 相同但栈不在 tao → 不 drop (防误吞)
- 栈在 tao 但 panic message 不同 → 不 drop (防误吞)

受影响 Sentry: UNICLIPBOARD-RUST-P (4 events / 2 users, Windows
0.7.0→0.10.0)。

(cherry picked from commit e38d53b)

* fix(tray): survive libayatana-appindicator3 dlopen failure on Linux

Linux 用户机器上 libayatana-appindicator3 缺失或其依赖 libayatana-ido3 跟
系统 glib 有 ABI skew(找不到 g_once_init_leave_pointer 等)时,Tauri 的
tray-icon 经 libappindicator-rs 走 dlopen,失败时**抛 panic 而非返回 Err**,
直接撂倒整个进程。run.rs 那一层的 `if let Err(e)` 接不住。

三层防御:

A. uc_tauri::tray::init 用 `catch_unwind` 兜 `TrayIconBuilder::build`,
   panic 时打一条 warn(并明确告诉用户缺哪个包),返回 Ok(()) 让 app
   继续启动 —— 只是少 tray 图标。`is_initialized()` 仍返回 false,所有
   依赖 tray 的菜单更新路径已经 noop,行为自然降级。

B. uc_bootstrap::tracing::known_upstream_panic 加规则
   `libappindicator-rs#dlopen`,按 panic value 前缀匹配把这条事件从
   Sentry 流里 drop。catch_unwind 不会阻止 panic hook 触发,A 已经在
   logs 留下 warn,Sentry 那份纯属噪音。覆盖单元测试包含真实 Sentry
   上看到的多行 value(prefix + 具体 .so 路径与 undefined symbol)。

C. tauri.conf.json 给 deb/rpm bundle 显式声明运行时依赖:
   - deb.depends:   libayatana-appindicator3-1
   - rpm.depends:   libayatana-appindicator-gtk3
   下次发包后 apt/dnf 会自动拉起这个 lib,从源头消灭 A 触发的最常见
   场景。AppImage/源码构建/Arch 仍需 A 兜底(包管理器不在我们手里)。

受影响 Sentry: UNICLIPBOARD-RUST-G(20 events) + -10(5 events),
跨 0.7.0 → 0.10.0,Arch/CachyOS/Zen/Ubuntu 24.10+ 等。

(cherry picked from commit 664ac41)

* ci(alpha-build): install darwin targets onto src-tauri's pinned toolchain

build.yml fixed this in PR #N earlier — alpha-build.yml never copied the
workaround over. dtolnay/rust-toolchain@stable installs `x86_64-apple-darwin`
into stable, but `src-tauri/rust-toolchain.toml` pins cargo to a specific
channel (1.95.0). `cargo build --target x86_64-apple-darwin` resolves the
pinned channel and reports `Target ... is not installed`.

Mirrors the build.yml step verbatim: after dtolnay completes, run
`rustup target add --toolchain <pinned channel> ... x86_64-apple-darwin`
so the target is present in the channel cargo actually uses.

Surfaced by alpha-build run 26074579386 (Build x86_64-apple-darwin failed
at tauri-action, same signature as build.yml's earlier 25960898069 /
25961183688).

(cherry picked from commit 9be3a1c)

* ci(release): let prepare-release base off any branch

prepare-release.yml was hardcoded to ref: main, so iterating a
prerelease on an existing release/v<X> branch (whose commits have
not been merged back to main) would re-bump from main's older
version and clash with the existing release branch on the
"Check release branch does not exist" step.

Add a base_branch input (default: main), thread it through the
checkout step, the PR --base flag, and the PR body. Extend
tag-on-merge.yml to also fire on PRs targeting release/v* — without
this, a PR merged into a release branch never reaches the tag step
because the workflow's branches filter only matched main.

(cherry picked from commit 255172c)

* fix(tray): pre-probe libappindicator3 with libloading before build

664ac41 加的 catch_unwind 兜底在 release 下完全无效 ——
src-tauri/Cargo.toml `[profile.release] panic = "abort"`,rustc 不生成
unwind 表,catch_unwind 无法接住任何 panic。0.10.1-alpha.2 AppImage
在 Arch 上仍然 `Aborted (core dumped)` 验证了这点。

改"事后接 panic" → "事前预探 .so":新增 appindicator_lib_available(),
按上游 libappindicator-sys-0.9.0/src/lib.rs:13 的 Lazy closure 同款
顺序 dlopen 四个候选(`.so.1` × 2 + backcompat `.so` × 2)。全部失败
就 warn + return Ok(()),根本不让 TrayIconBuilder::build 触发上游
Lazy 的 panic!()。is_initialized() 仍返回 false,依赖 tray 的菜单
更新路径已经 noop,降级行为不变。

catch_unwind 保留作为冗余:dev/test profile 是 panic = unwind,
那时还能挡住 builder 内部其他类型的 panic;release 下注释明确说明
它无效,以免后人读到这段代码时被误导。

附带 Cargo.lock 同步:9e76963c bump 时漏更工作空间各 crate 的
version,本地 cargo check 顺手补齐。

受影响 Sentry: UNICLIPBOARD-RUST-G / -10(0.10.1-alpha.2 起仍在刷)。

(cherry picked from commit 3062d86)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Windows] Panic in EventLoopThreadExecutor::execute_in_thread (Re-entrancy / Destroyed state)

2 participants