]> granicus.if.org Git - php/commitdiff
MFH: fix PECL bug #10194 (crash in Oracle client when memory limit reached in the...
authorAntony Dovgal <tony2001@php.net>
Thu, 29 Mar 2007 09:33:04 +0000 (09:33 +0000)
committerAntony Dovgal <tony2001@php.net>
Thu, 29 Mar 2007 09:33:04 +0000 (09:33 +0000)
preallocate the required buffer, so that it would fail earlier.

ext/oci8/oci8_lob.c
ext/oci8/php_oci8_int.h
ext/oci8/tests/pecl_bug10194.phpt [new file with mode: 0644]
ext/oci8/tests/pecl_bug10194_blob.phpt [new file with mode: 0644]

index 624a755dcf726c179530119c5d051d48a56f4660..10dcdcddbe3f44cf5975dd09b2ec270b3d2e5db5 100644 (file)
@@ -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;
index 8737bef6b22c546f65a94fb8f1db2c0b84aeba05..1e5233263e88dc28da93555ab10a4c2b7b4dfd94 100644 (file)
@@ -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 {{{ */
diff --git a/ext/oci8/tests/pecl_bug10194.phpt b/ext/oci8/tests/pecl_bug10194.phpt
new file mode 100644 (file)
index 0000000..1b937c4
--- /dev/null
@@ -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
diff --git a/ext/oci8/tests/pecl_bug10194_blob.phpt b/ext/oci8/tests/pecl_bug10194_blob.phpt
new file mode 100644 (file)
index 0000000..4e7be26
--- /dev/null
@@ -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