Skip to content

Conversation

commercebyte
Copy link
Contributor

Corrupted class entries on shutdown when a destructor spawns another object
(C) 2017 CommerceByte Consulting

When zend_objects_store_call_destructors() is called from the shutdown sequence -
it's calling the dtor's for remaining objects one by one in sequence of object handles.
If the dtor spawns one or more objects, and the new objects happen to reuse the old handles -
their dtor's are not called in this cycle.
The dtor's are called later on, when zend_deactivete() kicks in, and the static property lists in the class entries are freed.
This causes "Undefined static property" errors, and/or SIGSEGV.

Solution:
zend_object_store.no_reuse field is added
Set to 0 on initialization, set to 1 on the shutdown sequence.
zend_objects_store_put(zend_object *) checks the no_reuse flag, and never reuses the old handle slots if set.
This way, the dtor's for newly spawned objects are guaranteed to be called in the zend_objects_store_call_destructors() loop.

Corrupted class entries on shutdown when a destructor spawns another object
(C) 2017 CommerceByte Consulting

When zend_objects_store_call_destructors() is called from the shutdown sequence -
it's calling the dtor's for remaining objects one by one in sequence of object handles.
If the dtor spawns one or more objects, and the new objects happen to reuse the old handles -
their dtor's are not called in this cycle.
The dtor's are called later on, when zend_deactivete() kicks in, and the static property lists in the class entries are freed.
This causes "Undefined static property" errors, and/or SIGSEGV.

Solution:
zend_object_store.no_reuse field is added
Set to 0 on initialization, set to 1 on the shutdown sequence.
zend_objects_store_put(zend_object *) checks the no_reuse flag, and never reuses the old handle slots if set.
This way, the dtor's for newly spawned objects are guaranteed to be called in the zend_objects_store_call_destructors() loop.
@krakjoe krakjoe added the Feature label Feb 7, 2017
@krakjoe krakjoe requested a review from nikic February 7, 2017 05:48
…buggy behavior,

when PHP returns "Undefined static property" error due to class entry corruption.
With my fix for bug 74053, both tests return no errors now, I corrected the EXPECTF accordingly

[Anybody please advice if I'm wrong?]

Also created bug74053.phpt, for the code I mentioned in the bug description
@@ -45,6 +45,7 @@ typedef struct _zend_objects_store {
uint32_t top;
uint32_t size;
int free_list_head;
char no_reuse; /* to be set to true when shutting down, to avoid missing dtor call on objects spawned by another dtor */
Copy link
Member

Choose a reason for hiding this comment

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

This is an ABI break on 32-bit platforms, so this change could only go into master as-is.

@commercebyte
Copy link
Contributor Author

commercebyte commented Feb 7, 2017 via email

@nikic
Copy link
Member

nikic commented Feb 7, 2017

Apart from the ABI issue, this approach looks fine to me.

@dstogov What do you think about this change?

@nikic
Copy link
Member

nikic commented Feb 7, 2017

My apologies - let's change to int.
I'll push an update in a few minutes

Changing it to int won't help here: The issue is not the used type, the issue is that on 32-bit this change increases the size of the zend_object_store struct, which is embedded in the executor globals. This will shift all globals coming after it down by 4 bytes, breaking any shared objects using those members.

@commercebyte
Copy link
Contributor Author

commercebyte commented Feb 7, 2017 via email

@nikic
Copy link
Member

nikic commented Feb 8, 2017

Then I can suggest to move no_reuse out of zend_objects_store, and make it a separate global var. Looks like objects store is used only as a single global instance, so this approach should work. Any thoughts?

Yes, this should work, if you declare the variable as ZEND_TLS (the object store is per-thread).

…object_store_no_reuse,

to avoid alignment issues
@commercebyte
Copy link
Contributor Author

commercebyte commented Feb 8, 2017 via email

@dstogov
Copy link
Member

dstogov commented Feb 8, 2017 via email

@commercebyte
Copy link
Contributor Author

commercebyte commented Feb 8, 2017 via email

@dstogov
Copy link
Member

dstogov commented Feb 9, 2017

Right. Currently we have only EG(active), but we may easily add another 8-bit EG(state) or/and EG(flags).

EG_FLAGS_IN_SHUTDOWN - is set when PHP is in shutdown state
@php-pulls php-pulls merged commit 1b1399c into php:master Feb 10, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants