-
-
Notifications
You must be signed in to change notification settings - Fork 10.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New function ImHashAdd() to create a new ID instead of (ID + int). #6140
Conversation
Thank you for the careful amount of details.
It's actually used in two other occasions: for the ID of columns in the Table code ( The reason for that addition was to ensure that a majority of tables (which don't have multiple instances) could be accessed with an obvious "universal identifier" in the Dear ImGui Test Engine (e.g. Whereas my logic breaks is that in turns we are unable to access subsequent instances of a same Table with an easy/known string identifier, but only through a small helper (e.g.
I'll be working on that. |
… table. Storing instance id for convenience. (#6140) TableGetColumnResizeID() are still using an incorrect table, but having only one-level left tends to cancel things out.
…d "table_multi_instances" test with extra bits. Ref ocornut/imgui#6140
Pushed fix f799a29 + amended tests and updated test engine for this ocornut/imgui_test_engine@27c3f05 Also simplified the PushID() in TableHeadersRow(). Thanks! |
That is a great solution, but this lines make me a bit wary:
The obvious solution is to increase that array size to 16, of course. But just for the sake of reviving my old code, it could also be a new override:
And then we need no string format:
|
You are absolutely right. Pushed d6ea56d. |
In issue #4612 there is a comment about a hash collision in the
ShowDemoWindow
, in the "Synced Tables" section. As it happens there is a collision, but it is not a because of a random chance, but because of how CRC32 works and a faulty assumption in the code, that this PR tries to fix.The issue is in
imgui_tables.cpp:336
that creates a new ID by taking the old ID and adding a number.That looks innocent enough, the hash is different. But later, it does:
That basically translates to
PushID(0)
,PushID(1)
,PushID(2)
,PushID(3)
... that in turn will callImHashData(&n, sizeof(int), instance_id);
.Now, let's see what happens when
id
ends with an hexadecimal 0x1. On one hand we callImHasData(&0, sizeof(int), 0xXYZ1)
. That if we look into the CRC32 code will do this line 4 times, being*data == 0
in all of them:Sometime later
instance_no=1
andcolumn_n=0
it will callImHashData(&3, sizeof(int), 0xXYZ2)
that will call the same crc code once with*data==3
and three times with*data==0
.But if we compare the first computation of CRC in both cases:
Simplifying a bit:
But
0xZ2 ^ 3 == 0xZ1
!! And the next 3 input bytes are identical, and both functions will return the same hash!This is not actually a weakness in CRC32 as it is not an intended use. Changing the seed using an arbitrary arithmetic operation may raise unwanted patterns in the output of the hash. The proper way to derive a new seed is to always run the CRC kernel.
So I wrote a small
ImHashAdd()
that does the moral equivalent to an addition, actually callingImHashData
.I reviewed the whole Dear ImGui codebase and I only found this instance of adding a number to an ID. But maybe I skipped some, or maybe third-party code does it willy-nilly. This is why in addition to this PR I opened thos other one #6138 recommending changing the hash algorithm to a more sophisticated one.
I'm not sure that is worth it, but other option to avoid unwanted arithmetic to IDs would be to typedef it not to be an integer, a new-type pattern:
Then
ImHashAdd()
could be converted intoImGuiID::operator+(int)
and everybody would be happy.