sixd Tue Jan 15 20:47:50 2008 UTC Modified files: /php-src/ext/oci8 oci8.c oci8_lob.c php_oci8_int.h /php-src/ext/oci8/tests bug43497.phpt Log: MFB: fix #43497 (OCI8 XML/getClobVal aka temporary LOBs leak UGA memory)
http://cvs.php.net/viewvc.cgi/php-src/ext/oci8/oci8.c?r1=1.339&r2=1.340&diff_format=u Index: php-src/ext/oci8/oci8.c diff -u php-src/ext/oci8/oci8.c:1.339 php-src/ext/oci8/oci8.c:1.340 --- php-src/ext/oci8/oci8.c:1.339 Mon Dec 31 07:12:12 2007 +++ php-src/ext/oci8/oci8.c Tue Jan 15 20:47:50 2008 @@ -26,7 +26,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: oci8.c,v 1.339 2007/12/31 07:12:12 sebastian Exp $ */ +/* $Id: oci8.c,v 1.340 2008/01/15 20:47:50 sixd Exp $ */ /* TODO * * file://localhost/www/docs/oci10/ociaahan.htm#423823 - implement lob_empty() with OCI_ATTR_LOBEMPTY @@ -674,7 +674,7 @@ php_info_print_table_start(); php_info_print_table_row(2, "OCI8 Support", "enabled"); php_info_print_table_row(2, "Version", "1.2.2"); - php_info_print_table_row(2, "Revision", "$Revision: 1.339 $"); + php_info_print_table_row(2, "Revision", "$Revision: 1.340 $"); snprintf(buf, sizeof(buf), "%ld", OCI_G(num_persistent)); php_info_print_table_row(2, "Active Persistent Connections", buf); @@ -1645,7 +1645,10 @@ php_oci_descriptor *descriptor; ub4 lob_length; int column_size; - zstr lob_buffer, zstr_data = ZSTR(column->data); + int lob_fetch_status; + zstr lob_buffer; + zstr zstr_data = ZSTR(column->data); + php_oci_lob_type lob_type; if (column->indicator == -1) { /* column is NULL */ ZVAL_NULL(value); @@ -1674,17 +1677,15 @@ } if (column->data_type != SQLT_RDD && (mode & PHP_OCI_RETURN_LOBS)) { - php_oci_lob_type lob_type; /* 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); + lob_fetch_status |= (php_oci_lob_get_type(descriptor, &lob_type TSRMLS_CC) > 0); + php_oci_temp_lob_close(descriptor); + if (lob_fetch_status) { ZVAL_FALSE(value); return 1; } - - if (php_oci_lob_get_type(descriptor, &lob_type TSRMLS_CC) > 0) { - return 1; - } switch (lob_type) { case OCI_IS_CLOB: http://cvs.php.net/viewvc.cgi/php-src/ext/oci8/oci8_lob.c?r1=1.31&r2=1.32&diff_format=u Index: php-src/ext/oci8/oci8_lob.c diff -u php-src/ext/oci8/oci8_lob.c:1.31 php-src/ext/oci8/oci8_lob.c:1.32 --- php-src/ext/oci8/oci8_lob.c:1.31 Mon Dec 31 07:12:12 2007 +++ php-src/ext/oci8/oci8_lob.c Tue Jan 15 20:47:50 2008 @@ -25,7 +25,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: oci8_lob.c,v 1.31 2007/12/31 07:12:12 sebastian Exp $ */ +/* $Id: oci8_lob.c,v 1.32 2008/01/15 20:47:50 sixd Exp $ */ @@ -575,7 +575,6 @@ 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)); @@ -584,7 +583,21 @@ 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) { @@ -594,7 +607,6 @@ } if (is_temporary) { - PHP_OCI_CALL_RETURN(connection->errcode, OCILobFreeTemporary, (connection->svc, connection->err, descriptor->descriptor)); if (connection->errcode != OCI_SUCCESS) { @@ -606,6 +618,7 @@ 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) @@ -652,7 +665,6 @@ Close LOB descriptor and free associated resources */ void php_oci_lob_free (php_oci_descriptor *descriptor TSRMLS_DC) { - if (!descriptor || !descriptor->connection) { return; } @@ -667,6 +679,12 @@ 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); @@ -899,7 +917,9 @@ return php_oci_lob_write(descriptor, 0, data, data_len, &bytes_written TSRMLS_CC); } /* }}} */ -int php_oci_lob_get_type(php_oci_descriptor *descriptor, php_oci_lob_type *lob_type TSRMLS_DC) /* {{{ */ +/* {{{ php_oci_lob_get_type() + Determine whether LOB is a CLOB or a BLOB */ +int php_oci_lob_get_type(php_oci_descriptor *descriptor, php_oci_lob_type *lob_type TSRMLS_DC) { php_oci_connection *connection = descriptor->connection; http://cvs.php.net/viewvc.cgi/php-src/ext/oci8/php_oci8_int.h?r1=1.38&r2=1.39&diff_format=u Index: php-src/ext/oci8/php_oci8_int.h diff -u php-src/ext/oci8/php_oci8_int.h:1.38 php-src/ext/oci8/php_oci8_int.h:1.39 --- php-src/ext/oci8/php_oci8_int.h:1.38 Mon Dec 31 07:12:12 2007 +++ php-src/ext/oci8/php_oci8_int.h Tue Jan 15 20:47:50 2008 @@ -25,7 +25,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_oci8_int.h,v 1.38 2007/12/31 07:12:12 sebastian Exp $ */ +/* $Id: php_oci8_int.h,v 1.39 2008/01/15 20:47:50 sixd Exp $ */ #if HAVE_OCI8 # ifndef PHP_OCI8_INT_H @@ -352,6 +352,7 @@ 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, zstr, int TSRMLS_DC); #endif void php_oci_lob_free(php_oci_descriptor * TSRMLS_DC); http://cvs.php.net/viewvc.cgi/php-src/ext/oci8/tests/bug43497.phpt?r1=1.1&r2=1.2&diff_format=u Index: php-src/ext/oci8/tests/bug43497.phpt diff -u /dev/null php-src/ext/oci8/tests/bug43497.phpt:1.2 --- /dev/null Tue Jan 15 20:47:50 2008 +++ php-src/ext/oci8/tests/bug43497.phpt Tue Jan 15 20:47:50 2008 @@ -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
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php