-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix GH-10519: Array Data Address Reference Issue #10749
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
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 looks like it fixes the bug. But I do not understand this magic to be honest, so could you answer my couple of questions?
ext/spl/spl_array.c
Outdated
//??? TODO: try to avoid array duplication | ||
ZVAL_ARR(&intern->array, zend_array_dup(Z_ARR_P(array))); |
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.
Why is the comment removed? The duplication still happens.
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.
Sorry, I deleted it carelessly.
ext/spl/spl_array.c
Outdated
@@ -531,6 +556,7 @@ static void spl_array_unset_dimension_ex(int check_inherited, zend_object *objec | |||
HashTable *ht; | |||
spl_array_object *intern = spl_array_from_obj(object); | |||
spl_hash_key key; | |||
uint32_t refcount = 0; |
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.
Move the definition to where it's first use please.
ext/spl/spl_array.c
Outdated
static uint32_t spl_array_set_refcount(spl_array_object *intern, HashTable *ht, uint32_t refcount) /* {{{ */ | ||
{ | ||
uint32_t old_refcount = 0; | ||
if (intern->is_child) { | ||
old_refcount = GC_REFCOUNT(ht); | ||
GC_SET_REFCOUNT(ht, refcount); | ||
} | ||
|
||
return old_refcount; | ||
} /* }}} */ |
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'm really confused by what's the point of this function is, staring at the usage.
Is this to detect if an SPLArray is a child and is refcounted?
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.
ZVAL_ARR(&intern->array, zend_array_dup(Z_ARR_P(array)));
if (intern->is_child) {
Z_TRY_DELREF_P(&intern->bucket->val);
intern->bucket->val = intern->array;
Z_TRY_ADDREF_P(&intern->array);
}
Because I increased the refcount
+ 1 manually here and the assertion HT_ASSERT_RC1(ht)
will failed.
static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag)
{
........
IS_CONSISTENT(ht);
HT_ASSERT_RC1(ht);
........
#define HT_ASSERT_RC1(ht) HT_ASSERT(ht, GC_REFCOUNT(ht) == 1)
So I have to set the refcount
to 1 when intern->is_child
is true to make assertion success and restore the refcount
to the original value after modifying the array
.
ext/spl/spl_array.c
Outdated
object_init_ex(retval, pce); | ||
spl_array_object *new_intern = Z_SPLARRAY_P(retval); | ||
new_intern->is_child = true; | ||
new_intern->bucket = (Bucket *)((char*)(arg1) - XtOffsetOf(Bucket, val)); |
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 line needs a comment, because I have no idea what the hell is happening here.
You are doing some address arithmetic but I don't really get why you are using a Bucket
and not just a zval
for the spl_array_object
struct, as it seems you're just using the zval part anyway?
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.
These things happened when creating this object:
- Setting
new_intern->is_child = true
indicating that this child object was created byRecursiveArrayIterator::getChildren()
method. - After copying the array by
zend_array_dup
, I need to share the newarray
between the parent and child object. - So, I need this
Bucket
of parent object. In this way, I can directly modify this valueintern->bucket->val = intern->array
, so that changes between child object and parent object can affect each other.
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.
new_intern->bucket = (Bucket *)((char*)(arg1) - XtOffsetOf(Bucket, val));
So I can get the bucket
of the parent object by address arithmetic and replace bucket->val
with copy array
.
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.
Okay with the explanations now and the comments, I get what's going on!
Thanks for tackling this!
Thank you. |
No description provided.