Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:19405 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 73747 invoked by uid 1010); 4 Oct 2005 16:14:44 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 73731 invoked from network); 4 Oct 2005 16:14:44 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 4 Oct 2005 16:14:44 -0000 X-Host-Fingerprint: 69.12.155.130 69-12-155-130.dsl.static.sonic.net Linux 2.4/2.6 Received: from ([69.12.155.130:4528] helo=pigeon.alphaweb.net) by pb1.pair.com (ecelerity 2.0 beta r(6323M)) with SMTP id C3/45-54476-47AA2434 for ; Tue, 04 Oct 2005 12:14:44 -0400 Received: from localhost ([127.0.0.1] helo=lighthammer) by pigeon.alphaweb.net with smtp (Exim 4.10) id 1EMojj-0006Hr-00; Tue, 04 Oct 2005 08:29:48 -0700 Message-ID: <002801c5c8fe$b62d2ef0$6d561a44@lighthammer> To: "David Olsson" Cc: References: <4A.46.54476.C2272434@pb1.pair.com> Date: Tue, 4 Oct 2005 09:14:27 -0700 MIME-Version: 1.0 Content-Type: text/plain; format=flowed; charset="iso-8859-1"; reply-type=response Content-Transfer-Encoding: 7bit X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 6.00.2900.2180 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2180 Subject: Re: zval "passthrough"? From: pollita@php.net ("Sara Golemon") > 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