mirror of
https://github.com/ocornut/imgui.git
synced 2026-10-16 22:40:48 +00:00
clang 23 miscompilation due to strict aliasing violation #9557
Labels
No labels
accidentally closed
android
backends
bug
building
clipper
coloredit
color spaces
cplusplus
data types
demo
disabled
doc
docking
dpi
drag drop
drawing/drawlist
dropped
dx12
enhancement
focus
font/text
gallery
help wanted
idle/power saving
ime
in progress
inputs
inputtext
internals
label/id and id stack
language bindings
layout
linux/bsd
menus
multi-contexts
multi-threading
multi-viewports
nav
news/info
opengl
optimization
osx/ios
overlap
plot/graph
popups
question
scrolling
selection
settings
sliders/drags
style
tables/columns
tabs
test wanted
tools
tooltips
tree
tricks & tips
useful widgets
vulkan
web
window pos/depth
window sizing
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
ocornut/imgui#9557
Loading…
Add table
Add a link
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?
Version/Branch of Dear ImGui:
Version 1.92.9b-59-ge0a2f6dea, Branch: master
Back-ends:
Magnum
Compiler, OS:
clang 23.1.1, x86-64 MinGW + lld, Windows 11
Full config/build information:
No response
Details:
Please note that the report below was diagnosed and written by AI. I've reviewed it fully, but there's still a chance of complete nonsense. The assertion failure is very real however.
ImHashData: strict-aliasing violation miscompiled under LTO
Version, back-ends, compiler, OS
IMGUI_VERSION_NUM19297), master, commite0a2f6dea(2026-09-10),unmodified
No
imgui_impl_*.cpp.Full config/build information
Not in that list:
IMGUI_DISABLE_DEFAULT_FONTIMGUI_USER_CONFIG="Magnum/ImGuiIntegration/visibility.h", which only defines export macrosIMGUI_ENABLE_SSE4_2_CRC, which-mavxturns on throughimgui_internal.h:66-73The build flags don't matter: the repro below needs only
-O2 -msse4.2 -flto.Assert
The app requests its font at 16px, later at 19px. Both requests get the same
BakedId, soBakedMapreturns the 16px baked font andbaked->Size == font_sizefails. WithNDEBUG,every size of a font silently renders at the first size that was baked.
Problem
ImFontAtlasBakedGetId(imgui_draw.cpp:5429) hashes a struct holding two floats:The SSE4.2 path of
ImHashData(imgui.cpp:2495) reads it 4 bytes at a time:That reads
floatobjects through anunsigned intglvalue, which is undefined behaviour under[basic.lval]. Clang's type-based alias analysis assumes an
unsigned intload never observes afloatstore. Once full LTO inlinesImHashDatafromimgui.cppinto its caller inimgui_draw.cpp, the float stores are dropped, and the size never reaches the hash.The same violation is in every
ImHashDatacaller that hashes something other thanint:imgui.cpp:9345GetID(const void*)imgui.cpp:9372GetIDFromPosImVec2imgui.cpp:9381GetIDFromRectangle(used byBeginDragDropTarget,BeginDragDropSource)ImRectimgui_draw.cpp:5435ImFontAtlasBakedGetIdThe
intcallers (imgui.cpp:7010,:7021,:9357,:9445) are legal:intmay beread as
unsigned int.Minimal repro
Two files, so that
ImHashDatagets inlined only at link time, as in ImGui.The fix, under
#ifdef FIX:Without
FIX,mainhashes the constantFontIdthree times and prints one result twice:With
FIX, the float bits0x41500000(13.0f),0x41800000(16.0f) and0x3f800000(1.0f)go into
crc32. 2389227250 is CRC32C of the words{1, 1, 1}, the sameBakedIdthe debuggershowed for both requests in the app.
At
-Os,mainstores onlyFontId. Both float stores are gone, and thecrc32loop reads 8bytes of uninitialized stack, so the id changes on every run. With
__attribute__((noinline))on
ImFontAtlasBakedGetId, its out-of-line copy hashes the running CRC into itself(
crc32 eax, eaxtwice), as the out-of-line copy in the app does.Correct:
-O1, no LTO,-fno-strict-aliasing, or both functions in one file.-mcrc32inplace of
-msse4.2also reproduces it, but ImGui enables its SSE4.2 path only for__SSE4_2__or
__AVX__. Tested only with this clang 23.1.1 on x86_64-w64-windows-gnu.Fix
The same
memcpychange atimgui.cpp:2495. A fixed 4-bytememcpycompiles to a plain loadthat isn't typed
unsigned int, so it sees the float stores. One line covers every caller in thetable above. Verified with all five imgui TUs and a small driver, full LTO: unpatched gives
2389227250 for every size, patched gives the CRC32C ids.
Workaround without patching:
-DIMGUI_USE_LEGACY_CRC32_ADLER. It switches to the byte-tableCRC, which reads through
unsigned char, and changes every ImGui ID.But at what cost?
The
memcpy(3)call costs nothing. Compiled on its own, ImHashData produces an identical instruction stream with and without-DFIX. I've checked with-O2 -msse4.2and with-O3 -march=x86-64-v2 -mavx, and diff of the two.sfiles, ignoring assembler directives, was empty in both cases. The fixed loop: