-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Bug Fix: #2372
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
Bug Fix: #2372
Conversation
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.
…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
Zend/zend_objects_API.h
Outdated
@@ -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 */ |
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 is an ABI break on 32-bit platforms, so this change could only go into master as-is.
My apologies - let's change to int.
I'll push an update in a few minutes -
…______________
Jim Zubov
CommerceByte Consulting
President
(917) 336-6221
Skype: commercebyte
Schedule an Appointment: https://calendly.com/commercebyte
On February 7, 2017 10:47:47 AM EST, Nikita Popov ***@***.***> wrote:
nikic commented on this pull request.
> @@ -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 */
This is an ABI break on 32-bit platforms, so this change could only go
into master as-is.
--
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub:
#2372 (review)
|
Apart from the ABI issue, this approach looks fine to me. @dstogov What do you think about this change? |
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. |
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?
…______________
Jim Zubov
CommerceByte Consulting
President
(917) 336-6221
Skype: commercebyte
Schedule an Appointment: https://calendly.com/commercebyte
On February 7, 2017 10:53:53 AM EST, Nikita Popov ***@***.***> wrote:
> 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.
--
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub:
#2372 (comment)
|
Yes, this should work, if you declare the variable as |
…object_store_no_reuse, to avoid alignment issues
Redefined as a global.
Just a thought - it might've been better to have a public global execute state var - to be able to distinguish whether it's a normal execution or a shutdown. I don't see anything like that in the code.
…______________
Jim Zubov
CommerceByte Consulting
President
(917) 336-6221
Skype: commercebyte
Schedule an Appointment: https://calendly.com/commercebyte
On February 7, 2017 7:06:21 PM EST, Nikita Popov ***@***.***> wrote:
> 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).
--
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub:
#2372 (comment)
|
This fixes the issue, but looks like a hack.
Let me think about a different solution.
…________________________________
From: Nikita Popov <notifications@github.com>
Sent: Tuesday, February 7, 2017 6:51:28 PM
To: php/php-src
Cc: Dmitry Stogov; Mention
Subject: Re: [php/php-src] Bug Fix: (#2372)
Apart from the ABI issue, this approach looks fine to me.
@dstogov<https://github.com/dstogov> What do you think about this change?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#2372 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ACZM0sKcNUNWv7ogRjYmFolUcG4hbagmks5raJMAgaJpZM4L43PK>.
|
I agree, looks somewhat like a hack. See my latest suggestion on the thread for another option - an execution state flag.
…______________
Jim Zubov
CommerceByte Consulting
President
(917) 336-6221
Skype: commercebyte
Schedule an Appointment: https://calendly.com/commercebyte
On February 8, 2017 2:38:48 AM EST, Dmitry Stogov ***@***.***> wrote:
This fixes the issue, but looks like a hack.
Let me think about a different solution.
________________________________
From: Nikita Popov ***@***.***>
Sent: Tuesday, February 7, 2017 6:51:28 PM
To: php/php-src
Cc: Dmitry Stogov; Mention
Subject: Re: [php/php-src] Bug Fix: (#2372)
Apart from the ABI issue, this approach looks fine to me.
@dstogov<https://github.com/dstogov> What do you think about this
change?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on
GitHub<#2372 (comment)>,
or mute the
thread<https://github.com/notifications/unsubscribe-auth/ACZM0sKcNUNWv7ogRjYmFolUcG4hbagmks5raJMAgaJpZM4L43PK>.
--
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub:
#2372 (comment)
|
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
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.