Skip to content

Fix bug #69227 and #65967 #1175

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 2 commits into from
Mar 13, 2015
Merged

Fix bug #69227 and #65967 #1175

merged 2 commits into from
Mar 13, 2015

Conversation

vektah
Copy link

@vektah vektah commented Mar 13, 2015

See https://bugs.php.net/bug.php?id=69227

The old:
SplObjectStorage had a get_gc method that returns SplObjectStorage->properties. A hidden \x00gcdata property is added as an array so the gc can iterate over the contents of the collection. This was added to address https://bugs.php.net/bug.php?id=53071.

When a SplObjectStorage has a reference to itself in its collection (directly or indirectly) the gc will fetch a copy of gcdata, then going depth first into its children it hits itself a second time at which point it truncates the existing gcdata hash and fills it with the same data. This frees the pointer being held by the first pass of gcdata. Use after free ensues.

The new:
This patch removes the hidden \x00gcdata property from SplObjectStorage, replacing it with a list of zval*'s. Unlike a linked list updating the contents of a flat array does not invalidate the callers reference. Also the values never really change as the underlying collection does not change during gc

This fixes the free after use, and other bugs resulting from gcdata being a property (eg https://bugs.php.net/bug.php?id=65967)

This is broken in 5.* and master, but master will require a different patch as the gc has changed a little.

This patch fixes a use (in zend_gc.c) after free (in spl_observer.c).
See https://bugs.php.net/bug.php?id=69227
@laruence
Copy link
Member

from my first glance, I don't think this could fixed bug 69227 , because you still erealloc (free previously allocated zval*[]) while doing recursively call to get_gc..

@laruence
Copy link
Member

but maybe your are right, it only do realloc while elements are changed...

@vektah
Copy link
Author

vektah commented Mar 13, 2015

@laruence the realloc should only ever get triggered on the first call, or after modification of the collection, never during a gc run.

@laruence
Copy link
Member

@vektah Anyway, this break ABI BC... and SPL is used by some exts, so maybe could only goes into PHP 7 even if it is works..

that means, we still needs some ugly fix for 5.x

@laruence
Copy link
Member

hmm, after a second thought , I think it's okey, only appending... thanks... this seems much better than previouse ugly hack

Z_ARRVAL_P(gcdata_arr)->pDestructor = NULL;
if (requiredLength > intern->gcdata_len) {
if (intern->gcdata_len > 0) {
efree(intern->gcdata);
Copy link
Member

Choose a reason for hiding this comment

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

why efree here, you use erealloc blow anyway.

Copy link
Author

Choose a reason for hiding this comment

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

Initially I was doing free/emalloc. Missed it when I switched to erealloc. Oops!

@@ -86,6 +86,8 @@ typedef struct _spl_SplObjectStorage { /* {{{ */
long flags;
zend_function *fptr_get_hash;
HashTable *debug_info;
zval **gcdata;
long gcdata_len;
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you mean count? length seems not a good name for this.

@php-pulls php-pulls merged commit 482500b into php:PHP-5.5 Mar 13, 2015
@laruence
Copy link
Member

merged after a little improvement, thanks

@vektah
Copy link
Author

vektah commented Mar 14, 2015

@laruence Should this be if (intern->storage.nNumOfElements * 2 > ...?

    if (intern->storage.nNumOfElements > intern->gcdata_num) {
        intern->gcdata_num = intern->storage.nNumOfElements * 2;    
        intern->gcdata = (zval**)erealloc(intern->gcdata, sizeof(zval*) * intern->gcdata_num);
    }

@laruence
Copy link
Member

@vektah yeah, it was a typo, fixed, thanks

@vektah vektah deleted the bug69227 branch March 15, 2015 01:01
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.

4 participants