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;
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
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php