From: Antony Dovgal Date: Thu, 29 Mar 2007 09:30:25 +0000 (+0000) Subject: fix #10194 (crash in Oracle client when memory limit reached in the callback) X-Git-Tag: RELEASE_1_1_0~85 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9d57173cdf66846053d1fbfe6e36326e0273dcab;p=php fix #10194 (crash in Oracle client when memory limit reached in the callback) preallocate the required buffer, so that it would fail earlier. --- diff --git a/ext/oci8/oci8_lob.c b/ext/oci8/oci8_lob.c index 519efea4d1..a8fcf7df67 100644 --- a/ext/oci8/oci8_lob.c +++ b/ext/oci8/oci8_lob.c @@ -161,7 +161,13 @@ 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 + TEXT_BYTES(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; @@ -174,14 +180,19 @@ 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; default: 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; @@ -235,11 +246,13 @@ int php_oci_lob_read (php_oci_descriptor *descriptor, long read_length, long ini int bytes_read, offset = 0; int requested_len = read_length; /* this is by default */ #endif + sb4 bytes_per_char = 1; *data_len = 0; *data = NULL_ZSTR; ctx.lob_len = data_len; ctx.lob_data = &(data->s); + ctx.alloc_len = 0; if (php_oci_lob_get_length(descriptor, &length TSRMLS_CC)) { return 1; @@ -282,6 +295,21 @@ int php_oci_lob_read (php_oci_descriptor *descriptor, long read_length, long ini return 1; } + if (lob_type == OCI_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 + UBYTES(1)) * bytes_per_char; + data->s = ecalloc(bytes_per_char, requested_len + UBYTES(1)); + #ifdef HAVE_OCI_LOB_READ2 if (lob_type == OCI_IS_CLOB) { chars_read = requested_len; diff --git a/ext/oci8/php_oci8_int.h b/ext/oci8/php_oci8_int.h index 3ecbb62e34..56101330f9 100644 --- a/ext/oci8/php_oci8_int.h +++ b/ext/oci8/php_oci8_int.h @@ -141,6 +141,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 {{{ */ diff --git a/ext/oci8/tests/pecl_bug10194.phpt b/ext/oci8/tests/pecl_bug10194.phpt new file mode 100644 index 0000000000..1b937c4905 --- /dev/null +++ b/ext/oci8/tests/pecl_bug10194.phpt @@ -0,0 +1,47 @@ +--TEST-- +PECL Bug #10194 (segfault in Instant Client when memory_limit is reached inside the callback) +--SKIPIF-- + +--INI-- +memory_limit=10M +--FILE-- +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 diff --git a/ext/oci8/tests/pecl_bug10194_blob.phpt b/ext/oci8/tests/pecl_bug10194_blob.phpt new file mode 100644 index 0000000000..4e7be26c7f --- /dev/null +++ b/ext/oci8/tests/pecl_bug10194_blob.phpt @@ -0,0 +1,47 @@ +--TEST-- +PECL Bug #10194 (segfault in Instant Client when memory_limit is reached inside the callback) +--SKIPIF-- + +--INI-- +memory_limit=10M +--FILE-- +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