Skip to content

fix: auto-disable XDP for non-conforming apps#1664

Merged
dengbo11 merged 1 commit into
OpenAtom-Linyaps:masterfrom
reddevillg:invalid_xdp_id
May 18, 2026
Merged

fix: auto-disable XDP for non-conforming apps#1664
dengbo11 merged 1 commit into
OpenAtom-Linyaps:masterfrom
reddevillg:invalid_xdp_id

Conversation

@reddevillg

Copy link
Copy Markdown
Collaborator

Disable XDP integration when the appid does not conform xdp id

Disable XDP integration when the appid does not conform xdp id

Signed-off-by: reddevillg <reddevillg@gmail.com>
@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

deepin pr auto review

你好!我是CodeGeeX。我已仔细审查了你提交的 git diff。这次代码变更的主要目的是在运行容器前校验 AppID 是否符合 XDG Desktop Portal (XDP) 规范,并在不符合时默认禁用 XDP 集成,同时提供了相应的单元测试。

整体来看,代码逻辑清晰,测试用例覆盖较为全面。但在语法逻辑、代码性能和代码安全方面,还有一些可以改进和优化的空间。以下是详细的审查意见:

1. 语法与逻辑

问题:日志提示信息与代码逻辑不匹配

  • 位置: libs/linglong/src/linglong/cli/cli.cpp 第873-876行
  • 描述: 代码中的条件判断是 !options.disableXdp.has_value(),这意味着当用户没有显式指定 disableXdp 参数时,才会进入此分支。然而,日志中却提示用户使用 Use --enable-xdp to override.
  • 分析: 如果用户原本就没有指定该参数,你提示他用 --enable-xdp 去覆盖,这在逻辑上是错位的。根据逻辑,如果用户没有显式配置,程序自动禁用了 XDP,用户如果想强行开启,应该提示他使用开启的参数(假设 CLI 确实提供了 --enable-xdp 选项)。
  • 建议: 确认 CLI 参数的设计。如果确实存在 --enable-xdp 参数,提示是合理的,但建议改为更明确的表述,例如:"Appid '{}' is invalid for XDP, XDP integration is auto-disabled. Use --enable-xdp to force enable it.";如果不存在该参数,请移除提示。

2. 代码性能

问题:不必要的内存动态分配

  • 位置: libs/utils/src/linglong/utils/xdp.h 第20-30行
  • 描述: isValidXdgDesktopPortalId 函数中使用了 std::vector<std::string_view> segments; 来存储按 . 分割的子串。这会导致在堆上动态分配内存。
  • 分析: 对于这种短字符串、高频调用的校验函数,堆分配会带来不必要的性能开销。实际上,你可以完全省去分割和存储的过程,直接在原字符串上进行单次遍历即可完成校验,这不仅消除了动态内存分配,还提升了缓存命中率。
  • 建议: 重构该函数,去掉 std::vector,采用状态机或分段即时校验的方式。见下方优化后的代码示例。

3. 代码安全与健壮性

问题:std::isalnum 的未定义行为风险

  • 位置: libs/utils/src/linglong/utils/xdp.h 第39行和第49行
  • 描述: std::isalnum (以及 <cctype> 中的其他函数) 接收的参数必须是 unsigned charEOF。虽然你已经使用了 static_cast<unsigned char>(c) 进行了转换(这一点做得很好!),但在重构为单次遍历后,需要继续保持这一安全实践。
  • 补充: 如果输入的 appid 包含非 ASCII 字符(如 UTF-8 编码的中文),std::isalnum 的行为可能因平台/locale 而异。对于 AppID,通常期望是纯 ASCII,当前逻辑在遇到非 ASCII 时会返回 false,这是符合预期的。

4. 代码质量

问题:头文件包含冗余

  • 位置: libs/utils/src/linglong/utils/xdp.h
  • 描述: 引入了 <vector><algorithm>。如果按照上述性能优化建议去掉 std::vectorstd::all_of,则这两个头文件可以移除,从而减少不必要的依赖,加快编译速度。

💡 改进后的代码建议

基于以上分析,我为你重构了 xdp.h 中的校验函数。新函数采用单次遍历,无内存分配,逻辑更紧凑:

/*
 * SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
 *
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */

#pragma once

#include <cctype>
#include <string_view>

namespace linglong::utils {

inline bool isValidXdgDesktopPortalId(std::string_view appid) noexcept
{
    if (appid.empty()) {
        return false;
    }

    bool has_dot = false;
    bool segment_valid = false; // 标记当前分段是否至少有一个有效字符
    bool is_last_segment = false;

    for (size_t i = 0; i < appid.size(); ++i) {
        char c = appid[i];

        if (c == '.') {
            if (!segment_valid) {
                // 遇到 '.' 但前面分段为空 (例如 ".." 或 "org..app" 或 ".app")
                return false;
            }
            has_dot = true;
            segment_valid = false; // 重置,准备校验下一个分段
            is_last_segment = false;
        } else {
            // 只要遇到了非 '.' 字符,说明进入了新的分段
            if (!segment_valid) {
                segment_valid = true;
                // 判断是否是最后一个分段:后续字符中不再包含 '.'
                is_last_segment = (appid.find('.', i) == std::string_view::npos);
            }

            bool char_valid = false;
            if (std::isalnum(static_cast<unsigned char>(c)) || c == '_') {
                char_valid = true;
            } else if (c == '-' && is_last_segment) {
                // 仅在最后一个分段允许连字符 '-'
                char_valid = true;
            }

            if (!char_valid) {
                return false;
            }
        }
    }

    // 必须至少包含一个 '.' (保证至少两个分段),且最后一个分段不能为空
    return has_dot && segment_valid;
}

} // namespace linglong::utils

关于 CLI 逻辑的修改建议

针对 cli.cpp 中的提示语,建议修改为:

    const auto &appid = runContext.getTargetID();
    if (!options.disableXdp.has_value() && !utils::isValidXdgDesktopPortalId(appid)) {
        LogW("appid '{}' doesn't conform to XDP ID specification, XDP integration is auto-disabled. "
             "Use --enable-xdp to override if you know what you are doing.",
             appid);
        runOptions.disableXdp = true;
    }

总结

你的单元测试写得非常好,覆盖了各种边界情况(空串、单段、多段、特殊字符位置等)。在采用上述重构代码后,你可以直接运行原有的单元测试,它们应该全部通过。重构后的代码在性能上更优,且不依赖标准库容器的堆分配,更适合作为基础工具函数。

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces a validation check for XDG Desktop Portal IDs to ensure compatibility before enabling XDP integration. It includes a new utility function isValidXdgDesktopPortalId, unit tests for various ID formats, and logic in the CLI to disable XDP with a warning if the ID is invalid. Feedback suggests optimizing the validation function to avoid heap allocations and locale-dependent checks, while also ensuring strict conformance to D-Bus specifications regarding segments starting with digits.

Comment on lines +9 to +12
#include <algorithm>
#include <cctype>
#include <string_view>
#include <vector>

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.

medium

If the optimized implementation of isValidXdgDesktopPortalId (suggested below) is adopted, the <algorithm>, <cctype>, and <vector> headers are no longer necessary, and only <string_view> is required.

Suggested change
#include <algorithm>
#include <cctype>
#include <string_view>
#include <vector>
#include <string_view>

Comment on lines +16 to +51
inline bool isValidXdgDesktopPortalId(std::string_view appid) noexcept
{
std::vector<std::string_view> segments;

size_t start = 0;
for (size_t i = 0; i < appid.size(); ++i) {
if (appid[i] == '.') {
segments.push_back(appid.substr(start, i - start));
start = i + 1;
}
}
segments.push_back(appid.substr(start));

if (segments.size() < 2) {
return false;
}

for (size_t i = 0; i + 1 < segments.size(); ++i) {
if (segments[i].empty()) {
return false;
}
if (!std::all_of(segments[i].begin(), segments[i].end(), [](char c) {
return std::isalnum(static_cast<unsigned char>(c)) || c == '_';
})) {
return false;
}
}

const auto &last = segments.back();
if (last.empty()) {
return false;
}
return std::all_of(last.begin(), last.end(), [](char c) {
return std::isalnum(static_cast<unsigned char>(c)) || c == '_' || c == '-';
});
}

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.

medium

The current implementation of isValidXdgDesktopPortalId is inefficient as it allocates a std::vector and performs multiple passes over the string. It can be implemented in a single pass without heap allocations.

Additionally, std::isalnum is locale-dependent. For protocol-level validation like D-Bus/XDP IDs, which are strictly ASCII, it is safer and more idiomatic to use explicit range checks.

Note: According to the D-Bus and Desktop Entry specifications, segments of a well-known name must not begin with a digit. The current implementation allows this (e.g., org.2example.app). If strict conformance is required, you should add a check to ensure segments do not start with a digit (and update the corresponding test case).

inline bool isValidXdgDesktopPortalId(std::string_view appid) noexcept
{
    if (appid.empty()) {
        return false;
    }

    size_t segmentCount = 0;
    size_t start = 0;
    for (size_t i = 0; i <= appid.size(); ++i) {
        if (i == appid.size() || appid[i] == '.') {
            std::string_view segment = appid.substr(start, i - start);
            if (segment.empty()) {
                return false;
            }

            bool isLast = (i == appid.size());
            for (char c : segment) {
                bool ok = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_');
                if (isLast && c == '-') {
                    ok = true;
                }
                if (!ok) {
                    return false;
                }
            }

            segmentCount++;
            start = i + 1;
        }
    }

    return segmentCount >= 2;
}

@codecov

codecov Bot commented May 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.61538% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
libs/linglong/src/linglong/cli/cli.cpp 0.00% 4 Missing ⚠️
Files with missing lines Coverage Δ
libs/utils/src/linglong/utils/xdp.h 100.00% <100.00%> (ø)
libs/linglong/src/linglong/cli/cli.cpp 1.68% <0.00%> (-0.01%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI 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.

Pull request overview

This PR adds a small utility to validate whether an application ID conforms to the expected XDG desktop portal (XDP) ID format, and uses it in ll-cli run to automatically disable XDP integration for non-conforming app IDs unless the user explicitly overrides via CLI flags.

Changes:

  • Added linglong::utils::isValidXdgDesktopPortalId() helper in libs/utils.
  • Added unit tests covering valid/invalid XDP IDs.
  • Updated ll-cli run path to auto-disable XDP when the resolved target ID is not a valid XDP ID (unless --enable-xdp/--disable-xdp was explicitly set).

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
libs/utils/src/linglong/utils/xdp.h Introduces the XDP ID validation helper.
libs/utils/CMakeLists.txt Adds the new header to the utils library sources list.
libs/linglong/tests/ll-tests/src/linglong/utils/xdp_test.cpp Adds gtest coverage for XDP ID validation behavior.
libs/linglong/tests/ll-tests/CMakeLists.txt Registers the new test file in the ll-tests target.
libs/linglong/src/linglong/cli/cli.cpp Disables XDP integration by default when appid is invalid, with a warning and an override hint.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@dengbo11 dengbo11 requested a review from 18202781743 May 18, 2026 03:22
@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743, dengbo11, reddevillg

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

@dengbo11 dengbo11 merged commit e83168e into OpenAtom-Linyaps:master May 18, 2026
17 checks passed
@reddevillg reddevillg deleted the invalid_xdp_id branch May 18, 2026 05:03
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.

5 participants