mirror of
https://github.com/php/php-src.git
synced 2024-09-22 02:17:32 +00:00
MFH: fix PECL bug #10194 (crash in Oracle client when memory limit reached in the callback)
preallocate the required buffer, so that it would fail earlier.
This commit is contained in:
parent
4a119f9a79
commit
26cf62d293
@ -160,7 +160,12 @@ sb4 php_oci_lob_callback (dvoid *ctxp, CONST dvoid *bufxp, ub4 len, ub1 piece)
|
||||
switch (piece)
|
||||
{
|
||||
case OCI_LAST_PIECE:
|
||||
*(ctx->lob_data) = erealloc(*(ctx->lob_data), (size_t) (*(ctx->lob_len) + lenp + 1));
|
||||
if ((*(ctx->lob_len) + lenp) > (ctx->alloc_len)) {
|
||||
/* this should not happen ever */
|
||||
*(ctx->lob_data) = NULL;
|
||||
*(ctx->lob_len) = 0;
|
||||
return OCI_ERROR;
|
||||
}
|
||||
memcpy(*(ctx->lob_data) + *(ctx->lob_len), bufxp, (size_t) lenp);
|
||||
*(ctx->lob_len) += lenp;
|
||||
*(*(ctx->lob_data) + *(ctx->lob_len)) = 0x00;
|
||||
@ -168,7 +173,12 @@ sb4 php_oci_lob_callback (dvoid *ctxp, CONST dvoid *bufxp, ub4 len, ub1 piece)
|
||||
|
||||
case OCI_FIRST_PIECE:
|
||||
case OCI_NEXT_PIECE:
|
||||
*(ctx->lob_data) = erealloc(*(ctx->lob_data), (size_t) (*(ctx->lob_len) + lenp));
|
||||
if ((*(ctx->lob_len) + lenp) > ctx->alloc_len) {
|
||||
/* this should not happen ever */
|
||||
*(ctx->lob_data) = NULL;
|
||||
*(ctx->lob_len) = 0;
|
||||
return OCI_ERROR;
|
||||
}
|
||||
memcpy(*(ctx->lob_data) + *(ctx->lob_len), bufxp, (size_t) lenp);
|
||||
*(ctx->lob_len) += lenp;
|
||||
return OCI_CONTINUE;
|
||||
@ -176,7 +186,6 @@ sb4 php_oci_lob_callback (dvoid *ctxp, CONST dvoid *bufxp, ub4 len, ub1 piece)
|
||||
default: {
|
||||
TSRMLS_FETCH();
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unexpected LOB piece id received (value:%d)", piece);
|
||||
efree(*(ctx->lob_data));
|
||||
*(ctx->lob_data) = NULL;
|
||||
*(ctx->lob_len) = 0;
|
||||
return OCI_ERROR;
|
||||
@ -226,16 +235,19 @@ int php_oci_lob_read (php_oci_descriptor *descriptor, long read_length, long ini
|
||||
oraub8 bytes_read, offset = 0;
|
||||
oraub8 requested_len = read_length; /* this is by default */
|
||||
oraub8 chars_read = 0;
|
||||
int is_clob = 0;
|
||||
#else
|
||||
int bytes_read, offset = 0;
|
||||
int requested_len = read_length; /* this is by default */
|
||||
#endif
|
||||
int is_clob = 0;
|
||||
sb4 bytes_per_char = 1;
|
||||
|
||||
*data_len = 0;
|
||||
*data = NULL;
|
||||
|
||||
ctx.lob_len = data_len;
|
||||
ctx.lob_data = data;
|
||||
ctx.alloc_len = 0;
|
||||
|
||||
if (php_oci_lob_get_length(descriptor, &length TSRMLS_CC)) {
|
||||
return 1;
|
||||
@ -272,9 +284,7 @@ int php_oci_lob_read (php_oci_descriptor *descriptor, long read_length, long ini
|
||||
PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_OCI_LOB_READ2
|
||||
else {
|
||||
} else {
|
||||
ub2 charset_id = 0;
|
||||
|
||||
PHP_OCI_CALL_RETURN(connection->errcode, OCILobCharSetId, (connection->env, connection->err, descriptor->descriptor, &charset_id));
|
||||
@ -290,6 +300,22 @@ int php_oci_lob_read (php_oci_descriptor *descriptor, long read_length, long ini
|
||||
}
|
||||
}
|
||||
|
||||
if (is_clob) {
|
||||
PHP_OCI_CALL_RETURN(connection->errcode, OCINlsNumericInfoGet, (connection->env, connection->err, &bytes_per_char, OCI_NLS_CHARSET_MAXBYTESZ));
|
||||
|
||||
if (connection->errcode != OCI_SUCCESS) {
|
||||
php_oci_error(connection->err, connection->errcode TSRMLS_CC);
|
||||
PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
/* BLOBs don't have encoding, so bytes_per_char == 1 */
|
||||
}
|
||||
|
||||
ctx.alloc_len = (requested_len + 1) * bytes_per_char;
|
||||
*data = ecalloc(bytes_per_char, requested_len + 1);
|
||||
|
||||
#ifdef HAVE_OCI_LOB_READ2
|
||||
if (is_clob) {
|
||||
chars_read = requested_len;
|
||||
bytes_read = 0;
|
||||
|
@ -134,6 +134,7 @@ typedef struct { /* php_oci_descriptor {{{ */
|
||||
typedef struct { /* php_oci_lob_ctx {{{ */
|
||||
char **lob_data; /* address of pointer to LOB data */
|
||||
ub4 *lob_len; /* address of LOB length variable (bytes) */
|
||||
ub4 alloc_len;
|
||||
} php_oci_lob_ctx; /* }}} */
|
||||
|
||||
typedef struct { /* php_oci_collection {{{ */
|
||||
|
47
ext/oci8/tests/pecl_bug10194.phpt
Normal file
47
ext/oci8/tests/pecl_bug10194.phpt
Normal file
@ -0,0 +1,47 @@
|
||||
--TEST--
|
||||
PECL Bug #10194 (segfault in Instant Client when memory_limit is reached inside the callback)
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
require dirname(__FILE__).'/connect.inc';
|
||||
require dirname(__FILE__).'/create_table.inc';
|
||||
|
||||
$ora_sql = "INSERT INTO
|
||||
".$schema.$table_name." (clob)
|
||||
VALUES (empty_clob())
|
||||
";
|
||||
|
||||
$statement = oci_parse($c,$ora_sql);
|
||||
oci_execute($statement);
|
||||
|
||||
$ora_sql = "SELECT clob FROM ".$schema.$table_name." FOR UPDATE";
|
||||
$statement = oci_parse($c,$ora_sql);
|
||||
oci_execute($statement, OCI_DEFAULT);
|
||||
|
||||
$row = oci_fetch_assoc($statement);
|
||||
|
||||
$string = str_repeat("test", 32768*4*4);
|
||||
|
||||
for ($i = 0; $i < 8; $i++) {
|
||||
$row['CLOB']->write($string);
|
||||
}
|
||||
|
||||
oci_commit($c);
|
||||
|
||||
$ora_sql = "SELECT clob FROM ".$schema.$table_name."";
|
||||
$statement = oci_parse($c,$ora_sql);
|
||||
oci_execute($statement);
|
||||
|
||||
$row = oci_fetch_assoc($statement);
|
||||
var_dump(strlen($row['CLOB']->load())); /* here it should fail */
|
||||
|
||||
require dirname(__FILE__).'/drop_table.inc';
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of 10485760 bytes exhausted at %s:%d (tried to allocate %d bytes) in %s on line %d
|
47
ext/oci8/tests/pecl_bug10194_blob.phpt
Normal file
47
ext/oci8/tests/pecl_bug10194_blob.phpt
Normal file
@ -0,0 +1,47 @@
|
||||
--TEST--
|
||||
PECL Bug #10194 (segfault in Instant Client when memory_limit is reached inside the callback)
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
|
||||
--INI--
|
||||
memory_limit=10M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
require dirname(__FILE__).'/connect.inc';
|
||||
require dirname(__FILE__).'/create_table.inc';
|
||||
|
||||
$ora_sql = "INSERT INTO
|
||||
".$schema.$table_name." (blob)
|
||||
VALUES (empty_blob())
|
||||
";
|
||||
|
||||
$statement = oci_parse($c,$ora_sql);
|
||||
oci_execute($statement);
|
||||
|
||||
$ora_sql = "SELECT blob FROM ".$schema.$table_name." FOR UPDATE";
|
||||
$statement = oci_parse($c,$ora_sql);
|
||||
oci_execute($statement, OCI_DEFAULT);
|
||||
|
||||
$row = oci_fetch_assoc($statement);
|
||||
|
||||
$string = str_repeat("test", 32768*4*4);
|
||||
|
||||
for ($i = 0; $i < 8; $i++) {
|
||||
$row['BLOB']->write($string);
|
||||
}
|
||||
|
||||
oci_commit($c);
|
||||
|
||||
$ora_sql = "SELECT blob FROM ".$schema.$table_name."";
|
||||
$statement = oci_parse($c,$ora_sql);
|
||||
oci_execute($statement);
|
||||
|
||||
$row = oci_fetch_assoc($statement);
|
||||
var_dump(strlen($row['BLOB']->load())); /* here it should fail */
|
||||
|
||||
require dirname(__FILE__).'/drop_table.inc';
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Allowed memory size of %d bytes exhausted at %s:%d (tried to allocate %d bytes) in %s on line %d
|
Loading…
Reference in New Issue
Block a user