{"id":109163,"date":"2023-12-18T07:00:00","date_gmt":"2023-12-18T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109163"},"modified":"2023-12-18T07:19:30","modified_gmt":"2023-12-18T15:19:30","slug":"20231218-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20231218-00\/?p=109163","title":{"rendered":"If the RegisterClass function takes ownership of the custom background brush, why is it leaking?"},"content":{"rendered":"<p>A customer found that their program was leaking GDI resources, but they couldn&#8217;t figure out why.<\/p>\n<p>They suspect that it may have something to do with a recent change they made. They discovered in the fine print of the documentation of the <code>hbrBackground<\/code> member of the <code>WNDCLASS<\/code> structure<\/p>\n<blockquote class=\"q\"><p>The system automatically deletes class background brushes when the class is unregistered by using <b>Unregister\u00adClass<\/b>. An application should not delete these brushes.<\/p><\/blockquote>\n<p>The code responsible for registering classes was registering the classes with brushes it did not own. When the original owner destroyed the brushes, that created a double-free bug. To fix the problem, they had their class registration code create a duplicate of the brush and register with the duplicate.<\/p>\n<p>This fixed the double-free bug, but somehow it introduced a resource leak. Were they incorrect to duplicate the brush? Are all these duplicates being leaked? It seemed so, because most of the time, the program ran out of resources on the <code>CreateBrushIndirect<\/code> call in their brush duplication function, which suggests that these brushes are being leaked after all.<\/p>\n<p>What&#8217;s going on?<\/p>\n<p>After being reassured that the <code>Register\u00adClass<\/code> function does indeed take ownership of the brushes used for class registrations, they went and studied their code more closely and found the problem.<\/p>\n<p>The issue was that they created a brush for the class registration, expecting the <code>Register\u00adClass<\/code> to take responsibility for destroying the brush when it&#8217;s no longer needed. But they neglected to deal with the case where they register the same class more than once.<\/p>\n<p>The code registers classes on demand, and before they create a window, they call <code>Register\u00adClass<\/code> to register the class just in time. If the class is already registered, then <code>Register\u00adClass<\/code> fails with <code>ERROR_<wbr \/>CLASS_<wbr \/>ALREADY_<wbr \/>EXISTS<\/code>, in which case <code>Register\u00adClass<\/code> does <i>not<\/i> take responsibility for the <code>hbrBackground<\/code> brush. In the case that <code>Register\u00adClass<\/code> fails, the code needs to delete the brush manually.<\/p>\n<p>The way to write the code will vary depending on which RAII class library you&#8217;re using (if you&#8217;re using one at all). If you&#8217;re using the <a href=\"https:\/\/github.com\/microsoft\/wil\"> Windows Implementation Library<\/a>, then it would go something like this:<\/p>\n<pre>\/* Asssume DuplicateBrush makes a copy of a brush *\/\r\nwil::unique_hbrush backgroundBrush = DuplicateBrush(hbrBackground);\r\nRETURN_LAST_ERROR_IF(!backgroundBrush);\r\n\r\nWNDCLASS wc{};\r\nwc.hbrBackground = backgroundBrush.get();\r\n\u27e6 other WNDCLASS initialization goes here \u27e7\r\n\r\nif (RegisterClass(&amp;wc)) {\r\n    \/\/ System owns the brush now.\r\n    <span style=\"border: solid 1px currentcolor;\">backgroundBrush.release();<\/span>\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>It takes ownership only on success.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-109163","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It takes ownership only on success.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109163","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=109163"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109163\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=109163"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109163"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109163"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}