On 26.11.2016 at 12:45, Nikita Popov wrote:

> On Sat, Nov 26, 2016 at 12:29 PM, Christoph M. Becker <cmbecke...@gmx.de>
> wrote:
> 
>> On 26.11.2016 at 01:47, Thomas Hruska wrote:
>>
>>> Okay, everyone has been helpful.  Thanks.  I'll go with:
>>>
>>>
>>>     zval *zprevcount = NULL;
>>>     zend_long count;
>>>
>>>     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/",
>>> &zprevcount) == FAILURE)  return;
>>>
>>>     ...
>>>
>>>     if (zprevcount != NULL)
>>>     {
>>>         count = (zend_long)PrevCount;
>>>
>>>         zval_dtor(zprevcount);
>>>         ZVAL_LONG(zprevcount, count);
>>>     }
>>>
>>>
>>> Just one little thing I found in php_str_replace_common() in
>>> ext/standard/string.c.  That particular function calls zval_ptr_dtor()
>>> instead of zval_dtor() on zcount.  Just wondering why it does that - I'm
>>> thinking it has something to do with removing the ZPP call for PHP 7 and
>>> using the (mostly undocumented?) Z_PARAM_ZVAL_EX() macro.  However,
>>> php_do_pcre_match() over in ext/pcre/php_pcre.c calls zval_dtor() on
>>> subpats but also uses the Z_PARAM_ZVAL_EX() macro in a similar fashion.
>>> Looking back at PHP 5.6's php_str_replace_common() shows that it
>>> previously called zval_dtor().  So it might also be a bug of some sort.
>>
>> zval_dtor() destroys the value; zval_ptr_dtor() decrements the refcount,
>> and destroys the value only if the refcount has dropped to 0.  See also
>> <http://www.phpinternalsbook.com/zvals/memory_management.html> (which is
>> written for PHP 5, but is still useful).
>>
>> In your case, zval_dtor() is appropriate, as the zval has already been
>> separated (ZPP's /), so there can't be other references.
> 
> The situation here has become a bit confusing in PHP 7. zval_dtor() is now
> actually the same as zval_ptr_dtor_nogc(). As such, you can use zval_dtor()
> on zvals with rc>1, but collectible zvals will not be added to the GC root
> buffer.
> 
> In the vast majority of cases, you will want to use zval_ptr_dtor().
> zval_dtor() / zval_ptr_dtor_nogc() are useful either as an optimization in
> cases where you know for certain that a value is a root, or to prevent
> values from being placed in the GC root buffer, in cases where this
> violates the memory model (e.g. this is relevant for opcache'd literals).

Thanks for the explanation, Nikita.

> The fact that php_pcre.c uses zval_dtor() is simply a bug, because code like
> 
>     $obj = new stdClass;
>     $obj->obj = $obj;
>     preg_match('/./', 'x', $obj);
> 
> leaks.

Indeed.  At least preg_replace()'s $count parameter has the same issue.
Is there already a bug report about this?

-- 
Christoph M. Becker

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to