Skip to content

PHPC-2456: Correctly dereference arrays in type maps #1683

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

Merged
merged 1 commit into from
Sep 24, 2024

Conversation

alcaeus
Copy link
Member

@alcaeus alcaeus commented Sep 24, 2024

PHPC-2456

This PR adds dereferencing logic to the PHP array API polyfill. This logic has already been added for longs, strings, and doubles, but not for arrays and objects. This can cause issues when passing a reference to an array in a type map, as we extract an array but receive NULL. To the user, this makes no sense as from their point of view, a reference to an array is an array like any other.

Note that I'm targeting v1.19 here as that's our current stable branch, but we may opt to not release another 1.19 patch release and only fix this in 1.20.0.

@alcaeus alcaeus requested a review from jmikola September 24, 2024 08:46
@alcaeus alcaeus self-assigned this Sep 24, 2024
@alcaeus alcaeus requested a review from GromNaN September 24, 2024 08:47
@alcaeus alcaeus changed the base branch from v1.19 to v1.20 September 24, 2024 11:26
return zarr;
default:
return NULL;
}
Copy link
Member

Choose a reason for hiding this comment

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

This looks related to a previous issue we had with dereferencing strings. See c68cdcd from PHPC-1839.

Also, you should contribute all of these ZVAL_DEREF() changes upstream to sgolemon/php-array-api when you get a chance. It's your ticket to the very exclusive contributors club.

Maybe @sgolemon can make us t-shirts.

Copy link
Member Author

Choose a reason for hiding this comment

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

Will contribute this upstream 👍

switch (Z_TYPE_P(zarr)) {
case IS_REFERENCE:
ZVAL_DEREF(zarr);
goto try_again;
Copy link
Member

Choose a reason for hiding this comment

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

I realize this is the same logic from c68cdcd, but I'm curious this could be replaced with a fall-through.

Dereferencing and Unwrapping includes the following code example:

zval *val;
ZEND_HASH_FOREACH_VAL(ht, val) {
    ZVAL_DEREF(val);

    /* Do something with val, now a guaranteed non-reference. */
} ZEND_HASH_FOREACH_END();

That implies that dereferencing would never yield another IS_REFERENCE type. That is also supported by this earlier text in Initializing references:

zval *zv = /* ... */;
ZVAL_MAKE_REF(zv);

If zv was already a reference, this does nothing. It if wasn’t a reference yet, this will change zv into a reference and set its initial value to the old value of zv.

It's a bit too early for me to dive through the macros in zend_types.h to confirm this.

Copy link
Member

Choose a reason for hiding this comment

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

Looking through php-src, I don't see any examples of ZVAL_DEREF() being called iteratively. It tends to precede zval access, and code relies on it being a no-op for non-references. In that case, perhaps you could unconditionally call ZVAL_DEREF(zarr) after the initial NULL check and eliminate the goto.

Likewise for the original patch in c68cdcd.

If you'd rather not make this change now, I'd consider it for the upstream contribution to sgolemon/php-array-api.

Copy link
Member Author

Choose a reason for hiding this comment

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

Looking at this, I don't think that will work. After calling ZVAL_DEREF we still have to check the type of the dereferenced zval before accessing the ce, which wouldn't work with a fallthrough. As much as I hate the goto way of doing things, the only other option I see is a while (Z_TYPE_P(z) == IS_REFERENCE), which is equally bad.

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed the goto after all by calling ZVAL_DEREF unconditionally after a NULL check.

Copy link
Member

@jmikola jmikola left a comment

Choose a reason for hiding this comment

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

I have a suggestion to eliminate the goto, but I'm sure this works as-is given the regression test (and previous, related issue).

@alcaeus alcaeus force-pushed the phpc-2456-fix-typeMap-refs branch 2 times, most recently from 4c0d2cd to 3ffdce9 Compare September 24, 2024 14:26
@alcaeus alcaeus mentioned this pull request Sep 24, 2024
@alcaeus alcaeus force-pushed the phpc-2456-fix-typeMap-refs branch from 3ffdce9 to db4f369 Compare September 24, 2024 14:46
@alcaeus alcaeus mentioned this pull request Sep 24, 2024
@alcaeus alcaeus merged commit e19b31b into mongodb:v1.20 Sep 24, 2024
71 of 72 checks passed
@alcaeus alcaeus deleted the phpc-2456-fix-typeMap-refs branch September 24, 2024 14:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants