#43497 [Opn->Asn]: OCI8 XML/getClobVal leaks UGA memory
| From: | tony2001@php.net | Date: | Sun, 06 Jan 2008 20:42:53 +0000 |
| Subject: | #43497 [Opn->Asn]: OCI8 XML/getClobVal leaks UGA memory | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-121086@lists.php.net to get a copy of this message | ||
ID: 43497
Updated by: tony2001@php.net
Reported By: ghosh at q-one dot com
-Status: Open
+Status: Assigned
Bug Type: OCI8 related
Operating System: Linux 2.6.22-14-server
PHP Version: 5.2.5
-Assigned To:
+Assigned To: sixd
New Comment:
>What I don't understand: I thought OCI_RETURN_LOBS is just a short-
>cut for those who don't want to write:
That's what I don't understand either: does the leak appear only on
per-session basis or Oracle doesn't free those LOBs at all?
If the leak is only per-session, then users are not supposed even to
notice it, since PHP requests are not supposed to take more than several
seconds.
Previous Comments:
------------------------------------------------------------------------
[2007-12-29 22:37:21] ghosh at q-one dot com
Really great! Thanks a lot!! This patch works. What I don't understand:
I thought OCI_RETURN_LOBS is just a short-cut for those who don't want
to write:
$s=$result[0]->load();
$result[0]->free();
$result[0]=$s;
If you use OCI_RETURN_LOBS you dont want to care about lobs but get the
result as a string and forget about lobs altogether. So IMHO this should
work as well. My specific problem is solved though.
------------------------------------------------------------------------
[2007-12-27 21:44:07] sixd@php.net
This is really an issue with temporary LOBS since getClobVal()
returns a temporary LOB.
There are two parts to the fix: changing the script and patching
the OCI8 extension. Also don't forget to apply the patch for
http://bugs.php.net/bug.php?id=42496
Please test this suggestion and report any issues.
Thanks to Krishna & Shankar for the solution.
1. Change the test to get the results as LOBs, not as
strings. This allows the script to free temporary LOBs.
In the supplied testcase change:
$query = "select extract(xml, '/').getclobval() from ugatest";
$stmt = oci_parse($conn, $query);
if (oci_execute($stmt))
while ($result = oci_fetch_array($stmt,
OCI_NUM+OCI_RETURN_LOBS))
;
to:
$query = "select extract(xml, '/').getclobval() from ugatest";
$stmt = oci_parse($conn, $query);
if (oci_execute($stmt))
while ($result = oci_fetch_array($stmt, OCI_NUM)) {
// echo $result[0]->load(), "\n"; // do something with the
XML
$result[0]->free(); // free the temporary LOB
}
The connection must be open when LOB->free() is called, as the
underlying OCILobFreeTemporary() call does a roundtrip to the
database.
2. Patch oci8_lob.c. The change copies some LOB freeing code
from php_oci_lob_close() into php_oci_lob_free():
--- oci8_lob.c.orig 2007-07-31 12:21:08.000000000 -0700
+++ oci8_lob.c 2007-12-27 12:33:19.000000000 -0800
@@ -647,6 +647,9 @@
Close LOB descriptor and free associated resources */
void php_oci_lob_free (php_oci_descriptor *descriptor TSRMLS_DC)
{
+#ifdef HAVE_OCI8_TEMP_LOB
+ int is_temporary;
+#endif
if (!descriptor || !descriptor->connection) {
return;
@@ -662,6 +665,40 @@
php_oci_lob_flush(descriptor, OCI_LOB_BUFFER_FREE TSRMLS_CC);
}
+#ifdef HAVE_OCI8_TEMP_LOB
+ if (descriptor->type == OCI_DTYPE_LOB) {
+ PHP_OCI_CALL_RETURN(descriptor->connection->errcode,
+ OCILobIsTemporary,
+ (
+ descriptor->connection->env,
+ descriptor->connection->err,
+ descriptor->descriptor,
+ &is_temporary
+ )
+ );
+ if (descriptor->connection->errcode != OCI_SUCCESS) {
+ php_oci_error(descriptor->connection->err,
descriptor->connection->errcode TSRMLS_CC);
+ PHP_OCI_HANDLE_ERROR(descriptor->connection,
descriptor->connection->errcode);
+ return 1;
+ }
+ if (is_temporary) {
+ PHP_OCI_CALL_RETURN(descriptor->connection->errcode,
+ OCILobFreeTemporary,
+ (
+ descriptor->connection->svc,
+ descriptor->connection->err,
+ descriptor->descriptor
+ )
+ );
+ if (descriptor->connection->errcode != OCI_SUCCESS) {
+ php_oci_error(descriptor->connection->err,
descriptor->connection->errcode TSRMLS_CC);
+ PHP_OCI_HANDLE_ERROR(descriptor->connection,
descriptor->connection->errcode);
+ return 1;
+ }
+ }
+ }
+#endif
+
PHP_OCI_CALL(OCIDescriptorFree, (descriptor->descriptor,
descriptor->type));
zend_list_delete(descriptor->connection->rsrc_id);
------------------------------------------------------------------------
[2007-12-20 18:04:32] ghosh at q-one dot com
Would pay someone who resolves this bug. Feel free to contact me if you
are interested.
------------------------------------------------------------------------
[2007-12-05 23:18:05] sixd@php.net
Confirmed.
------------------------------------------------------------------------
[2007-12-04 13:09:49] ghosh at q-one dot com
Description:
------------
There is a memory leaking when using the OCI8 interface and querying
XML columns. Demo code available via the url below. This creates a
table with an XML column and queries this column. UGA memory is
leaking. This does not happen when doing the same directly via
SQLPlus.
Reproduce code:
---------------
http://oberon.q-one-hosting.com/6648051.txt
Expected result:
----------------
No UGA memory leaking
Actual result:
--------------
UGA memory going up. Table with temporary lobs filling up.
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=43497&edit=1