Skip to content

fix(editor): Disconnect D-Bus signals in TextEdit destructor to preve…#426

Merged
deepin-bot[bot] merged 1 commit intolinuxdeepin:masterfrom
dengzhongyuan365-dev:master
Mar 3, 2026
Merged

fix(editor): Disconnect D-Bus signals in TextEdit destructor to preve…#426
deepin-bot[bot] merged 1 commit intolinuxdeepin:masterfrom
dengzhongyuan365-dev:master

Conversation

@dengzhongyuan365-dev
Copy link
Contributor

@dengzhongyuan365-dev dengzhongyuan365-dev commented Mar 3, 2026

…nt callbacks to destroyed objects

  • Added disconnection of D-Bus signals for gesture and audio events in the TextEdit destructor.
  • Ensured proper handling based on system version and Qt version to avoid potential crashes.

Log: Prevent callbacks to destroyed TextEdit instances by disconnecting D-Bus signals.

bug: https://pms.uniontech.com/bug-view-350765.html

Summary by Sourcery

Bug Fixes:

  • Prevent crashes caused by D-Bus gesture and audio callbacks targeting destroyed TextEdit instances by disconnecting their signals in the destructor.

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: dengzhongyuan365-dev

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
Copy link

sourcery-ai bot commented Mar 3, 2026

Reviewer's Guide

This PR updates the TextEdit destructor to explicitly disconnect gesture and audio-related D-Bus signal handlers based on system and Qt versions, preventing callbacks to already-destroyed TextEdit instances and eliminating a crash risk on teardown.

Sequence diagram for TextEdit destruction and D-Bus signal disconnection

sequenceDiagram
    participant TextEdit
    participant Utils
    participant QDBusConnection
    participant SystemBus
    participant SessionBus
    participant DBusGestureService
    participant DBusAudioService

    TextEdit->>TextEdit: ~TextEdit()
    TextEdit->>Utils: getSystemVersion()
    Utils-->>TextEdit: SystemVersion

    TextEdit->>QDBusConnection: sessionBus()
    QDBusConnection-->>TextEdit: dbus

    alt systemVersion is V23
        TextEdit->>SystemBus: disconnect(org.deepin.dde.Gesture1, /org/deepin/dde/Gesture1, org.deepin.dde.Gesture1, Event, this, fingerZoom(QString, QString, int))
        SystemBus-->>DBusGestureService: unregister handler for fingerZoom
    else other systemVersion
        TextEdit->>SystemBus: disconnect(com.deepin.daemon.Gesture, /com/deepin/daemon/Gesture, com.deepin.daemon.Gesture, Event, this, fingerZoom(QString, QString, int))
        SystemBus-->>DBusGestureService: unregister handler for fingerZoom
    end

    alt Qt version >= 6.0.0
        TextEdit->>SessionBus: disconnect(org.deepin.dde.Audio1, /org/deepin/dde/Audio1, org.deepin.dde.Audio1, PortEnabledChanged, this, onAudioPortEnabledChanged(quint32, QString, bool))
        SessionBus-->>DBusAudioService: unregister handler for onAudioPortEnabledChanged
    else Qt version < 6.0.0
        TextEdit->>SessionBus: disconnect(com.deepin.daemon.Audio, /com/deepin/daemon/Audio, com.deepin.daemon.Audio, PortEnabledChanged, this, onAudioPortEnabledChanged(quint32, QString, bool))
        SessionBus-->>DBusAudioService: unregister handler for onAudioPortEnabledChanged
    end

    TextEdit-->>TextEdit: continue destructor teardown without pending callbacks
Loading

Class diagram for updated TextEdit destructor D-Bus cleanup

classDiagram
    class TextEdit {
        +TextEdit(QWidget *parent)
        +~TextEdit()
        -QAbstractAnimation *m_scrollAnimation
        +void fingerZoom(QString device, QString gesture, int value)
        +void onAudioPortEnabledChanged(quint32 port, QString name, bool enabled)
    }

    class Utils {
        <<static>>
        +SystemVersion getSystemVersion()
        <<enum>> SystemVersion
        +SystemVersion V23
    }

    class QDBusConnection {
        +static QDBusConnection sessionBus()
        +static QDBusConnection systemBus()
        +bool disconnect(QString service, QString path, QString interface, QString name, QObject *receiver, const char *slot)
    }

    class DBusGestureService_V23 {
        +QString serviceName = org.deepin.dde.Gesture1
        +QString path = /org/deepin/dde/Gesture1
        +QString interfaceName = org.deepin.dde.Gesture1
        +QString signalName = Event
    }

    class DBusGestureService_Default {
        +QString serviceName = com.deepin.daemon.Gesture
        +QString path = /com/deepin/daemon/Gesture
        +QString interfaceName = com.deepin.daemon.Gesture
        +QString signalName = Event
    }

    class DBusAudioService_Qt6 {
        +QString serviceName = org.deepin.dde.Audio1
        +QString path = /org/deepin/dde/Audio1
        +QString interfaceName = org.deepin.dde.Audio1
        +QString signalName = PortEnabledChanged
    }

    class DBusAudioService_Qt5 {
        +QString serviceName = com.deepin.daemon.Audio
        +QString path = /com/deepin/daemon/Audio
        +QString interfaceName = com.deepin.daemon.Audio
        +QString signalName = PortEnabledChanged
    }

    TextEdit ..> Utils : uses getSystemVersion
    TextEdit ..> QDBusConnection : disconnects signals in destructor
    TextEdit ..> DBusGestureService_V23 : disconnects fingerZoom
    TextEdit ..> DBusGestureService_Default : disconnects fingerZoom
    TextEdit ..> DBusAudioService_Qt6 : disconnects onAudioPortEnabledChanged
    TextEdit ..> DBusAudioService_Qt5 : disconnects onAudioPortEnabledChanged
Loading

File-Level Changes

Change Details Files
Disconnect gesture-related D-Bus signals in the TextEdit destructor based on system version.
  • Obtain the session bus QDBusConnection at the start of the destructor for reuse.
  • Use Utils::getSystemVersion() to select between V23-specific and default gesture D-Bus service, object path, and interface.
  • Call disconnect on the appropriate gesture D-Bus service to remove the fingerZoom(QString, QString, int) slot connection before object destruction.
src/editor/dtextedit.cpp
Disconnect audio-related D-Bus signals in the TextEdit destructor with Qt-version-specific service names.
  • Use a Qt version check macro (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) to branch between org.deepin.dde.Audio1 and com.deepin.daemon.Audio service/interface names.
  • Call disconnect on the appropriate audio D-Bus service to remove the onAudioPortEnabledChanged(quint32, QString, bool) slot connection before object destruction.
  • Ensure D-Bus disconnection happens prior to existing destructor logic, such as scroll animation teardown.
src/editor/dtextedit.cpp

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

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • The QDBusConnection dbus = QDBusConnection::sessionBus(); local variable is misleading since you immediately call the static systemBus()/sessionBus() methods on it; consider either using the static QDBusConnection::systemBus()/sessionBus() directly or storing the specific bus you actually want to disconnect from.
  • The new destructor block has inconsistent indentation (extra leading spaces before the comment, switch, and #if), which makes the code harder to scan compared to the surrounding style; aligning it with the existing destructor body would improve readability.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `QDBusConnection dbus = QDBusConnection::sessionBus();` local variable is misleading since you immediately call the static `systemBus()`/`sessionBus()` methods on it; consider either using the static `QDBusConnection::systemBus()`/`sessionBus()` directly or storing the specific bus you actually want to disconnect from.
- The new destructor block has inconsistent indentation (extra leading spaces before the comment, switch, and `#if`), which makes the code harder to scan compared to the surrounding style; aligning it with the existing destructor body would improve readability.

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.

…nt callbacks to destroyed objects

- Added disconnection of D-Bus signals for gesture and audio events in the TextEdit destructor.
- Ensured proper handling based on system version and Qt version to avoid potential crashes.

Log: Prevent callbacks to destroyed TextEdit instances by disconnecting D-Bus signals.

bug: https://pms.uniontech.com/bug-view-350765.html
@deepin-ci-robot
Copy link

deepin pr auto review

这段代码主要是在 TextEdit 类的析构函数中添加了对 D-Bus 信号的断开连接逻辑,以防止在对象销毁后 D-Bus 回调继续访问已销毁的对象(悬空指针/野指针)。这是一个很好的防御性编程实践。

以下是对这段代码的详细审查和改进建议:

1. 代码逻辑与安全性

优点:

  • 防止野指针:在析构函数中断开信号槽连接是必须的,特别是对于跨进程通信(D-Bus)。如果不断开,当 D-Bus 信号到达时,Qt 会尝试调用已销毁对象的槽函数,导致程序崩溃。
  • 版本兼容:代码使用了 Utils::getSystemVersion()QT_VERSION_CHECK 来处理不同系统和 Qt 版本的接口差异,逻辑清晰。

问题与改进建议:

  1. D-Bus 连接对象的生命周期与一致性

    • 问题:代码中声明了 QDBusConnection dbus = QDBusConnection::sessionBus();,但在断开连接时却使用了 dbus.systemBus()。这是一个严重的逻辑错误。sessionBus(会话总线)和 systemBus(系统总线)是两个完全不同的 D-Bus 实例。
    • 后果:如果手势信号实际上连接在 sessionBus 上,这里的 disconnect 调用将无效,无法断开连接,依然存在崩溃风险。
    • 建议:请确认手势服务是注册在系统总线还是会话总线上。根据代码中的 Audio 服务使用的是 sessionBus,手势服务通常也是用户态服务,大概率也应该使用 sessionBus。请务必检查并统一。
  2. 断开连接的可靠性检查

    • 问题QDBusConnection::disconnect 的返回值是 bool,表示是否成功找到并断开了连接。当前代码忽略了返回值。
    • 建议:虽然析构函数中即使断开失败也不应抛出异常或阻塞,但建议添加 qWarning() 记录断开失败的情况,便于调试。如果断开失败,通常意味着连接时使用的参数与断开时不一致。
  3. 代码风格与格式

    • 问题:缩进不一致。例如 // Disconnect D-Bus signals... 这行的缩进比其他代码多。
    • 建议:统一缩进(通常为 4 个空格),保持代码整洁。

2. 代码性能

  • 析构函数中的性能:析构函数的执行频率相对较低,且 D-Bus 断开操作主要涉及字符串匹配和移除回调指针,性能开销极小,可以忽略不计。这部分代码不需要为了性能进行复杂的优化。

3. 改进后的代码示例

假设手势服务确实应该连接在 sessionBus 上(请务必核实),以下是修正了缩进、总线类型一致性,并增加了日志记录的改进代码:

TextEdit::~TextEdit()
{
    qDebug() << "Destroying TextEdit component";

    // Disconnect D-Bus signals to prevent callbacks to destroyed object
    
    // 修正:统一使用 sessionBus,除非手势服务明确在 systemBus 上
    QDBusConnection sessionBus = QDBusConnection::sessionBus();

    // 1. 断开手势信号
    bool disconnectedGesture = false;
    switch (Utils::getSystemVersion()) {
    case Utils::V23:
        disconnectedGesture = sessionBus.disconnect("org.deepin.dde.Gesture1",
                                                    "/org/deepin/dde/Gesture1", 
                                                    "org.deepin.dde.Gesture1",
                                                    "Event",
                                                    this, SLOT(fingerZoom(QString, QString, int)));
        break;
    default:
        disconnectedGesture = sessionBus.disconnect("com.deepin.daemon.Gesture",
                                                    "/com/deepin/daemon/Gesture", 
                                                    "com.deepin.daemon.Gesture",
                                                    "Event",
                                                    this, SLOT(fingerZoom(QString, QString, int)));
        break;
    }

    if (!disconnectedGesture) {
        // 使用 qWarning 而不是 qDebug,因为断开失败可能意味着潜在的逻辑错误
        qWarning() << "Failed to disconnect Gesture signal in TextEdit destructor.";
    }

    // 2. 断开音频信号
    bool disconnectedAudio = false;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
    disconnectedAudio = sessionBus.disconnect("org.deepin.dde.Audio1",
                                "/org/deepin/dde/Audio1", 
                                "org.deepin.dde.Audio1",
                                "PortEnabledChanged",
                                this, SLOT(onAudioPortEnabledChanged(quint32, QString, bool)));
#else
    disconnectedAudio = sessionBus.disconnect("com.deepin.daemon.Audio",
                                "/com/deepin/daemon/Audio", 
                                "com.deepin.daemon.Audio",
                                "PortEnabledChanged",
                                this, SLOT(onAudioPortEnabledChanged(quint32, QString, bool)));
#endif

    if (!disconnectedAudio) {
        qWarning() << "Failed to disconnect Audio signal in TextEdit destructor.";
    }

    // 原有逻辑
    if (m_scrollAnimation != nullptr) {
        qDebug() << "m_scrollAnimation is not null";
        if (m_scrollAnimation->state() != QAbstractAnimation::Stopped) {
            // ...
        }
    }
}

总结

这段代码在安全性上的初衷是正确的,但在实现细节上存在 sessionBussystemBus 混用 的严重逻辑风险。请务必修正这一点,否则无法达到防止崩溃的目的。同时,增加断开结果的日志记录有助于排查问题。

@dengzhongyuan365-dev
Copy link
Contributor Author

/merge

@deepin-bot
Copy link
Contributor

deepin-bot bot commented Mar 3, 2026

This pr cannot be merged! (status: unstable)

@dengzhongyuan365-dev
Copy link
Contributor Author

/forcemerge

@deepin-bot
Copy link
Contributor

deepin-bot bot commented Mar 3, 2026

This pr force merged! (status: unstable)

@deepin-bot deepin-bot bot merged commit 0d973f1 into linuxdeepin:master Mar 3, 2026
19 of 20 checks passed
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.

3 participants