A Window constructor that throws leaves this in Device::windows and as listener data, so the next window touches freed memory #169
Labels
No labels
claude:blocked
claude:done
claude:failed
claude:in-progress
claude:ready
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Catcrafts/Crafter.Graphics#169
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
On Wayland the
Windowconstructor registers the window before the steps that can throw:Device::windowsholdsthis, and the xdg surface, the toplevel and the fractional scale have it as listener data. When a later step throws,~Windowdoes not run, so nothing takesthisback or destroys those objects, and the storage they point at is released. An application that catches the error and carries on reads and writes freed memory. Line numbers refer to670df31.Details
implementations/Crafter.Graphics-Window.cpp:358:Device::windows.push_back(this);:363-364and:378: the listeners getthis.Device::CheckVkResult(implementations/Crafter.Graphics-Device.cpp:134) on surface creation (Window.cpp:459) and the surface queries that follow; no surface format a storage image can be written through (:499);CreateSwapchain(:531), which also throws when the driver makes the swapchain with other thannumFramesimages (:1640).~Window(:633) is what erases the window fromDevice::windows, clears the focus pointers and destroys the proxies. A constructor that throws never reaches it.Afterwards
Device::windowsholds a dangling pointer. The event loop walks it (Window.cpp:928,:967,:992,:1007), and the text-input, pointer, keyboard and touch enters dereference every entry while matching their surface (Device.cpp:383,:502,:569,:684). The leaked toplevel can still be sent configures, whichxdg_toplevel_configurewrites into the freed object (Window.cpp:1766-1767).Found by reading the code. The likeliest trigger is a surface without a storage-writable format, in an application that catches the error to report it or to try again.
Suggested fix
Make the constructor exception-safe: factor
~Window's teardown into a function and run it from a guard local to the constructor unless construction completes, or registerthisinDevice::windowslast and destroy what was made before rethrowing. A function-try-block won't do, since its handler may not touch the members.The Win32 constructor has the same problem. Line numbers refer to
implementations/Crafter.Graphics-Window.cppat852ae8a.CreateWindowEx(:417) passesthisas the create parameter,WM_NCCREATEstores it inGWLP_USERDATA(:140-148), andShowWindow(:434) puts the window on screen.vkCreateWin32SurfaceKHRthroughCheckVkResult(:451), the storage-format check (:499),CreateSwapchain(:531).~Windowis what detaches the HWND and destroys it (:687-688). A constructor that throws never gets there.So the window stays on screen with
GWLP_USERDATApointing at the freedWindow. Once anything pumps messages on that thread again (the application's own loop, another window'sStartSync, aMessageBox), hovering, clicking, resizing or closing it sendsWM_SETCURSOR,WM_MOUSEMOVE, the button messages,WM_SIZEorWM_CLOSEintoWndProc, which writes into the freed object and invokes its destroyed events. TheVkSurfaceKHRleaks too.The guard suggested above covers it if it also detaches and destroys the HWND and destroys the surface. Found while reviewing
claude/win32-title.