Skip to content

Fix GH-15938: Hold onto the container after a get_property_ptr_ptr() call#20246

Open
arnaud-lb wants to merge 2 commits intophp:masterfrom
arnaud-lb:gh15938
Open

Fix GH-15938: Hold onto the container after a get_property_ptr_ptr() call#20246
arnaud-lb wants to merge 2 commits intophp:masterfrom
arnaud-lb:gh15938

Conversation

@arnaud-lb
Copy link
Member

@arnaud-lb arnaud-lb commented Oct 20, 2025

Effects performed after a get_property_ptr_ptr() call may make the property pointer invalid by freeing or reallocating its container.

The container might be the object itself, the properties ht, a proxied object. For internal classes, this can be anything else.

Here we change the get_property_ptr_ptr handler so it exposes the actual container. The caller can then increase its refcount if any operation performed before the last access to the property could render the property invalid.

The get_property_ptr_ptr() implementation has the responsibility of ensuring that while the container's refcount is incremented, the property pointer remains valid.

Fixes GH-15938

cc @iluuu1994 @nielsdos

Effects performed after a get_property_ptr_ptr() call may make the property
pointer invalid by freeing or reallocating its container.

The container might be the object itself, the properties ht, a proxied object,
or anything else (for internal classes).

Here we change the get_property_ptr_ptr handler so it exposes the actual
container. The caller can then increase its refcount if any operation performed
before the last access to the property could render the property invalid.

The get_property_ptr_ptr() implementation has the responsibility of ensuring
that while the container's refcount is incremented, the property pointer remains
valid.
Copy link
Member

@iluuu1994 iluuu1994 left a comment

Choose a reason for hiding this comment

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

The approach seems reasonable. It's a bit unfortunate that this API change is necessary only because of internal classes with fetch_ptr_ptr to custom storage that may also move, which should be very rare. FWIU, the properties table RC could simply always be increased along with the object RC, making that problem go away. For internal classes, maybe we could fix the issue in a different way by flagging the object for the duration of the ptr lifetime, and prevent changes being made to objects with such flags. This would require checks in multiple places, so might not be a better solution.

In any case, I don't object to this approach.

@arnaud-lb arnaud-lb marked this pull request as ready for review October 28, 2025 16:26
@Girgias Girgias removed their request for review October 29, 2025 13:32
@arnaud-lb arnaud-lb changed the title Hold onto the container after a get_property_ptr_ptr() call Fix GH-15938: Hold onto the container after a get_property_ptr_ptr() call Oct 30, 2025
Copy link
Member

@ndossche ndossche left a comment

Choose a reason for hiding this comment

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

This approach seems relatively simple and I can't immediately think of a problem. Will need to test more intensively coming week.

Copy link
Member

@derickr derickr 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 no objections either.

@dstogov
Copy link
Member

dstogov commented Jan 26, 2026

I see this like a wrong direction...

@arnaud-lb
Copy link
Member Author

arnaud-lb commented Jan 30, 2026

@dstogov I'm happy to explore other directions.

The root of the problem is that we may have to coerce to string with __toString() after fetching the property ptr, but this may invalidate it. We can not coerce before fetching the property for two reasons:

I can think of the following alternatives solutions:

  • Consider the pointer invalid after a __toString() call, so fetch it again, or fallback or zend_assign_op_overloaded_property(). This moves complexity to zend_binary_assign_op_typed_prop() / concat_function() / users of get_property_ptr_ptr().
  • Detect that the pointer was invalidated, but I don't think it's feasible or cheaper than the proposed solution. The pointer can be invalidated in many ways. If it's an obj->properties hash bucket, the bucket may be removed, or the hash table may be reallocated. If it's a pointer to obj->properties_table, the object itself maybe freed. If the object is lazy, it maybe a pointer to another object that may be freed.
  • Deprecate __toString() for implicit coercion

@dstogov
Copy link
Member

dstogov commented Feb 2, 2026

  • Deprecate __toString() for implicit coercion

How can we detect the "implicit coercion"?

I think, this class of problems, should be fixed by disabling magic functions to do destructive things.
Just terminate the script without an attempt to recover.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Side effects after get_property_ptr_ptr() handler

5 participants