-
Notifications
You must be signed in to change notification settings - Fork 7.8k
Reduce HT_MAX_SIZE to account for the max load factor of 0.5 #10242
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
Conversation
zend_hash allocates a hash table twice as big as nTableSize (HT_HASH_SIZE(HT_SIZE_TO_MASK(nTableSize)) == nTableSize*2), so HT_MAX_SIZE must be half the max table size or less.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks sensible to me.
Maybe just expand the comment on why the MAX_SIZE was chosen in the header file?
(((size_t)(uint32_t)-(int32_t)(nTableMask)) * sizeof(uint32_t)) | ||
(((size_t)-(uint32_t)(nTableMask)) * sizeof(uint32_t)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(int32_t)(nTableMask)
is implementation defined when nTableMask
has its max value (uint32_t)INT32_MAX+1
.
I think that the (int32_t)
cast is not necessary here, and that -(uint32_t)(nTableMask)
gives the same result without being implementation defined.
#if SIZEOF_SIZE_T == 4 | ||
# define HT_MAX_SIZE 0x04000000 /* small enough to avoid overflow checks */ | ||
# define HT_MAX_SIZE 0x02000000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is SSIZE_MAX/(sizeof(Bucket)+2*sizeof(uint32_t)) (0x3ffffff) rounded down to the closest power of two
zend_hash allocates a hash table twice as big as nTableSize:
HT_HASH_SIZE(HT_SIZE_TO_MASK(nTableSize)) == nTableSize*2
, so HT_MAX_SIZE must be half the max table size or less.This fixes #10240:
In HT_HASH_RESET, HT_HASH_SIZE((ht)->nTableMask) evaluates to 0, leading to the assertion failure.
0
is indeed an invalid value for nTableMask, given how the hash table offsets are computed:This relies on nTableMask having at least the highest bit set, so that interpreting (hash | nTableMask) as signed gives an offset in the range
]-(~(nTableMask)+1)...0]
.ht->arData
points to the end of the hash table.hash
is always > 0, so the range is actually]-(~(nTableMask)+1)...-1]
.HT_SIZE_TO_MASK multiples nSize by 2 to ensure a load factor of 0.5.
Given that, I think that HT_MAX_SIZE should be (2**31 / 2) : 0x40000000.