Skip to content

fix: prevent indefinite blocking in fetchWindowPreview pipe read#1487

Merged
deepin-bot[bot] merged 1 commit intolinuxdeepin:masterfrom
yixinshark:fix-readblock
Mar 7, 2026
Merged

fix: prevent indefinite blocking in fetchWindowPreview pipe read#1487
deepin-bot[bot] merged 1 commit intolinuxdeepin:masterfrom
yixinshark:fix-readblock

Conversation

@yixinshark
Copy link
Contributor

@yixinshark yixinshark commented Mar 7, 2026

When KWin's screenshot service encounters an internal error, it may hold the write end of the pipe open without writing any data and without closing it. In this case, the previous blocking QFile::read() would wait forever, hanging the taskbar process.

Three issues are fixed in fetchWindowPreview():

  1. Replace pipe() with pipe2(fd, O_CLOEXEC) to prevent the write fd from being inherited by child processes, which would also cause read() to block indefinitely.

  2. Replace the blocking QFile::read() with a poll()-based read loop with a 5-second timeout. If KWin stalls or the pipe produces no data within the timeout, the function aborts gracefully and returns an empty QPixmap instead of hanging.

  3. Fix the read buffer size calculation: use imageHeight * imageStride instead of imageWidth * imageHeight * bpp / 8. imageStride is the actual bytes-per-row (including alignment padding) as reported by KWin, and may be larger than width * bpp/8. The old calculation could result in reading too few bytes, leading to an out-of-bounds access when constructing QImage. Also added image.copy() to ensure the QImage owns its data independently of the fileContent buffer.

当 KWin 截图服务发生内部异常时,可能持有管道写端却不写入任何数据
也不关闭,导致原先的阻塞式 QFile::read() 永久等待,任务栏进程卡死。

本次修复了 fetchWindowPreview() 中的三个问题:

  1. pipe() 改为 pipe2(fd, O_CLOEXEC),防止写端 fd 被 fork 出的子进程继承,否则子进程持有写端也会导致 read() 永久阻塞。

  2. 将阻塞式 QFile::read() 替换为带 5 秒超时的 poll() 读取循环。 若 KWin 卡顿或管道在超时内无数据,函数会提前退出并返回空的 QPixmap,而不是使进程永久挂起。

  3. 修正读取缓冲区大小计算:使用 imageHeight * imageStride 而非 imageWidth * imageHeight * bpp / 8。imageStride 是 KWin 返回的 每行实际字节数(含内存对齐 padding),可能大于 width*bpp/8。 原来的计算会导致读取字节数偏小,在构造 QImage 时发生越界访问。 同时添加 image.copy() 确保 QImage 独立持有数据。

Log: prevent indefinite blocking in fetchWindowPreview pipe read

Summary by Sourcery

Prevent window preview fetching from hanging when reading from the KWin screenshot pipe and ensure image data is fully and safely read.

Bug Fixes:

  • Avoid indefinite blocking when reading from the KWin screenshot pipe by adding a timeout-based polling loop.
  • Fix incorrect read buffer sizing for window preview images to prevent out-of-bounds access and incomplete image data.

Enhancements:

  • Use close-on-exec pipes for the KWin screenshot communication channel to avoid file descriptor leaks into child processes.
  • Ensure QImage used for window previews owns its data via a deep copy before creating the pixmap.

@sourcery-ai
Copy link

sourcery-ai bot commented Mar 7, 2026

Reviewer's Guide

Refactors fetchWindowPreview()’s pipe handling and image read logic to prevent indefinite blocking and out-of-bounds access by using CLOEXEC pipes, a poll() + timeout-based read loop sized by imageStride, and ensuring the QImage owns its data via a deep copy.

File-Level Changes

Change Details Files
Prevent indefinite blocking on the pipe used to read window preview image data.
  • Replaced pipe() with pipe2(..., O_CLOEXEC) so the write end is not inherited by child processes, avoiding situations where read() never sees EOF.
  • Removed QFile-based blocking read and instead read directly from the pipe file descriptor.
  • Added a poll()-based loop with a 5-second timeout around read() so that if KWin stalls or never writes/ closes the pipe, the function logs a warning and aborts the read instead of hanging.
  • Added checks for poll errors (including POLLERR, POLLNVAL) and read errors, logging appropriate warnings and exiting gracefully on failure.
  • Ensured the read file descriptor is always closed once reading is complete or aborted.
panels/dock/taskmanager/x11preview.cpp
Correct the image buffer sizing and ensure safe QImage construction.
  • Replaced the previous buffer size calculation based on width * height * bpp/8 with imageHeight * imageStride, matching what the compositor reports as bytes per row including padding.
  • Allocated a QByteArray of the exact expected size and tracked the total number of bytes read, validating that the full expected size was received before constructing the QImage.
  • Logged a warning and returned an empty QPixmap if the data read is incomplete, avoiding constructing a QImage with invalid/out-of-bounds backing data.
  • Constructed QImage using the buffer pointer and imageStride, then invoked image.copy() before creating the QPixmap so that QImage owns its data independently of the QByteArray storage.
panels/dock/taskmanager/x11preview.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 found 2 issues, and left some high level feedback:

  • The new poll/read loop will still block the UI thread for up to 5 seconds; consider moving this logic off the main thread or using a shorter timeout with an early abort to reduce perceived freezes when KWin stalls.
  • In the poll/read loop, it may be safer to explicitly handle EINTR for both poll and read (e.g., by retrying) so that transient signal interruptions don’t cause spurious failures or early aborts.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new poll/read loop will still block the UI thread for up to 5 seconds; consider moving this logic off the main thread or using a shorter timeout with an early abort to reduce perceived freezes when KWin stalls.
- In the poll/read loop, it may be safer to explicitly handle EINTR for both poll and read (e.g., by retrying) so that transient signal interruptions don’t cause spurious failures or early aborts.

## Individual Comments

### Comment 1
<location path="panels/dock/taskmanager/x11preview.cpp" line_range="121" />
<code_context>
-    QImage image(reinterpret_cast<uchar *>(fileContent.data()), imageWidth, imageHeight, imageStride, qimageFormat);
-    // close read
+    // imageStride 是每行实际字节数(含内存对齐 padding),必须用它而非 width*bpp/8
+    qsizetype expectedSize = static_cast<qsizetype>(imageHeight) * imageStride;
+    QByteArray fileContent(expectedSize, Qt::Uninitialized);
+    qsizetype totalRead = 0;
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Consider bounding `expectedSize` to avoid excessive allocations or overflow risk for malformed inputs.

If `imageHeight` or `imageStride` is unexpectedly large (e.g. from corrupted/hostile input), this can trigger a huge `QByteArray` allocation, causing memory exhaustion or failure. Add a sanity check on `expectedSize` (e.g., cap it based on screen size or a hard max buffer) and abort when it exceeds that limit.

Suggested implementation:

```cpp
    QImage::Format qimageFormat = static_cast<QImage::Format>(imageFormat);

    // imageStride 是每行实际字节数(含内存对齐 padding),必须用它而非 width*bpp/8
    // 为避免恶意 / 损坏输入导致过大分配,这里做上限检查
    constexpr qsizetype kMaxPreviewBufferBytes = 64 * 1024 * 1024; // 64 MiB 上限,可视需要调整

    if (imageHeight <= 0 || imageStride <= 0) {
        qWarning(x11WindowPreview) << "fetchWindowPreview: invalid image dimensions"
                                   << "height =" << imageHeight
                                   << "stride =" << imageStride;
        return {};
    }

    qsizetype expectedSize = static_cast<qsizetype>(imageHeight) * imageStride;
    if (expectedSize <= 0 || expectedSize > kMaxPreviewBufferBytes) {
        qWarning(x11WindowPreview) << "fetchWindowPreview: expected buffer too large or invalid"
                                   << "expectedSize =" << expectedSize
                                   << "height =" << imageHeight
                                   << "stride =" << imageStride;
        return {};
    }

    QByteArray fileContent(expectedSize, Qt::Uninitialized);
    qsizetype totalRead = 0;

```

If `fetchWindowPreview` does not return a `QImage` (or another type that can be value-initialized with `{}`), adjust the two `return {};` statements to return an appropriate error value for that function (e.g., `return QImage();`, `return false;`, or propagate the error via your existing error-handling mechanism).
</issue_to_address>

### Comment 2
<location path="panels/dock/taskmanager/x11preview.cpp" line_range="120" />
<code_context>
-    QByteArray fileContent = file.read(imageHeight * imageWidth * bitsCountPerPixel / 8);
-    QImage image(reinterpret_cast<uchar *>(fileContent.data()), imageWidth, imageHeight, imageStride, qimageFormat);
-    // close read
+    // imageStride 是每行实际字节数(含内存对齐 padding),必须用它而非 width*bpp/8
+    qsizetype expectedSize = static_cast<qsizetype>(imageHeight) * imageStride;
+    QByteArray fileContent(expectedSize, Qt::Uninitialized);
</code_context>
<issue_to_address>
**issue (complexity):** Consider extracting the timeout-based pipe reading and pixmap construction into small helper functions to keep fetchWindowPreview’s main logic linear and easier to follow.

Extracting the low-level I/O into helpers would reduce the local complexity of `fetchWindowPreview` without changing behavior.

You can keep all the new robustness (timeout, partial reads, stride-based sizing) but move it out of the main function:

```cpp
namespace {

// blocking read with timeout for a known-size buffer
bool readWithTimeout(int fd, QByteArray &buffer, qsizetype expectedSize, int timeoutMs)
{
    buffer.resize(expectedSize);
    qsizetype totalRead = 0;

    while (totalRead < expectedSize) {
        struct pollfd pfd{fd, POLLIN, 0};
        int ret = ::poll(&pfd, 1, timeoutMs);
        if (ret == 0) {
            qWarning(x11WindowPreview) << "fetchWindowPreview: pipe read timeout, KWin may have stalled";
            return false;
        }
        if (ret < 0) {
            qWarning(x11WindowPreview) << "fetchWindowPreview: poll error:" << strerror(errno);
            return false;
        }
        if (pfd.revents & (POLLERR | POLLNVAL)) {
            qWarning(x11WindowPreview) << "fetchWindowPreview: pipe error, revents=" << pfd.revents;
            return false;
        }

        const ssize_t n = ::read(fd, buffer.data() + totalRead, expectedSize - totalRead);
        if (n <= 0) {
            if (n < 0)
                qWarning(x11WindowPreview) << "fetchWindowPreview: read error:" << strerror(errno);
            return false; // n == 0: EOF before expectedSize
        }
        totalRead += n;
    }

    return true;
}

QPixmap pixmapFromRawData(const QByteArray &data,
                          int width, int height, int stride,
                          QImage::Format format)
{
    QImage image(reinterpret_cast<const uchar *>(data.constData()),
                 width, height, stride, format);
    return QPixmap::fromImage(image.copy()); // deep copy, same as current behavior
}

} // namespace
```

Then `fetchWindowPreview` becomes much closer to the original linear flow:

```cpp
QPixmap fetchWindowPreview(qulonglong winId)
{
    // ... unchanged setup code ...

    int imageWidth  = imageInfo.value("width").toUInt();
    int imageHeight = imageInfo.value("height").toUInt();
    int imageStride = imageInfo.value("stride").toUInt();
    int imageFormat = imageInfo.value("format").toUInt();

    if (imageWidth <= 1 || imageHeight <= 1) {
        ::close(fd[0]);
        return QPixmap();
    }

    QImage::Format qimageFormat = static_cast<QImage::Format>(imageFormat);

    const qsizetype expectedSize = static_cast<qsizetype>(imageHeight) * imageStride;
    QByteArray fileContent;

    constexpr int kTimeoutMs = 5000;
    const bool ok = readWithTimeout(fd[0], fileContent, expectedSize, kTimeoutMs);
    ::close(fd[0]);

    if (!ok) {
        qWarning(x11WindowPreview) << "fetchWindowPreview: incomplete data, expected" << expectedSize;
        return QPixmap();
    }

    auto pixmap = pixmapFromRawData(fileContent, imageWidth, imageHeight, imageStride, qimageFormat);
    if (!pixmap.isNull()) {
        s_windowPreviewCache.insert(winId, pixmap);
    }
    return pixmap;
}
```

Benefits:

- `fetchWindowPreview` no longer mixes protocol, process/pipe setup, polling, and image construction.
- The timeout/read logic is now reusable and easier to unit-test in isolation.
- The raw pointer cast and `image.copy()` semantics are encapsulated in a single helper.
</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.

When KWin's screenshot service encounters an internal error, it may
hold the write end of the pipe open without writing any data and
without closing it. In this case, the previous blocking `QFile::read()`
would wait forever, hanging the taskbar process.

Three issues are fixed in fetchWindowPreview():

1. Replace `pipe()` with `pipe2(fd, O_CLOEXEC)` to prevent the write
   fd from being inherited by child processes, which would also cause
   read() to block indefinitely.

2. Replace the blocking `QFile::read()` with a `poll()`-based read
   loop with a 5-second timeout. If KWin stalls or the pipe produces
   no data within the timeout, the function aborts gracefully and
   returns an empty QPixmap instead of hanging.

3. Fix the read buffer size calculation: use `imageHeight * imageStride`
   instead of `imageWidth * imageHeight * bpp / 8`. imageStride is the
   actual bytes-per-row (including alignment padding) as reported by
   KWin, and may be larger than width * bpp/8. The old calculation
   could result in reading too few bytes, leading to an out-of-bounds
   access when constructing QImage. Also added image.copy() to ensure
   the QImage owns its data independently of the fileContent buffer.

当 KWin 截图服务发生内部异常时,可能持有管道写端却不写入任何数据
也不关闭,导致原先的阻塞式 `QFile::read()` 永久等待,任务栏进程卡死。

本次修复了 fetchWindowPreview() 中的三个问题:

1. 将 `pipe()` 改为 `pipe2(fd, O_CLOEXEC)`,防止写端 fd 被 fork
   出的子进程继承,否则子进程持有写端也会导致 read() 永久阻塞。

2. 将阻塞式 `QFile::read()` 替换为带 5 秒超时的 `poll()` 读取循环。
   若 KWin 卡顿或管道在超时内无数据,函数会提前退出并返回空的
   QPixmap,而不是使进程永久挂起。

3. 修正读取缓冲区大小计算:使用 `imageHeight * imageStride` 而非
   `imageWidth * imageHeight * bpp / 8`。imageStride 是 KWin 返回的
   每行实际字节数(含内存对齐 padding),可能大于 width*bpp/8。
   原来的计算会导致读取字节数偏小,在构造 QImage 时发生越界访问。
   同时添加 image.copy() 确保 QImage 独立持有数据。

Log: prevent indefinite blocking in fetchWindowPreview pipe read
@deepin-ci-robot
Copy link

deepin pr auto review

这段巴达代码审查。这段代码主要改进了管道通信的健壮性和安全性,以下是详细的审查意见:

1. 语法逻辑

  • 正确性:代码逻辑正确。
    • pipe2 的使用是正确的,相比 pipe 增加了 O_CLOEXEC 标志,防止子进程继承文件描述符。
    • poll 的使用逻辑正确,处理了超时、错误和正常读取三种情况。
    • read 的循环读取逻辑正确,能够处理部分读取的情况。
  • 数据类型
    • expectedSize 的计算使用了 qsizetype,这是 Qt 中用于表示大小的正确类型,避免了潜在的整数溢出问题。
    • imageStride 的使用是正确的,考虑了内存对齐。

2. 代码质量

  • 注释:代码注释清晰,解释了关键步骤和设计决策。
  • 错误处理
    • 增加了详细的错误日志,使用 qWarning 输出错误信息,便于调试。
    • pollread 的返回值进行了检查,确保异常情况能够被正确处理。
  • 资源管理
    • 文件描述符 fd[0] 在使用后被正确关闭。
    • 使用 QByteArray 管理内存,避免了手动内存管理。

3. 代码性能

  • 阻塞问题
    • 使用 poll 替代了阻塞的 QFile::read(),避免了因 KWin 异常导致的永久阻塞,提高了程序的响应性。
    • 设置了 5 秒的超时时间,合理平衡了等待时间和数据完整性。
  • 内存分配
    • QByteArray 预分配了 expectedSize 大小的内存,避免了多次重新分配,提高了读取效率。

4. 代码安全

  • 文件描述符泄漏
    • 使用 pipe2O_CLOEXEC 标志,防止了文件描述符泄漏到子进程。
  • 缓冲区溢出
    • 使用 imageStride 计算预期大小,避免了基于 width * bitsPerPixel / 8 的不精确计算导致的缓冲区溢出风险。
  • 输入验证
    • 检查了 pollread 的返回值,防止了潜在的缓冲区溢出和未定义行为。
  • 类型安全
    • 使用 reinterpret_cast<const uchar *> 替代了 reinterpret_cast<uchar *>,确保了数据的不可变性,提高了类型安全性。

5. 改进建议

  1. 魔法数字
    • kTimeoutMs = 5000 定义为 constexpr 是好的,但可以考虑将其定义为类的静态常量或配置项,以便于统一管理。
  2. 错误恢复
    • 当前代码在读取失败时直接返回空 QPixmap,可以考虑增加重试机制或降级处理策略。
  3. 日志分类
    • 使用了 x11WindowPreview 作为日志分类,建议确保该分类在日志系统中已注册,以便于过滤和查看。
  4. 资源清理
    • 虽然 fd[0] 被关闭了,但 fd[1](写端)在之前的代码中似乎已被关闭(diff 未显示),建议确保所有文件描述符在任何错误路径上都被正确关闭。可以使用 RAII 封装文件描述符以确保异常安全。
  5. 性能优化
    • 如果数据量很大,可以考虑使用内存映射文件(mmap)替代 read,但在此场景下可能收益不大。

总结

这段代码改进了管道通信的健壮性和安全性,主要解决了潜在的阻塞问题和缓冲区溢出风险。代码逻辑清晰,错误处理完善,是一个高质量的改进。建议根据上述改进建议进一步优化代码的可维护性和可配置性。

@yixinshark
Copy link
Contributor Author

#0 __GI___libc_read (nbytes=3840, buf=0x557aa3d9d3f0, fd=54) at ../sysdeps/unix/sysv/linux/read.c:26
#1 __GI___libc_read (fd=54, buf=0x557aa3d9d3f0, nbytes=3840) at ../sysdeps/unix/sysv/linux/read.c:24
#2 0x00007f37794f3cdc in QFSFileEngine::read(char*, long long) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#3 0x00007f37794e81be in QFileDevice::readData(char*, long long) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#4 0x00007f37794f92d2 in QIODevicePrivate::read(char*, long long, bool) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#5 0x00007f37794f9dbc in QIODevice::read(long long) () at /lib/x86_64-linux-gnu/libQt6Core.so.6
#6 0x00007f3770b2db34 in dock::fetchWindowPreview (winId=) at ./panels/dock/taskmanager/x11preview.cpp:126
#7 0x00007f3770b31d9f in dock::AppItemWindowDeletegate::sizeHint (this=, option=, index=...) at ./panels/dock/taskmanager/x11preview.cpp:279
#8 0x00007f377a5e3d9e in QAbstractItemView::sizeHintForIndex(QModelIndex const&) const () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#9 0x00007f3770b2f079 in dock::PreviewsListView::viewportSizeHint (this=0x557aa1831cc0) at ./panels/dock/taskmanager/x11preview.cpp:149
#10 0x00007f377a41722c in QAbstractScrollArea::sizeHint() const () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#11 0x00007f377a3871af in QWidgetPrivate::adjustedSize() const () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#12 0x00007f377a38910e in QWidget::adjustSize() () at /lib/x86_64-linux-gnu/libQt6Widgets.so.6
#13 0x00007f3770b2f6db in dock::X11WindowPreviewContainer::updateSize (this=0x36, windowCount=-1546005520) at ./panels/dock/taskmanager/x11preview.cpp:672
#14 0xffffffffffffffff in ??? ()
#15 0x00007ffd686ae930 in ??? ()
#16 0x00007f3770b2c923 in QModelIndex::QModelIndex (this=0x7f376c07c870) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qabstractitemmodel.h:128
#17 dock::X11WindowPreviewContainer::showPreviewWithModel
(this=0x7f3770b2f2e0 <QtPrivate::QCallableObject<void (dock::X11WindowPreviewContainer::)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase, QObject*, void**, bool*)+112>, sourceModel=0x7f377a3890e0 QWidget::adjustSize(), window=, previewXoffset=, previewYoffset=, direction=)
at ./panels/dock/taskmanager/x11preview.cpp:468
#18 0x00007f3770b390c0 in dock::X11WindowMonitor::requestPreview
(this=0x557a9f408870, sourceModel=0x557a9f4dc1f0, relativePositionItem=0x7ffd686aea10, previewXoffset=75, previewYoffset=691, direction=3)
at ./panels/dock/taskmanager/x11windowmonitor.cpp:150
#19 0x00007f3770aba394 in dock::TaskManager::qt_metacall (this=0x557a9f43abd0, _c=QMetaObject::InvokeMetaMethod, _id=14, _a=0x7ffd686aed68)
at ./obj-x86_64-linux-gnu/panels/dock/taskmanager/dock-taskmanager_autogen/EWIEGA46WW/moc_taskmanager.cpp:513
#20 0x00007f377af10273 in ??? () at /lib/x86_64-linux-gnu/libQt6Qml.so.6
#21 0x00007f377adfa19b in QV4::QObjectMethod::callPrecise(QQmlObjectOrGadget const&, QQmlPropertyData const&, QV4::ExecutionEngine*, QV4::CallData*, QMetaObject::Call) ()
at /lib/x86_64-linux-gnu/libQt6Qml.so.6
#22 0x00007f377adfcf39 in QV4::QObjectMethod::callInternal(QV4::Value const*, QV4::Value const*, int) const () at /lib/x86_64-linux-gnu/libQt6Qml.so.6
#23 0x00007f377ae183d9 in QV4::Runtime::CallPropertyLookup::call(QV4::ExecutionEngine*, QV4::Value const&, unsigned int, QV4::Value*, int) () at /lib/x86_64-linux-gnu/libQt6Qml.so.6
#24 0x00007f37714d8760 in ??? ()
#25 0x0000557aa08fb7e0 in ??? ()
#26 0x0000000000000010 in ??? ()
#27 0x0000557a9f446720 in ??? ()
#28 0x0000000000000000 in ??? ()

用户操作插拔屏幕后,任务栏卡死,以上是堆栈,在读截图管道数据的时候卡住。

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

@yixinshark
Copy link
Contributor Author

/forcemerge

@deepin-bot
Copy link

deepin-bot bot commented Mar 7, 2026

This pr force merged! (status: blocked)

@deepin-bot deepin-bot bot merged commit d170f5e into linuxdeepin:master Mar 7, 2026
9 of 12 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