Skip to content

fix: handle X server disconnection gracefully#1649

Closed
fly602 wants to merge 1 commit into
linuxdeepin:masterfrom
fly602:master
Closed

fix: handle X server disconnection gracefully#1649
fly602 wants to merge 1 commit into
linuxdeepin:masterfrom
fly602:master

Conversation

@fly602

@fly602 fly602 commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

When X server is killed (e.g., during init 3 to init 5 switch), libX11's default I/O error handler calls exit(), bypassing Qt's normal shutdown. This causes plugins to be destroyed during global destructors when objects are already partially destroyed, leading to SIGSEGV.

Changes made:

  1. Added X11 package dependency to CMakeLists.txt for Xlib headers and linking
  2. Implemented custom X I/O error handler that calls QCoreApplication::quit() instead of exit()
  3. Added SIGPIPE signal handler to prevent crashes when X pipe is broken
  4. Handlers are installed only on xcb platform, not needed on Wayland

This ensures plugins receive aboutToQuit signal and can clean up properly.

Log: Fixed crash when X server disconnects by installing custom error handlers

Influence:

  1. Test graceful shutdown when X server is terminated (init 3 to init 5 switch)
  2. Verify no SIGSEGV occurs during X server disconnection
  3. Confirm application exits cleanly with proper plugin cleanup
  4. Verify fix does not affect Wayland sessions
  5. Test that aboutToQuit signal fires correctly for plugin cleanup

fix: 优雅处理X服务器断开连接

当X服务器被终止时(例如从init 3切换到init 5),libX11的默认I/O错误处理器
会调用exit(),绕过Qt的正常关闭流程。这导致插件在全局析构函数中被销毁,此
时对象已部分销毁,从而引发SIGSEGV崩溃。

修改内容:

  1. 在CMakeLists.txt中添加X11包依赖,引入Xlib头文件和链接库
  2. 实现自定义X I/O错误处理器,调用QCoreApplication::quit()替代exit()
  3. 添加SIGPIPE信号处理器,防止X管道断开时崩溃
  4. 仅在xcb平台安装处理器,Wayland不需要

这确保插件能收到aboutToQuit信号并正确清理资源。

Log: 通过安装自定义错误处理器修复X服务器断开时的崩溃问题

Influence:

  1. 测试X服务器终止时的优雅关闭(init 3到init 5切换)
  2. 验证X服务器断开时不会出现SIGSEGV崩溃
  3. 确认应用程序能正常退出并正确清理插件
  4. 验证修复不影响Wayland会话
  5. 测试aboutToQuit信号是否正确触发以清理插件

PMS: BUG-363347

Summary by Sourcery

Handle X server disconnections gracefully to avoid crashes and ensure clean Qt shutdown.

Bug Fixes:

  • Prevent SIGSEGV on X server disconnection by replacing libX11's default I/O error exit path with a Qt-driven shutdown.
  • Avoid crashes from broken X pipes by handling SIGPIPE and triggering an orderly application exit.

Build:

  • Add X11 pkg-config dependency and link against X11 for Xlib error handling support.

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: fly602

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai

sourcery-ai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Reviewer's Guide

Installs custom X11 I/O and SIGPIPE handlers (only on xcb) so X server disconnection leads to a clean Qt shutdown instead of an immediate exit, and adds X11 as a build dependency.

Sequence diagram for graceful shutdown on X server disconnection

sequenceDiagram
    participant XServer
    participant libX11
    participant dde_shell_main as dde_shell_main
    participant QCoreApplication
    participant PluginManager

    dde_shell_main->>libX11: XSetIOErrorHandler(xio_error_handler)

    XServer-->>libX11: [connection broken]
    libX11->>dde_shell_main: xio_error_handler(Display)
    dde_shell_main->>QCoreApplication: QCoreApplication::quit()
    QCoreApplication-->>PluginManager: aboutToQuit
    PluginManager->>PluginManager: cleanup_plugins()
    QCoreApplication-->>dde_shell_main: exec() returns
    dde_shell_main->>dde_shell_main: exit main()

    Note over dde_shell_main,QCoreApplication: Custom handler avoids libX11 calling exit() directly
Loading

Flow diagram for installing X11 handlers only on xcb platform

flowchart TD
    A[main] --> B[QGuiApplication::platformName]
    B --> C{platformName starts with xcb}
    C -- yes --> D["XSetIOErrorHandler(xio_error_handler)"]
    D --> E[setup sigaction for SIGPIPE with sigpipe_handler]
    C -- no --> F[Skip X11 handlers]
    E --> G[a.exec]
    F --> G[a.exec]
Loading

File-Level Changes

Change Details Files
Install custom X11 I/O error handler to map X server disconnects to QCoreApplication::quit() instead of process exit.
  • Include Xlib headers in main.cpp to access X11 error handling APIs.
  • Define xio_error_handler that logs a critical message and calls QCoreApplication::quit() when an X I/O error occurs.
  • Register xio_error_handler via XSetIOErrorHandler when running on the xcb platform backend.
shell/main.cpp
Add SIGPIPE handling on xcb so broken X pipes trigger graceful shutdown instead of crashes.
  • Define sigpipe_handler that logs a critical message and calls QCoreApplication::quit() on SIGPIPE.
  • Install a SIGPIPE handler using sigaction only when the platform name starts with "xcb".
shell/main.cpp
Introduce X11 as a required build-time dependency for the shell and link against it.
  • Add pkg_check_modules(X11 REQUIRED IMPORTED_TARGET x11) to locate X11 via pkg-config.
  • Link dde-shell target against PkgConfig::X11 alongside existing dependencies.
shell/CMakeLists.txt

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The SIGPIPE handler currently calls qCCritical and QCoreApplication::quit(), both of which are not async-signal-safe; consider replacing this with setting a std::atomic<bool>/sig_atomic_t flag and reacting in the main event loop instead of doing complex work in the signal handler.
  • Including <X11/Xlib.h> unconditionally and adding a REQUIRED X11 pkg-config dependency can break builds on platforms without X11 even when only Wayland is used; consider wrapping the X11-specific code in preprocessor guards and making the X11 dependency optional or conditional on an X11 build option.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The SIGPIPE handler currently calls `qCCritical` and `QCoreApplication::quit()`, both of which are not async-signal-safe; consider replacing this with setting a `std::atomic<bool>`/`sig_atomic_t` flag and reacting in the main event loop instead of doing complex work in the signal handler.
- Including `<X11/Xlib.h>` unconditionally and adding a REQUIRED X11 pkg-config dependency can break builds on platforms without X11 even when only Wayland is used; consider wrapping the X11-specific code in preprocessor guards and making the X11 dependency optional or conditional on an X11 build option.

## Individual Comments

### Comment 1
<location path="shell/main.cpp" line_range="66-68" />
<code_context>
+    return 0;
+}
+
+static void sigpipe_handler(int /*sig*/)
+{
+    qCCritical(dsLog) << "Received SIGPIPE, shutting down gracefully.";
+    QCoreApplication::quit();
+}
</code_context>
<issue_to_address>
**issue (bug_risk):** Avoid non-async-signal-safe work in the SIGPIPE handler.

`qCCritical` and `QCoreApplication::quit()` are not async-signal-safe: they depend on Qt internals, likely heap allocations and locks, which must not be used in a signal handler. Instead, have the handler set an `std::atomic<bool>`/`sig_atomic_t` flag or write to a self-pipe, and then perform logging and `quit()` from the main event loop (e.g. via `QSocketNotifier` or a timer). The current approach risks undefined behavior in rare, hard-to-debug scenarios.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread shell/main.cpp Outdated
Comment on lines +66 to +68
static void sigpipe_handler(int /*sig*/)
{
qCCritical(dsLog) << "Received SIGPIPE, shutting down gracefully.";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): Avoid non-async-signal-safe work in the SIGPIPE handler.

qCCritical and QCoreApplication::quit() are not async-signal-safe: they depend on Qt internals, likely heap allocations and locks, which must not be used in a signal handler. Instead, have the handler set an std::atomic<bool>/sig_atomic_t flag or write to a self-pipe, and then perform logging and quit() from the main event loop (e.g. via QSocketNotifier or a timer). The current approach risks undefined behavior in rare, hard-to-debug scenarios.

When X server is killed (e.g., during init 3 to init 5 switch), libX11's
default I/O error handler calls exit(), bypassing Qt's normal shutdown.
This causes plugins to be destroyed during global destructors when
objects are already partially destroyed, leading to SIGSEGV.

Changes made:
1. Added X11 package dependency to CMakeLists.txt for Xlib headers and
linking
2. Implemented custom X I/O error handler that calls
QCoreApplication::quit() instead of exit()
3. Added SIGPIPE signal handler to prevent crashes when X pipe is broken
4. Handlers are installed only on xcb platform, not needed on Wayland

This ensures plugins receive aboutToQuit signal and can clean up
properly.

Log: Fixed crash when X server disconnects by installing custom error
handlers

Influence:
1. Test graceful shutdown when X server is terminated (init 3 to init
5 switch)
2. Verify no SIGSEGV occurs during X server disconnection
3. Confirm application exits cleanly with proper plugin cleanup
4. Verify fix does not affect Wayland sessions
5. Test that aboutToQuit signal fires correctly for plugin cleanup

fix: 优雅处理X服务器断开连接

当X服务器被终止时(例如从init 3切换到init 5),libX11的默认I/O错误处理器
会调用exit(),绕过Qt的正常关闭流程。这导致插件在全局析构函数中被销毁,此
时对象已部分销毁,从而引发SIGSEGV崩溃。

修改内容:
1. 在CMakeLists.txt中添加X11包依赖,引入Xlib头文件和链接库
2. 实现自定义X I/O错误处理器,调用QCoreApplication::quit()替代exit()
3. 添加SIGPIPE信号处理器,防止X管道断开时崩溃
4. 仅在xcb平台安装处理器,Wayland不需要

这确保插件能收到aboutToQuit信号并正确清理资源。

Log: 通过安装自定义错误处理器修复X服务器断开时的崩溃问题

Influence:
1. 测试X服务器终止时的优雅关闭(init 3到init 5切换)
2. 验证X服务器断开时不会出现SIGSEGV崩溃
3. 确认应用程序能正常退出并正确清理插件
4. 验证修复不影响Wayland会话
5. 测试aboutToQuit信号是否正确触发以清理插件

PMS: BUG-363347
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:95分

■ 【总体评价】

代码完美解决了X server断连导致的段错误及SIGPIPE死锁问题
逻辑严密、注释详尽且符合异步信号安全规范,无明显缺陷

■ 【详细分析】

  • 1.语法逻辑(完全正确)✓
    shell/CMakeLists.txt中强制引入X11依赖是合理的,因为shell/main.cpp中直接调用了XSetIOErrorHandler等X11 API,编译期必须存在X11库。运行时通过QGuiApplication::platformName()进行判断,准确区分了XCB与Wayland环境下的处理路径,逻辑闭环完整。
    建议:可考虑使用动态加载方式彻底解耦X11编译依赖,但当前方案在UOS环境下完全可接受。
  • 2.代码质量(优秀)✓
    注释质量极高,清晰阐述了BUG的根因(_XDefaultIOError调用exit()绕过Qt析构导致SIGSEGV)以及修复原理。在sigpipe_handler中特别标注了禁止调用非异步信号安全函数的原因,展现了深厚的系统编程功底。
    建议:保持这种高质量的注释风格。
  • 3.代码性能(高效)✓
    仅在应用启动时执行一次字符串前缀匹配和两个系统调用(XSetIOErrorHandlersigaction),时间复杂度为O(1),无任何资源泄漏或不必要的轮询开销。
    建议:无需优化。
  • 4.代码安全(存在0个安全漏洞)✓
    漏洞对比统计:新增漏洞 0 个,减少漏洞 1 个,持平 0 个
    成功修复了原有的SIGPIPE信号处理不当导致的死锁漏洞,且新代码未引入任何命令注入、内存越界或权限绕过等安全风险。信号处理函数严格遵循了异步信号安全规范。
    建议:继续保持对底层系统调用的安全审查。

■ 【改进建议代码示例】

// 当前代码已非常优秀,若需进一步提升跨平台编译的隔离性,
// 可将X11头文件引用及函数调用通过宏进行隔离(非必须):
#ifdef QT_NO_XCB
// Wayland-only build path (if X11 headers are completely absent)
#else
#include <X11/Xlib.h>

static int xio_error_handler(Display * /*dpy*/)
{
    qCCritical(dsLog) << "X I/O error detected, shutting down gracefully.";
    QCoreApplication::quit();
    return 0;
}
#endif

// 在 main 函数中:
#ifndef QT_NO_XCB
    if (QGuiApplication::platformName().startsWith(QStringLiteral("xcb"))) {
        XSetIOErrorHandler(xio_error_handler);

        struct sigaction sa;
        memset(&sa, 0, sizeof(sa));
        sa.sa_handler = sigpipe_handler;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = 0;
        sigaction(SIGPIPE, &sa, nullptr);
    }
#endif

@fly602 fly602 closed this Jun 24, 2026
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.

2 participants