]> granicus.if.org Git - php/commitdiff
MFB: fix #43497 (OCI8 XML/getClobVal aka temporary LOBs leak UGA memory)
authorChristopher Jones <sixd@php.net>
Tue, 15 Jan 2008 20:44:31 +0000 (20:44 +0000)
committerChristopher Jones <sixd@php.net>
Tue, 15 Jan 2008 20:44:31 +0000 (20:44 +0000)
ext/oci8/oci8.c
ext/oci8/oci8_lob.c
ext/oci8/php_oci8_int.h
ext/oci8/tests/bug43497.phpt [new file with mode: 0644]

index ac7c9f0bfce4e6e53e668223f3537820d9d713b0..231e7b24d05bde5dfb859c09fddb8f5ea6eb06c4 100644 (file)
@@ -1604,6 +1604,7 @@ int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode TSR
        ub4 lob_length;
        int column_size;
        char *lob_buffer;
+       int lob_fetch_status;
        
        if (column->indicator == -1) { /* column is NULL */ 
                ZVAL_NULL(value); 
@@ -1634,7 +1635,9 @@ int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode TSR
                if (column->data_type != SQLT_RDD && (mode & PHP_OCI_RETURN_LOBS)) {
                        /* PHP_OCI_RETURN_LOBS means that we want the content of the LOB back instead of the locator */
                        
-                       if (php_oci_lob_read(descriptor, -1, 0, &lob_buffer, &lob_length TSRMLS_CC)) {
+                       lob_fetch_status = php_oci_lob_read(descriptor, -1, 0, &lob_buffer, &lob_length TSRMLS_CC);
+                       php_oci_temp_lob_close(descriptor);
+                       if (lob_fetch_status) {
                                ZVAL_FALSE(value);
                                return 1;
                        } else {
index 24c79850114cdb212abd23e67fc4dd16d15accfd..2c0dc84342fd25e6a8907291c1b265812e66b90c 100644 (file)
@@ -570,7 +570,6 @@ int php_oci_lob_copy (php_oci_descriptor *descriptor_dest, php_oci_descriptor *d
 int php_oci_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
 {
        php_oci_connection *connection = descriptor->connection;
-       int is_temporary;
        
        PHP_OCI_CALL_RETURN(connection->errcode, OCILobClose, (connection->svc, connection->err, descriptor->descriptor));
 
@@ -579,7 +578,21 @@ int php_oci_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
                PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
                return 1;
        }
+
+       if (php_oci_temp_lob_close(descriptor)) {
+               return 1;
+       }
        
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_temp_lob_close() 
+   Close Temporary LOB */
+int php_oci_temp_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
+{
+       php_oci_connection *connection = descriptor->connection;
+       int is_temporary;
+
        PHP_OCI_CALL_RETURN(connection->errcode, OCILobIsTemporary, (connection->env,connection->err, descriptor->descriptor, &is_temporary));
        
        if (connection->errcode != OCI_SUCCESS) {
@@ -589,7 +602,6 @@ int php_oci_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
        }
        
        if (is_temporary) {
-               
                PHP_OCI_CALL_RETURN(connection->errcode, OCILobFreeTemporary, (connection->svc, connection->err, descriptor->descriptor));
                
                if (connection->errcode != OCI_SUCCESS) {
@@ -601,6 +613,7 @@ int php_oci_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
        return 0;
 } /* }}} */
 
+
 /* {{{ php_oci_lob_flush() 
  Flush buffers for the LOB (only if they have been used) */
 int php_oci_lob_flush(php_oci_descriptor *descriptor, long flush_flag TSRMLS_DC)
@@ -647,7 +660,6 @@ int php_oci_lob_flush(php_oci_descriptor *descriptor, long flush_flag TSRMLS_DC)
  Close LOB descriptor and free associated resources */
 void php_oci_lob_free (php_oci_descriptor *descriptor TSRMLS_DC)
 {
-
        if (!descriptor || !descriptor->connection) {
                return;
        }
@@ -662,6 +674,12 @@ void php_oci_lob_free (php_oci_descriptor *descriptor TSRMLS_DC)
                php_oci_lob_flush(descriptor, OCI_LOB_BUFFER_FREE TSRMLS_CC);
        }
 
+#ifdef HAVE_OCI8_TEMP_LOB
+       if (descriptor->type == OCI_DTYPE_LOB) {
+               php_oci_temp_lob_close(descriptor);
+       }
+#endif
+
        PHP_OCI_CALL(OCIDescriptorFree, (descriptor->descriptor, descriptor->type));
 
        zend_list_delete(descriptor->connection->rsrc_id);
index b9005d1f1e83fb59f45214a2a2160ffa9cea1747..aaa10087afdd6167fe4561f5477c0600dc722c05 100644 (file)
@@ -342,6 +342,7 @@ int php_oci_lob_get_buffering (php_oci_descriptor *);
 int php_oci_lob_copy (php_oci_descriptor *, php_oci_descriptor *, long TSRMLS_DC);
 #ifdef HAVE_OCI8_TEMP_LOB
 int php_oci_lob_close (php_oci_descriptor * TSRMLS_DC);
+int php_oci_temp_lob_close (php_oci_descriptor * TSRMLS_DC);
 int php_oci_lob_write_tmp (php_oci_descriptor *, ub1, char *, int TSRMLS_DC);
 #endif
 void php_oci_lob_free(php_oci_descriptor * TSRMLS_DC);
diff --git a/ext/oci8/tests/bug43497.phpt b/ext/oci8/tests/bug43497.phpt
new file mode 100644 (file)
index 0000000..908fe58
--- /dev/null
@@ -0,0 +1,294 @@
+--TEST--
+Bug #43497 (OCI8 XML/getClobVal aka temporary LOBs leak UGA memory)
+--SKIPIF--
+<?php if (!extension_loaded('oci8')) die ("skip no oci8 extension"); ?>
+--FILE--
+<?php
+
+require dirname(__FILE__).'/connect.inc';
+
+function sessionid($c)  // determines and returns current session ID
+{
+    $query = "select sid from v\$session where audsid = userenv('sessionid')";
+
+    $stmt = oci_parse($c, $query);
+
+    if (oci_execute($stmt, OCI_DEFAULT)) {
+               $row = oci_fetch($stmt);
+               return oci_result($stmt, 1);
+    }
+
+    return null;
+}
+
+
+function templobs($c, $sid)  // returns number of temporary LOBs
+{
+    $query = "select abstract_lobs from v\$temporary_lobs where sid = " . $sid;
+
+    $stmt = oci_parse($c, $query);
+
+    if (oci_execute($stmt, OCI_DEFAULT)) {
+               $row = oci_fetch($stmt);
+               $val = oci_result($stmt, 1);
+               oci_free_statement($stmt);
+               return $val;
+    }
+    return null;
+}
+
+
+// Read all XML data using explicit LOB locator
+function readxmltab_ex($c)
+{
+    $stmt = oci_parse($c, "select extract(xml, '/').getclobval() from bug43497_tab");
+
+       $cntchk = 0;
+       if (oci_execute($stmt)) {
+               while ($result = oci_fetch_array($stmt, OCI_NUM)) {
+                       $result[0]->free();   // cleanup properly
+                       ++$cntchk;
+               }
+       }
+       echo "Loop count check = $cntchk\n";
+}
+
+// Read all XML data using explicit LOB locator but without freeing the temp lobs
+function readxmltab_ex_nofree($c)
+{
+    $stmt = oci_parse($c, "select extract(xml, '/').getclobval() from bug43497_tab");
+
+       $cntchk = 0;
+       if (oci_execute($stmt)) {
+               while ($result = oci_fetch_array($stmt, OCI_NUM)) {
+                       ++$cntchk;
+               }
+       }
+       echo "Loop count check = $cntchk\n";
+}
+
+// Read all XML data using implicit LOB locator
+function readxmltab_im($c)
+{
+    $stmt = oci_parse($c, "select extract(xml, '/').getclobval() from bug43497_tab");
+
+       $cntchk = 0;
+       if (oci_execute($stmt)) {
+               while ($result = oci_fetch_array($stmt, OCI_NUM+OCI_RETURN_LOBS)) {
+                       ++$cntchk;
+               }
+       }
+       echo "Loop count check = $cntchk\n";
+}
+
+function createxmltab($c)  // create table w/ field of XML type
+{
+       @dropxmltab($c);
+    $stmt = oci_parse($c, "create table bug43497_tab (id number primary key, xml xmltype)");
+    oci_execute($stmt);
+}
+
+function dropxmltab($c)  // delete table
+{
+    $stmt = oci_parse($c, "drop table bug43497_tab");
+    oci_execute($stmt);
+}
+
+
+function fillxmltab($c)
+{
+       for ($id = 1; $id <= 100; $id++) {
+               
+               // create an XML element string with random data                
+               $s = "<data>";
+               for ($j = 0; $j < 128; $j++) {
+                       $s .= rand();           
+               }
+               $s .= "</data>\n";              
+               for ($j = 0; $j < 4; $j++) {
+                       $s .= $s;
+               }               
+               $data = "<?xml version=\"1.0\"?><records>" . $s . "</records>";
+               
+               // insert XML data into database
+               
+               $stmt = oci_parse($c, "insert into bug43497_tab(id, xml) values (:id, sys.xmltype.createxml(:xml))");
+               oci_bind_by_name($stmt, ":id", $id);
+               $clob = oci_new_descriptor($c, OCI_D_LOB);
+               oci_bind_by_name($stmt, ":xml", $clob, -1, OCI_B_CLOB);
+               $clob->writetemporary($data);
+               oci_execute($stmt);
+               
+               $clob->close();
+               $clob->free();
+       }
+}
+
+
+// Initialize
+
+createxmltab($c);
+fillxmltab($c);
+
+// Run Test
+
+$sid = sessionid($c);
+
+echo "Explicit LOB use\n";
+for ($i = 1; $i <= 10; $i++) {
+    echo "\nRun              = " . $i . "\n";
+    echo "Temporary LOBs   = " . templobs($c, $sid) . "\n";
+    readxmltab_ex($c);
+}
+
+echo "\nImplicit LOB use\n";
+for ($i = 1; $i <= 10; $i++) {
+    echo "\nRun              = " . $i . "\n";
+    echo "Temporary LOBs   = " . templobs($c, $sid) . "\n";
+    readxmltab_im($c);
+}
+
+echo "\nExplicit LOB with no free (i.e. a temp lob leak)\n";
+for ($i = 1; $i <= 10; $i++) {
+    echo "\nRun              = " . $i . "\n";
+    echo "Temporary LOBs   = " . templobs($c, $sid) . "\n";
+    readxmltab_ex_nofree($c);
+}
+
+
+
+// Cleanup
+
+dropxmltab($c);
+
+oci_close($c);
+
+echo "Done\n";
+?>
+--EXPECT--
+Explicit LOB use
+
+Run              = 1
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 2
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 3
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 4
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 5
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 6
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 7
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 8
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 9
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 10
+Temporary LOBs   = 0
+Loop count check = 100
+
+Implicit LOB use
+
+Run              = 1
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 2
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 3
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 4
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 5
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 6
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 7
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 8
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 9
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 10
+Temporary LOBs   = 0
+Loop count check = 100
+
+Explicit LOB with no free (i.e. a temp lob leak)
+
+Run              = 1
+Temporary LOBs   = 0
+Loop count check = 100
+
+Run              = 2
+Temporary LOBs   = 99
+Loop count check = 100
+
+Run              = 3
+Temporary LOBs   = 198
+Loop count check = 100
+
+Run              = 4
+Temporary LOBs   = 297
+Loop count check = 100
+
+Run              = 5
+Temporary LOBs   = 396
+Loop count check = 100
+
+Run              = 6
+Temporary LOBs   = 495
+Loop count check = 100
+
+Run              = 7
+Temporary LOBs   = 594
+Loop count check = 100
+
+Run              = 8
+Temporary LOBs   = 693
+Loop count check = 100
+
+Run              = 9
+Temporary LOBs   = 792
+Loop count check = 100
+
+Run              = 10
+Temporary LOBs   = 891
+Loop count check = 100
+Done