https://bugs.kde.org/show_bug.cgi?id=528237
--- Comment #2 from Gordon <[email protected]> --- Created attachment 198061 --> https://bugs.kde.org/attachment.cgi?id=198061&action=edit Crashlog with dbg Attached a backtrace with symbols: kwin-backtrace-20261104-132430.txt Getting it took a detour, so a note on what you're looking at. This box runs CachyOS and they don't publish debug symbols for their kwin rebuild (their debuginfod 404s on the build-id, and there is no kwin-debug package anywhere in their repos). So I replaced kwin with Arch's unmodified extra/kwin 6.8.2-2, same upstream version, and took symbols from debuginfod.archlinux.org. It crashed identically on that build, so what you're reading is a stock upstream kwin. Qt, libc and Mesa are still CachyOS builds with no symbols published, which is why those frames are bare. I can swap qt6-base the same way if you want the event loop resolved, but I doubt it matters here. While I was at it I found a much simpler reproducer than the VM I described in the original report. No virtualisation needed at all. With the session running on one GPU, unbind a second GPU from its driver: echo 0000:08:00.0 | sudo tee /sys/bus/pci/drivers/i915/unbind 0000:08:00.0 is an Arc A770 on i915 here, desktop is on an RX 9060 XT (amdgpu). Kills kwin_wayland every single time. libvirt does the same thing internally when it attaches a <hostdev managed='yes'/> GPU to a guest, which is how I hit this in the first place. Short version: findCompatibleRenderDevice() gets called with device == nullptr. #0 operator()<std::unique_ptr<KWin::RenderDevice> > (...) at src/core/gpumanager.cpp:177 177 if (device->bustype == DRM_BUS_PLATFORM) { ... #10 KWin::GpuManager::findCompatibleRenderDevice (this=this@entry=0x5577640325c0, device=device@entry=0x0) at src/core/gpumanager.cpp:190 #11 KWin::GpuManager::updateCompatibilityMap (this=0x5577640325c0) at src/core/gpumanager.cpp:150 device = 0x0 devices = std::vector of length 2, capacity 2 = {0x5577674846e0, 0x0} #12 KWin::GpuManager::handleUdevEvent (this=<optimized out>) at src/core/gpumanager.cpp:289 devNum = 1 The kernel log says the same thing, "segfault at c", and offsetof(drmDevice, bustype) is 12. I had assumed this would turn out to be one of the unguarded eglDisplay() derefs in the comparator further down, but it isn't. It's the drmGetDevices2() pair at the top of updateCompatibilityMap(), lines 139-150, which is the same in master right now: int numberOfDevices = drmGetDevices2(0, nullptr, 0); // counts 2 if (numberOfDevices <= 0) { return; } std::vector<drmDevicePtr> devices; devices.resize(numberOfDevices); // 2 slots, both null if (drmGetDevices2(0, devices.data(), numberOfDevices) < 0) { // fills 1, returns 1 qCWarning(KWIN_CORE, "drmGetDevices2 failed: %s", strerror(errno)); return; } for (drmDevicePtr device : devices) { // devices[1] is still null RenderDevice *render = findCompatibleRenderDevice(device); The GPU goes away between the counting call and the filling call. That isn't a narrow window in this case, it's the normal situation, because the whole path runs off handleUdevEvent() reacting to the remove action for the primary node of the device that just vanished (frame #12, devNum = 1, so card1, so the GPU being unbound). The second call fills fewer entries than it was asked for and returns that smaller count, but only "< 0" is checked, so the rest of the vector keeps its null initialiser and gets iterated into findCompatibleRenderDevice(). devices = {0x5577674846e0, 0x0} in frame #11 is exactly that, two slots and one of them filled. Using the return value should be enough: std::vector<drmDevicePtr> devices(numberOfDevices); const int count = drmGetDevices2(0, devices.data(), numberOfDevices); if (count < 0) { qCWarning(KWIN_CORE, "drmGetDevices2 failed: %s", strerror(errno)); return; } devices.resize(count); That has the side benefit of giving drmFreeDevices() at the end the real count rather than the inflated one. I can test patches if that helps, the repro takes about half a minute. -- You are receiving this mail because: You are watching all bug changes.
