-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Detect rehash in array-backed hashes #13919
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
This comment has been minimized.
This comment has been minimized.
b1a72a3
to
243d5ee
Compare
hash.c
Outdated
int status = (*arg->func)((VALUE)key, (VALUE)value, arg->arg); | ||
/* TODO: rehash check? rb_raise(rb_eRuntimeError, "rehash occurred during iteration"); */ | ||
if (!RHASH_AR_TABLE_P(arg->hash) || RHASH_AR_TABLE(arg->hash) != tbl) { |
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.
I forget what happens on rehash, but RHASH_AR_TABLE(arg->hash) != tbl
is correct checking?
hash.c
Outdated
int status = (*arg->func)((VALUE)key, (VALUE)value, arg->arg); | ||
/* TODO: rehash check? rb_raise(rb_eRuntimeError, "rehash occurred during iteration"); */ | ||
if (!RHASH_AR_TABLE_P(arg->hash) || RHASH_AR_TABLE(arg->hash) != tbl) { |
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.
I know this is copying from similar code using RHASH_ST_TABLE
, but that check might actually never trigger. RHASH_ST_TABLE() just adds an offset to the argument, so for the same hash, it's always going to be the same. arg->hash
is never going to be changed by the callback, so that check will always be false.
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.
I changed this condition to check if the bound increases. That should work, right?
@ko1 is this check and the on for ST table meant to be a debug assert? Seems like it's not possible to accurately check for rehash here efficiently. Maybe we should just remove the code and TODO, or turn them into st_table *tbl = RHASH_ST_TABLE(arg->hash);
int status = (*arg->func)((VALUE)key, (VALUE)value, arg->arg);
if (RHASH_ST_TABLE(arg->hash) != tbl) {
rb_raise(rb_eRuntimeError, "rehash occurred during iteration");
} With recent changes it never raises: static inline st_table *
RHASH_ST_TABLE(VALUE h)
{
return (st_table *)((uintptr_t)h + sizeof(struct RHash));
} Also, Hash#rehash disallows running while iterating, so it's unclear how these checks could fail in practice: if (hash_iterating_p(hash)) {
rb_raise(rb_eRuntimeError, "rehash during iteration");
} |
+1 for removing the code and TODO. |
Okay, I've removed the code I added and the TODO. Would you like me to squash this into a single commit or will you squash when you merge? |
Added safeguards for array-backed hashes by storing the table pointer and bound in
hash_foreach_arg
and checking them during iteration to raise an exception if a rehash occurs.Fixed TODO added in 2018 by @ko1.