mirror of
https://github.com/php/php-src.git
synced 2024-09-22 10:27:25 +00:00
MFB: fix #43497 (OCI8 XML/getClobVal aka temporary LOBs leak UGA memory)
This commit is contained in:
parent
05534af71b
commit
ed50a373b1
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
294
ext/oci8/tests/bug43497.phpt
Normal file
294
ext/oci8/tests/bug43497.phpt
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user