From fd80ded5a8511faed0cb1d25dba52ffc53233bda Mon Sep 17 00:00:00 2001 From: Gabriel Monteiro Date: Mon, 6 Jul 2026 00:28:03 -0300 Subject: [PATCH] fix(gui): startup crash in clang/LLVM builds, null pointer UB in create_scaled_bitmap (#14521) fix(gui): avoid null-pointer UB in create_scaled_bitmap with win == nullptr create_scaled_bitmap() documents that win may be nullptr, but called win->FromDIP() on it. Calling a member function through a null pointer is undefined behavior: clang assumes `this` is non-null and deletes the subsequent `win ?` null check added in #13117, turning the fallback branch into an unconditional virtual call through a null vtable. This crashed LLVM/clang-cl builds at startup (access violation reading 0x0 in BBLTopbar creation); MSVC builds were unaffected by luck. Use the static, null-safe wxWindow::FromDIP(x, win) overload instead, which falls back to the primary display DPI. Behavior is unchanged for non-null windows. --- src/slic3r/GUI/wxExtensions.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 66ad109fab..e40046c37d 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -436,7 +436,9 @@ wxBitmap create_scaled_bitmap( const std::string& bmp_name_in, return create_scaled_bitmap2(bmp_name_in, cache, win, px_cnt, grayscale, resize, array_new_color); } unsigned int width = 0; - unsigned int height = (unsigned int) (win->FromDIP(px_cnt) + 0.5f); + // win may be nullptr; use the static overload, which falls back to the primary display DPI. + // Calling win->FromDIP() on a null win is UB and lets the optimizer drop later null checks. + unsigned int height = (unsigned int) (wxWindow::FromDIP(px_cnt, win) + 0.5f); std::string bmp_name = bmp_name_in; boost::replace_last(bmp_name, ".png", ""); @@ -450,7 +452,7 @@ wxBitmap create_scaled_bitmap( const std::string& bmp_name_in, // Try loading an SVG first, then PNG if SVG was not found: wxBitmap *bmp = cache.load_svg(bmp_name, width, height, grayscale, dark_mode, new_color, resize ? em_unit(win) * 0.1f : 0.f); if (bmp == nullptr) { - bmp = cache.load_png(bmp_name, width, height, grayscale, resize ? win->FromDIP(10) * 0.1f : 0.f); + bmp = cache.load_png(bmp_name, width, height, grayscale, resize ? wxWindow::FromDIP(10, win) * 0.1f : 0.f); } if (bmp == nullptr) { @@ -471,7 +473,8 @@ wxBitmap create_scaled_bitmap2(const std::string& bmp_name_in, Slic3r::GUI::Bitm const vector& array_new_color/* = vector()*/) // color witch will used instead of orange { unsigned int width = 0; - unsigned int height = (unsigned int)(win->FromDIP(px_cnt) + 0.5f); + // win may be nullptr; see create_scaled_bitmap() above. + unsigned int height = (unsigned int)(wxWindow::FromDIP(px_cnt, win) + 0.5f); std::string bmp_name = bmp_name_in; boost::replace_last(bmp_name, ".png", "");