Skip to content

ext/spl: Fix various ArrayObject bugs #12037

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

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

Girgias
Copy link
Member

@Girgias Girgias commented Aug 23, 2023

This fixes:

ArrayObject is dealing with the property HashTable directly, this is not much of an issue for read, isset, and empty operations.

However, write operations are very different in that classes can impose restriction on those, ranging from visibility, types and dynamic properties.

Moreover, for some unknown reason, ArrayObject does not use the backing class overloaded property access magic methods and tests for this. Meaning, we cannot just use the standard write_property handler of the CE, thus we need to reimplement it ourself to dodge the __set() call.

Commit 1 is just code rearranging so that I could navigate this file more easily...

Comment on lines 494 to 522
if (check_inherited && intern->fptr_offset_set) {
zval tmp;

if (!offset) {
ZVAL_NULL(&tmp);
offset = &tmp;
}
zend_call_method_with_2_params(object, object->ce, &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
return;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be done in the !offset branch as well: https://3v4l.org/AYJjF

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if I understand what you are asking me to do here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the if (!offset) { branch above, you need to call offsetSet() if there is such method on the object. https://3v4l.org/AYJjF shows that offsetSet() used to be called during $arrayObject[] = ...;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the code at https://3v4l.org/lO4Tf, this is the output on master:

string(12) "A::offsetSet"
string(12) "B::offsetSet"

and this is the output on this branch:

string(12) "A::offsetSet"

Is this an expected behavior change? If not, I think that we should move the if (check_inherited && intern->fptr_offset_set) { block above if (!offset) {

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huuuum I think it is slightly problematic that an object that implements ArrayAccess supports appending as it is indistinguishable from $o[null] but this is something I should add tests for in #12723

But I do agree that ArrayObject subclassing and ArrayAccess implementations should behave identically. Thanks for spotting this, I'm amending this and adding a test :)

@Girgias Girgias changed the base branch from master to PHP-8.3 August 30, 2023 20:25
@Girgias Girgias force-pushed the spl-array-object-props-bugs branch from ab665f5 to 2799ee9 Compare August 30, 2023 21:18
@Girgias Girgias requested a review from bukka as a code owner August 30, 2023 21:18
@bukka
Copy link
Member

bukka commented Sep 7, 2023

I don't think this can go to 8.3 as it is quite late for such potentially breaking fixes considering that PR is also not ready at this stage (object leak and failed CI).

Especially the append bit is a BC break even though I agree that it should be fixed but I would prefer 8.4 instead as this should be for sure in UPGRADING. Note that at this stage we should no longer do any changes that require adding note to UPGRADING.

I would also prefer to add the Dynamic properties change to upgrading. You could argue that this should be done before and it is just an omission which is true but it wasn't done and users might be suprised if they see such change so I think each such changes should be explicitly mentioned in UPGRADING (deprecated functionality). You can see that this is already impacting one standard test so I guess some users will be impacted by this.

@Girgias Girgias changed the base branch from PHP-8.3 to master September 16, 2023 19:19
@Girgias Girgias force-pushed the spl-array-object-props-bugs branch 2 times, most recently from a9da402 to 9ccfbb5 Compare September 20, 2023 12:19
@Girgias Girgias force-pushed the spl-array-object-props-bugs branch 2 times, most recently from a42b71e to e44eb89 Compare November 16, 2023 00:42
@Girgias Girgias requested a review from arnaud-lb November 16, 2023 00:44
@arnaud-lb
Copy link
Member

arnaud-lb commented Nov 22, 2023

The code looks good to me except for the behavior change when offsetSet() is overridden (#12037 (comment))

@Girgias Girgias force-pushed the spl-array-object-props-bugs branch from b9c5c47 to 127652f Compare December 1, 2023 13:00
@arnaud-lb
Copy link
Member

I have mixed opinions about the change in 7e46992. On one hand it seems sensible and allows sub-classes to differentiate $o[null]= from $o[]=, but on the other hand it introduces an inconsistency in ArrayAccess handling and a breaking change.

I would like to see what others think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants