fix(cap_portal): remove unsafe pw::deinit() to prevent global state corruption

pw::init() is guarded by an internal OnceCell (process-global one-shot).
pw::deinit() is unsafe and requires 'only called once per process lifetime
after all PipeWire use has permanently stopped'. Since CapPortal can be
created/destroyed multiple times, calling deinit() from a function-local
scope would prevent re-initialization (OnceCell already consumed) and
violate the unsafe contract.

The 5 early-return error paths in pipewire_thread() that previously
leaked global state are now consistent with the success path — neither
calls pw::deinit(). Process exit reclaims global PipeWire state.
This commit is contained in:
dailz
2026-05-25 14:32:19 +08:00
parent b8026981d2
commit 460a3ee711

View File

@@ -301,7 +301,12 @@ fn pipewire_thread(ctx: PwThreadCtx) {
use std::rc::Rc;
use pw::spa::param::video::VideoInfoRaw;
// 初始化 PipeWire 库,必须在任何 PipeWire 操作之前调用
// 初始化 PipeWire 进程全局库。
//
// pipewire-rs 内部使用 OnceCell 保护 pw::init(),确保只调用一次。
// pw::deinit() 是 unsafe 且要求"进程生命周期内仅调用一次,且所有
// PipeWire 使用已停止"。由于 CapPortal 可被多次创建销毁,此函数
// 不调用 pw::deinit()——进程退出时全局状态由 OS 回收。
pw::init();
// 解构上下文,取出所有必要资源
@@ -607,10 +612,7 @@ fn pipewire_thread(ctx: PwThreadCtx) {
// run() returned — _shutdown_source drops first (reverse declaration order),
// which unregisters the callback from the loop. Then mainloop drops.
// No dangling raw pointers are possible.
// SAFETY: pipewire has been initialized with pw::init() above and all
// PipeWire resources (mainloop, stream) have been dropped.
unsafe { pw::deinit() };
// PipeWire global state is intentionally not deinitialized here — see pw::init() comment above.
}
/// 将四个 ASCII 字符编码为 32 位 FourCC (Four Character Code) 标识符