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