Skip to content

fix(accounts): guard userList against unavailable Accounts service - #148

Open
zccrs wants to merge 1 commit into
linuxdeepin:masterfrom
zccrs:fix/accounts-userList-service-guard
Open

fix(accounts): guard userList against unavailable Accounts service#148
zccrs wants to merge 1 commit into
linuxdeepin:masterfrom
zccrs:fix/accounts-userList-service-guard

Conversation

@zccrs

@zccrs zccrs commented Aug 25, 2026

Copy link
Copy Markdown
Member

Problem

DAccountsManager::userList()org.freedesktop.Accounts 不可用时直接解引用空 QArrayDataPointer<QDBusObjectPath>needsDetach(this=0x0)),导致 SIGSEGV(exit 139)。gdb 栈:

#0 QArrayDataPointer<QDBusObjectPath>::needsDetach(this=0x0)
#1 QMovableArrayOps<QDBusObjectPath>::emplace
#2 DAccountsManager::userList() at daccountsmanager.cpp:52
#3 UserModel::UserModel at treeland/src/greeter/usermodel.cpp:64
#4 Helper::init -> QQmlEngine::singletonInstance<UserModel>

treeland 启动时必现:Helper::init 无条件实例化 UserModel QML 单例,dde-system-daemonorg.deepin.dde.Accounts1)因 Go concurrent map 竞态崩溃后,org.freedesktop.Accounts 虽在但 QDBusPendingReply::value() 的解包路径在部分传输下返回 QDBusArgument 而非 QList<QDBusObjectPath>,原有 !isValid 检查不足,遍历空指针列表触发崩溃。

dtk6systemsettings 会自动从本仓库同步,故修复提交至此。

Fix

  • 调用前 QDBusConnection::systemBus().interface()->isServiceRegistered("org.freedesktop.Accounts"),不可用时直接返回 DUnexpected{ServiceUnknown}
  • waitForFinished 后同时检查 isError() || !isValid()
  • const auto value = reply.value() 拷贝后遍历,跳过空 path()

已在 archlinux + accounts-daemon 788 + treeland 验证:原库必 SIGSEGV,补丁库后正常启动。

Log: fix accounts userList SIGSEGV when service unavailable

Summary by Sourcery

Guard account user enumeration against unavailable services and malformed D-Bus responses.

Bug Fixes:

  • Prevent crashes in user listing when the Accounts service is unavailable or returns invalid user object paths.
  • Return an appropriate D-Bus service-unavailable error when the Accounts service cannot be reached.

Enhancements:

  • Expose Accounts service availability through the D-Bus interface and validate pending replies before processing users.

@sourcery-ai

sourcery-ai Bot commented Aug 25, 2026

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Hardens DAccountsManager::userList() against unavailable Accounts services and malformed or invalid D-Bus results, preventing startup SIGSEGV while preserving error reporting.

Sequence diagram for guarded Accounts user listing

sequenceDiagram
    participant UserModel
    participant DAccountsManager
    participant SystemBus as QDBusConnection
    participant Accounts as org.freedesktop.Accounts

    UserModel->>DAccountsManager: userList()
    DAccountsManager->>SystemBus: isServiceRegistered(org.freedesktop.Accounts)
    alt service unavailable
        SystemBus-->>DAccountsManager: false
        DAccountsManager-->>UserModel: DUnexpected ServiceUnknown
    else service available
        SystemBus-->>DAccountsManager: true
        DAccountsManager->>Accounts: listCachedUsers()
        Accounts-->>DAccountsManager: QDBusPendingReply
        DAccountsManager->>DAccountsManager: waitForFinished()
        alt isError() or !isValid()
            DAccountsManager-->>UserModel: DUnexpected D-Bus error
        else valid reply
            DAccountsManager->>DAccountsManager: value()
            DAccountsManager-->>UserModel: QList<quint64>
        end
    end
Loading

File-Level Changes

Change Details Files
Guard the D-Bus user enumeration path when the Accounts service or reply payload is unavailable.
  • Check system-bus registration for org.freedesktop.Accounts before issuing the request and return ServiceUnknown when absent.
  • Treat D-Bus errors and invalid pending replies as failures with propagated error details.
  • Copy the reply value before iteration and skip entries with empty object paths.
src/accounts/daccountsmanager.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

@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

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/accounts/daccountsmanager.cpp" line_range="53-54" />
<code_context>
 DExpected<QList<quint64>> DAccountsManager::userList() const
 {
     Q_D(const DAccountsManager);
+    if (!QDBusConnection::systemBus().interface()->isServiceRegistered(
+            QStringLiteral("org.freedesktop.Accounts"))) {
+        return DUnexpected{ DCORE_NAMESPACE::emplace_tag::USE_EMPLACE,
+                            static_cast<int>(QDBusError::ServiceUnknown),
</code_context>
<issue_to_address>
**issue (testing):** The new guard always checks for `org.freedesktop.Accounts` on the system bus, but unit-test builds define `USE_FAKE_INTERFACE`, causing `DAccountsInterface` to use `com.deepin.daemon.FakeAccounts` on the session bus. The fake service is therefore treated as unavailable, `userList()` returns before calling `listCachedUsers()`, and `tests/accounts/ut-daccountsmanager.cpp` fails because `m_userListTrigger` remains false.

**Triggers:** When the repository's unit tests are built with `USE_FAKE_INTERFACE`.

**Suggested fix:** Use the same service name and bus selected by `DAccountsInterface` under `USE_FAKE_INTERFACE`, or provide a test-compatible service-registration abstraction for this guard.
</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 src/accounts/daccountsmanager.cpp Outdated
@zccrs

zccrs commented Aug 25, 2026

Copy link
Copy Markdown
Member Author

已按 @sourcery-ai[bot] 建议修复:isServiceRegistered 检查现通过 #if defined(USE_FAKE_INTERFACE) 区分 com.deepin.daemon.FakeAccounts(session)与 org.freedesktop.Accounts(system),避免 USE_FAKE_INTERFACE 单测中 m_userListTrigger 失效。已 cmake --build 验证。

@zccrs

zccrs commented Aug 25, 2026

Copy link
Copy Markdown
Member Author

已按建议为 isEmpty() 分支补充 qWarning() << "DAccountsManager::userList: empty QDBusObjectPath skipped",便于定位解包异常时的脏数据,已推送 9eee139

@zccrs

zccrs commented Aug 25, 2026

Copy link
Copy Markdown
Member Author

已细化空路径 qWarning:现输出 index/total 与上下文 "accounts-daemon returned invalid entry",便于定位是第几个用户条目异常,已推送 bd87b0d

@zccrs

zccrs commented Aug 25, 2026

Copy link
Copy Markdown
Member Author

已按反馈重构可读性:新增 DAccountsInterface::isServiceRegistered() const { return m_inter->serviceValid(); }userList() 现以 if (!d->m_dAccountsInter->isServiceRegistered()) 判断,语义清晰且自动适配 USE_FAKE_INTERFACEcom.deepin.daemon.FakeAccounts/sessionBus)与正式环境(org.freedesktop.Accounts/systemBus),不再硬编码服务名。已推送 7063281

@zccrs
zccrs requested a review from 18202781743 August 25, 2026 13:30
18202781743
18202781743 previously approved these changes Aug 26, 2026
@18202781743

Copy link
Copy Markdown
Contributor

先不合,现在dtk向dtk6同步的流程被禁用了,但又没像其它dtk组件一样在dtk5仓库同时维护dtk5和dtk6的打包,需要先处理这个问题,

@zccrs

zccrs commented Aug 27, 2026

Copy link
Copy Markdown
Member Author

Follow-up: DAccountsInterface::isServiceRegistered() no longer uses DDBusInterface::serviceValid().

serviceValid() is filled in by an async NameHasOwner callback. Treeland constructs UserModel (and calls userList()) before QCoreApplication::exec(), so the guard always returned "Accounts service not available" even when org.freedesktop.Accounts was up.

The check is now a blocking QDBusConnectionInterface::isServiceRegistered() on the same connection/service as DAccountsInterface, so it still respects USE_FAKE_INTERFACE and works before the event loop.

DAccountsManager::userList() could SIGSEGV on a null QArrayDataPointer
when ListCachedUsers demarshalling failed. Check service registration
synchronously on the same bus/service as DAccountsInterface so
USE_FAKE_INTERFACE still works, reject isError replies, and skip empty
object paths.

Do not use DDBusInterface::serviceValid(): it is filled by an async
NameHasOwner callback, so callers such as Treeland's UserModel that
invoke userList() before QCoreApplication::exec() always saw the
service as missing.

Log: fix accounts userList SIGSEGV when service unavailable
@zccrs
zccrs force-pushed the fix/accounts-userList-service-guard branch from bb50a86 to d09cf2d Compare August 27, 2026 12:41
@zccrs
zccrs requested a review from 18202781743 August 27, 2026 12:41
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

🤖 AI 代码审查报告

总体评分: 99 分 (通过阈值: 70分)

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 总体评分 99 分,大于 70 分通过阈值。该提交修复了 DAccountsManager::userList() 在 Accounts 服务不可用时的 SIGSEGV 崩溃问题,代码实现与 commit message 描述的修复方案完全一致,逻辑清晰,防御性编程完善,未发现安全漏洞。

🔍 详细分析

1. 语法逻辑 ✅

评价: 优秀 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: 代码语法正确,逻辑清晰。isServiceRegistered() 方法正确使用 QDBusConnectionInterface 同步查询服务注册状态,null 检查完善(if (!iface) return false)。userList() 中服务可用性前置检查、isError() || !isValid() 组合检查、reply.value() 拷贝后遍历、空 path 跳过等逻辑均正确无误。


2. 代码质量 ✅

评价: 优秀 ✅ 通过

潜在问题:

  1. src/accounts/daccountsmanager.cpp:60 - qWarning 日志消息中使用非 ASCII 的 em dash 字符(—),建议替换为 ASCII 连字符(-)

建议: 代码结构清晰,isServiceRegistered() 方法注释详细解释了为何不使用 DDBusInterface::serviceValid() 的异步回调而改用同步查询,上下文充分。qWarning 日志内容合理(记录无效条目的索引和总数),建议将日志中的 em dash(—)替换为 ASCII 连字符(-)以增强日志兼容性。


3. 代码性能 ✅

评价: 优秀 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: 性能良好,资源使用合理。isServiceRegistered() 的同步 D-Bus NameHasOwner 查询开销极小(微秒级),且原代码已有 waitForFinished() 阻塞调用,整体仍为阻塞函数,无额外性能瓶颈。const auto value = reply.value() 的拷贝是必要的安全措施,避免 reply 对象在遍历期间被修改。


4. 代码安全 🔒

评价: 优秀 ✅ 通过

🔐 发现 0 个安全漏洞

安全漏洞详情:
✅ 未发现安全漏洞

建议: 存在0个安全漏洞,安全合规。本次修复实质上增强了安全性:1) 防止了 Accounts 服务不可用时的空指针解引用崩溃;2) 添加了对 D-Bus 返回值的防御性检查(空 path 跳过);3) 错误信息中不包含敏感数据。D-Bus 调用面向系统服务,无用户输入注入风险。


💡 改进建议代码示例

// 建议将 qWarning 中的 em dash 替换为 ASCII 连字符
// 修改前:
qWarning() << "DAccountsManager::userList: empty QDBusObjectPath at index" << i
           << "of" << value.size() << "skipped — accounts-daemon returned invalid entry";

// 修改后:
qWarning() << "DAccountsManager::userList: empty QDBusObjectPath at index" << i
           << "of" << value.size() << "skipped - accounts-daemon returned invalid entry";

本报告由 AI 代码审查工具自动生成

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743, zccrs

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

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