Hello David,

Thursday, October 6, 2005, 9:49:35 AM, you wrote:

> Thanks! That was very useful information. Had to go with the #3a 
> solution as I need to be compatible with PHP4.

> I still have some problems with my extension though. The extension 
> maintains a module global C++ std::map allocated in my MINIT function 
> and deallocated in my MSHUTDOWN function. This map stores some zval * 
> added to the map like this:

>         int nameLen;
>         char *name;
>         zval *v;
>         zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz!", &v);
>         zval *newv = new zval[1];
>         *newv = *v;
>         zval_copy_ctor(newv);
>         (*reinterpret_cast<map<string, zval *> *>(PSV_G(psvs)))[name] = newv;

 do you have any idea what a reinterpret_cast<>() does? So probably change
 your code so that you are actually use what you think you do.

 apart from that you should consider storing the zval's rather than pointers.

> where PSV_G(psvs) is a pointer to the map. The problem is that the 
> content of the map may change or dissapear without my extension 
> accessing it at all. Does the Zend engine do anything with the memory I 
> have allocated? Currently i allocate memory for the map with new instead 
> of emalloc but should that make any difference (except for larger risks 
> for memory leaks)?

> Thanks in advance!
> David Olsson

> Sara Golemon wrote:
>>> I'm writing a PHP extension in C++ which need to provide a function 
>>> which will take as a parameter a zval *. This zval * should, when the 
>>> function has completed its task, simply be returned unmodified. How do 
>>> I accomplish this? I've tried something like this:
>>>
>>> return_value = v;
>>>
>> There are two problems here:
>> 
>> #1 return_value is just a parameter in the prototype:
>> 
>> void zif_my_func(int ht, zval *return_value, zval **return_value_ptr, 
>> zval *this_ptr, int return_value_used TSRMLS_DC)
>> 
>> So when you set:   return_value = v;   You are in fact changing where 
>> return_value points, but you're not doing anything to the contents of 
>> the return_value zval that the calling scope (the engine) knows about.  
>> You're just changing the local pointer to look at another address.
>> 
>> Using return_value_ptr you can both clean up the original memory 
>> allocated for return_value, and change what the engine knows about 
>> return_value since you have the pointer to the pointer which the engine 
>> uses:
>> 
>> /* Destroy old return_value (prevents leaks) */
>> zval_ptr_dtor(return_value_ptr);
>> 
>> /* Point return_value at the passed in val */
>> *return_value_ptr = v;
>> 
>> This brings us to the second problem:
>> 
>> #2 The refcount of v will have been temporarily increased by the engine 
>> when it was placed on the parameter stack, however when the function 
>> exits, that refcount will be decremented back down and there will be no 
>> refcount associated with the copy stored in return_value.  Long story 
>> short you need to add ref the value when you assign it to a new container:
>> 
>> ZVAL_ADDREF(v);
>> zval_ptr_dtor(return_value_ptr);
>> *return_value_ptr = v;
>> 
>> 
>> Now for problem number 3 (What, you thought I'd stop at two?)
>> 
>> If v was an is_ref value, with a refcount of only 2 at the time of 
>> leaving your internal function, and you're using PHP 5.0, the function 
>> return will break the reference set.  This is a known bug and is fixed 
>> in the 5.1 branch.
>> 
>> And problem #3a (PHP4 compatability)
>> 
>> PHP4 doesn't even have the return_value_ptr parameter so you can't even 
>> do that stuff with it.  What you can do is perform a deep copy on the 
>> value:
>> 
>> *return_value = *v;
>> zval_copy_ctor(return_value);
>> 
>> While it's less memory/cpu efficient, it is usable across all versions.
>> 
>> -Sara




Best regards,
 Marcus

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

Reply via email to