diff options
author | Christopher Jones <christopher.jones@oracle.com> | 2016-10-17 12:40:14 +1100 |
---|---|---|
committer | Christopher Jones <christopher.jones@oracle.com> | 2016-10-17 12:40:14 +1100 |
commit | 8be59a13017f16396e862a8e50c888afafe1952d (patch) | |
tree | b329a36c0caf04d30b958dc537665aa83fee965b | |
parent | d82da7de3a460f1eee3d34448be79bca3de7abc1 (diff) | |
download | php-git-8be59a13017f16396e862a8e50c888afafe1952d.tar.gz |
Fixed bug #71148 (Bind reference overwritten on PHP 7)
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | ext/oci8/oci8.c | 5 | ||||
-rw-r--r-- | ext/oci8/oci8_interface.c | 2 | ||||
-rw-r--r-- | ext/oci8/oci8_statement.c | 61 | ||||
-rw-r--r-- | ext/oci8/package.xml | 26 | ||||
-rw-r--r-- | ext/oci8/php_oci8.h | 2 | ||||
-rw-r--r-- | ext/oci8/php_oci8_int.h | 1 | ||||
-rw-r--r-- | ext/oci8/tests/bug71148.phpt | 191 | ||||
-rw-r--r-- | ext/oci8/tests/driver_name.phpt | 6 |
9 files changed, 264 insertions, 33 deletions
@@ -18,6 +18,9 @@ PHP NEWS . Fixed bug #73279 (Integer overflow in gdImageScaleBilinearPalette()). (cmb) . Fixed bug #73280 (Stack Buffer Overflow in GD dynamicGetbuf). (cmb) +- OCI8 + . Fixed bug #71148 (Bind reference overwritten on PHP 7). (Oracle Corp.) + - phpdbg: . Properly allow for stdin input from a file. (Bob) . Add -s command line option / stdin command for reading script from stdin. diff --git a/ext/oci8/oci8.c b/ext/oci8/oci8.c index 0527b55847..59f993160c 100644 --- a/ext/oci8/oci8.c +++ b/ext/oci8/oci8.c @@ -1387,6 +1387,11 @@ void php_oci_bind_hash_dtor(zval *data) { php_oci_bind *bind = (php_oci_bind *) Z_PTR_P(data); + if (!Z_ISUNDEF(bind->parameter)) { + zval_ptr_dtor(&bind->parameter); + ZVAL_UNDEF(&bind->parameter); + } + if (bind->array.elements) { efree(bind->array.elements); bind->array.elements = NULL; diff --git a/ext/oci8/oci8_interface.c b/ext/oci8/oci8_interface.c index 727ec3e1c7..18714d16ed 100644 --- a/ext/oci8/oci8_interface.c +++ b/ext/oci8/oci8_interface.c @@ -110,7 +110,7 @@ PHP_FUNCTION(oci_bind_by_name) zval *bind_var = NULL; php_oci_statement *statement; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsz/|ll", &z_statement, &name, &name_len, &bind_var, &maxlen, &type) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsz|ll", &z_statement, &name, &name_len, &bind_var, &maxlen, &type) == FAILURE) { return; } diff --git a/ext/oci8/oci8_statement.c b/ext/oci8/oci8_statement.c index d4f08150e7..2b1fc4c1f1 100644 --- a/ext/oci8/oci8_statement.c +++ b/ext/oci8/oci8_statement.c @@ -1094,13 +1094,20 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l int mode = OCI_DATA_AT_EXEC; sb4 value_sz = -1; sword errstatus; + zval *param = NULL; + + if (!Z_ISREF_P(var)) { + param = var; + } else { + param = Z_REFVAL_P(var); + } switch (type) { case SQLT_NTY: { zval *tmp; - if (Z_TYPE_P(var) != IS_OBJECT || (tmp = zend_hash_str_find(Z_OBJPROP_P(var), "collection", sizeof("collection")-1)) == NULL) { + if (Z_TYPE_P(param) != IS_OBJECT || (tmp = zend_hash_str_find(Z_OBJPROP_P(param), "collection", sizeof("collection")-1)) == NULL) { php_error_docref(NULL, E_WARNING, "Unable to find collection property"); return 1; } @@ -1122,7 +1129,7 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l { zval *tmp; - if (Z_TYPE_P(var) != IS_OBJECT || (tmp = zend_hash_str_find(Z_OBJPROP_P(var), "descriptor", sizeof("descriptor")-1)) == NULL) { + if (Z_TYPE_P(param) != IS_OBJECT || (tmp = zend_hash_str_find(Z_OBJPROP_P(param), "descriptor", sizeof("descriptor")-1)) == NULL) { php_error_docref(NULL, E_WARNING, "Unable to find descriptor property"); return 1; } @@ -1141,17 +1148,17 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l case SQLT_INT: case SQLT_NUM: - if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) { + if (Z_TYPE_P(param) == IS_RESOURCE || Z_TYPE_P(param) == IS_OBJECT) { php_error_docref(NULL, E_WARNING, "Invalid variable used for bind"); return 1; } - convert_to_long(var); + convert_to_long(param); #if defined(OCI_MAJOR_VERSION) && (OCI_MAJOR_VERSION > 10) && \ (defined(__x86_64__) || defined(__LP64__) || defined(_LP64) || defined(_WIN64)) - bind_data = (ub8 *)&Z_LVAL_P(var); + bind_data = (ub8 *)&Z_LVAL_P(param); value_sz = sizeof(ub8); #else - bind_data = (ub4 *)&Z_LVAL_P(var); + bind_data = (ub4 *)&Z_LVAL_P(param); value_sz = sizeof(ub4); #endif mode = OCI_DEFAULT; @@ -1162,20 +1169,20 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l case SQLT_LNG: case SQLT_AFC: case SQLT_CHR: /* SQLT_CHR is the default value when type was not specified */ - if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) { + if (Z_TYPE_P(param) == IS_RESOURCE || Z_TYPE_P(param) == IS_OBJECT) { php_error_docref(NULL, E_WARNING, "Invalid variable used for bind"); return 1; } - if (Z_TYPE_P(var) != IS_NULL) { - convert_to_string(var); + if (Z_TYPE_P(param) != IS_NULL) { + convert_to_string(param); } if ((maxlength == -1) || (maxlength == 0)) { if (type == SQLT_LNG) { value_sz = SB4MAXVAL; - } else if (Z_TYPE_P(var) == IS_STRING) { - value_sz = (sb4) Z_STRLEN_P(var); + } else if (Z_TYPE_P(param) == IS_STRING) { + value_sz = (sb4) Z_STRLEN_P(param); } else { - /* Bug-72524: revert value_sz from PHP_OCI_PIECE_SIZE to 0. This restores PHP 5.6 behavior */ + /* Bug-72524: revert value_sz from PHP_OCI_PIECE_SIZE to 0. This restores PHP 5.6 behavior */ value_sz = 0; } } else { @@ -1184,11 +1191,11 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l break; case SQLT_RSET: - if (Z_TYPE_P(var) != IS_RESOURCE) { + if (Z_TYPE_P(param) != IS_RESOURCE) { php_error_docref(NULL, E_WARNING, "Invalid variable used for bind"); return 1; } - PHP_OCI_ZVAL_TO_STATEMENT_EX(var, bind_statement); + PHP_OCI_ZVAL_TO_STATEMENT_EX(param, bind_statement); value_sz = sizeof(void*); oci_stmt = bind_statement->stmt; @@ -1200,15 +1207,15 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l #if defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION >= 12 case SQLT_BOL: - if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) { + if (Z_TYPE_P(param) == IS_RESOURCE || Z_TYPE_P(param) == IS_OBJECT) { php_error_docref(NULL, E_WARNING, "Invalid variable used for bind"); return 1; } - convert_to_boolean(var); - bind_data = (zend_long *)&Z_LVAL_P(var); - if (Z_TYPE_P(var) == IS_TRUE) + convert_to_boolean(param); + bind_data = (zend_long *)&Z_LVAL_P(param); + if (Z_TYPE_P(param) == IS_TRUE) *(zend_long *)bind_data = 1; - else if (Z_TYPE_P(var) == IS_FALSE) + else if (Z_TYPE_P(param) == IS_FALSE) *(zend_long *)bind_data = 0; else { php_error_docref(NULL, E_WARNING, "Invalid variable used for bind"); @@ -1234,6 +1241,10 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l if ((old_bind = zend_hash_str_find_ptr(statement->binds, name, name_len)) != NULL) { bindp = old_bind; + if (!Z_ISUNDEF(bindp->parameter)) { + zval_ptr_dtor(&bindp->parameter); + ZVAL_UNDEF(&bindp->parameter); + } } else { zend_string *zvtmp; zvtmp = zend_string_init(name, name_len, 0); @@ -1241,16 +1252,20 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l bindp = zend_hash_update_ptr(statement->binds, zvtmp, bindp); zend_string_release(zvtmp); } - /* Make sure the minimum of value_sz is 1 to avoid ORA-3149 - * when both in/out parameters are bound with empty strings - */ + + /* Keep a copy of bound variable in the bind hash */ + ZVAL_COPY(&bindp->parameter, var); + + /* Make sure the minimum of value_sz is 1 to avoid ORA-3149 + * when both in/out parameters are bound with empty strings + */ if (value_sz == 0) value_sz = 1; bindp->descriptor = oci_desc; bindp->statement = oci_stmt; bindp->parent_statement = statement; - bindp->zval = var; + bindp->zval = param; bindp->type = type; /* Storing max length set in OCIBindByName() to check it later in * php_oci_bind_in_callback() function to avoid ORA-1406 error while diff --git a/ext/oci8/package.xml b/ext/oci8/package.xml index 29b5d6db0b..da54dfa707 100644 --- a/ext/oci8/package.xml +++ b/ext/oci8/package.xml @@ -46,12 +46,12 @@ Interoperability Support" (ID 207303.1) for details. <active>no</active> </lead> - <date>2016-08-18</date> + <date>2016-10-17</date> <time>12:00:00</time> <version> - <release>2.1.2</release> - <api>2.1.2</api> + <release>2.1.3</release> + <api>2.1.3</api> </version> <stability> <release>stable</release> @@ -60,8 +60,7 @@ Interoperability Support" (ID 207303.1) for details. <license uri="http://www.php.net/license">PHP</license> <notes> This version is for PHP 7 only. -Fixed invalid handle error with Implicit Result Sets -Fixed bug #72524 (Binding null values triggers ORA-24816 error) +Fixed bug #71148 (Bind reference overwritten on PHP 7) </notes> <contents> <dir name="/"> @@ -471,6 +470,23 @@ Fixed bug #72524 (Binding null values triggers ORA-24816 error) <release> <version> + <release>2.1.2</release> + <api>2.1.2</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.php.net/license">PHP</license> + <notes> +This version is for PHP 7 only. +Fixed invalid handle error with Implicit Result Sets +Fixed bug #72524 (Binding null values triggers ORA-24816 error) + </notes> +</release> + +<release> + <version> <release>2.1.1</release> <api>2.1.1</api> </version> diff --git a/ext/oci8/php_oci8.h b/ext/oci8/php_oci8.h index 70200e452d..ef9b35dcd4 100644 --- a/ext/oci8/php_oci8.h +++ b/ext/oci8/php_oci8.h @@ -43,7 +43,7 @@ */ #undef PHP_OCI8_VERSION #endif -#define PHP_OCI8_VERSION "2.1.2" +#define PHP_OCI8_VERSION "2.1.3" extern zend_module_entry oci8_module_entry; #define phpext_oci8_ptr &oci8_module_entry diff --git a/ext/oci8/php_oci8_int.h b/ext/oci8/php_oci8_int.h index 3a63504e05..1d66f05216 100644 --- a/ext/oci8/php_oci8_int.h +++ b/ext/oci8/php_oci8_int.h @@ -243,6 +243,7 @@ typedef struct { typedef struct { OCIBind *bind; /* bind handle */ zval *zval; /* value */ + zval parameter; /* a copy of bound variable used for oci_bind_by_name */ dvoid *descriptor; /* used for binding of LOBS etc */ OCIStmt *statement; /* used for binding REFCURSORs */ php_oci_statement *parent_statement; /* pointer to the parent statement */ diff --git a/ext/oci8/tests/bug71148.phpt b/ext/oci8/tests/bug71148.phpt new file mode 100644 index 0000000000..44bd0e8007 --- /dev/null +++ b/ext/oci8/tests/bug71148.phpt @@ -0,0 +1,191 @@ +--TEST-- +Bug #71448 (Binding reference overwritten on php7) +--SKIPIF-- +<?php +$target_dbs = array('oracledb' => true, 'timesten' => true); // test runs on these DBs +require(dirname(__FILE__).'/skipif.inc'); +?> +--FILE-- +<?php + +require(dirname(__FILE__).'/connect.inc'); + +// Initialize + +$stmtarray = array( + "CREATE OR REPLACE FUNCTION bindfunc(var1 varchar2, var2 varchar2) + RETURN varchar2 + AS var3 VARCHAR2(20); + BEGIN + var3 := CONCAT(var1, var2); + RETURN var3; + END;", + "CREATE OR REPLACE PROCEDURE bindproc(var1 IN string, var2 IN string, var3 IN OUT string) IS + BEGIN + var3 := CONCAT(var1, var3); + var3 := CONCAT(var3, var2); + END;" +); + +oci8_test_sql_execute($c, $stmtarray); + +// Run test + +function bindvar($stmt, $name, $var) +{ + oci_bind_by_name($stmt, $name, $var); +} + +// Test 1: Bind input parameter in a local function +$sql = "select :var1, :var2 from dual"; +$cache1 = "INSTR1"; +$cache2 = "INSTR2"; + +echo "Test 1: Bind input parameter in a local function\n"; +$stmt = oci_parse($c, $sql); + +bindvar($stmt, ':var1', $cache1); +bindvar($stmt, ':var2', $cache2); + +oci_execute($stmt); + +var_dump(oci_fetch_assoc($stmt)); + +oci_free_statement($stmt); + +// Test 2: Bind output parameter in a local function +$sql = "begin :output1 := 'OUTSTR1'; :output2 := 'OUTSTR2'; end;"; +$cache1 = "xxxxxx"; +$cache2 = "xxxxxx"; + +echo "\nTest 2: Bind output parameter in a local function\n"; +$stmt = oci_parse($c, $sql); + +bindvar($stmt, ':output1', $cache1); +bindvar($stmt, ':output2', $cache2); + +oci_execute($stmt); + +var_dump($cache1); +var_dump($cache2); + +oci_free_statement($stmt); + +// Test 3: Bind output parameter within the same scope of execute +$sql = "begin :output1 := 'OUTSTR1'; :output2 := 'OUTSTR2'; end;"; +$cache1 = "xxxxxx"; +$cache2 = "xxxxxx"; + +echo "\nTest 3: Bind output parameter within the same scope of execute\n"; +$stmt = oci_parse($c, $sql); + +oci_bind_by_name($stmt, ":output1", $cache1); +oci_bind_by_name($stmt, ":output2", $cache2); + +oci_execute($stmt); + +var_dump($cache1); +var_dump($cache2); + +oci_free_statement($stmt); + +// Test 4: Bind output parameter within the same scope of execute +$sql= "begin :output := bindfunc(:var1, :var2); end;"; +$cache1 = "STR1"; +$cache2 = "STR2"; + +echo "\nTest 4: Bind output parameter within the same scope of execute\n"; +$stmt = oci_parse($c, $sql); + +oci_bind_by_name($stmt, ":var1", $cache1, -1); +oci_bind_by_name($stmt, ":var2", $cache2, -1); +oci_bind_by_name($stmt, ":output", $cache3, 100); + +oci_execute($stmt); + +var_dump($cache3); + +// Test 5: Bind IN OUT parameter in a local function + +$sql = "call bindproc(:var1, :var2, :var3)"; +$cache1 = 'STR1'; +$cache2 = 'STR2'; +$cache3 = ' '; + +echo "\nTest 5: Bind IN OUT parameter in a local function\n"; +$stmt = oci_parse($c, $sql); + +bindvar($stmt, ':var1', $cache1); +bindvar($stmt, ':var2', $cache2); +bindvar($stmt, ':var3', $cache3); + +oci_execute($stmt); + +var_dump($cache1); +var_dump($cache2); +var_dump($cache3); + +oci_free_statement($stmt); + +// Test 6: Bind IN OUT parameter within the same scope of execute + +$sql = "call bindproc(:var1, :var2, :var3)"; +$cache1 = 'STR1'; +$cache2 = 'STR2'; +$cache3 = ' '; + +echo "\nTest 6: Bind IN OUT parameter within the same scope of execute\n"; +$stmt = oci_parse($c, $sql); + +oci_bind_by_name($stmt, ":var1", $cache1, -1); +oci_bind_by_name($stmt, ":var2", $cache2, -1); +oci_bind_by_name($stmt, ":var3", $cache3, 100); + +oci_execute($stmt); + +var_dump($cache1); +var_dump($cache2); +var_dump($cache3); + +// Cleanup + +$stmtarray = array( + "DROP FUNCTION bindfunc", + "DROP PROCEDURE bindproc" +); + +oci8_test_sql_execute($c, $stmtarray); + +?> +===DONE=== +<?php exit(0); ?> +--EXPECT-- +Test 1: Bind input parameter in a local function +array(2) { + [":VAR1"]=> + string(6) "INSTR1" + [":VAR2"]=> + string(6) "INSTR2" +} + +Test 2: Bind output parameter in a local function +string(6) "xxxxxx" +string(6) "xxxxxx" + +Test 3: Bind output parameter within the same scope of execute +string(7) "OUTSTR1" +string(7) "OUTSTR2" + +Test 4: Bind output parameter within the same scope of execute +string(8) "STR1STR2" + +Test 5: Bind IN OUT parameter in a local function +string(4) "STR1" +string(4) "STR2" +string(1) " " + +Test 6: Bind IN OUT parameter within the same scope of execute +string(4) "STR1" +string(4) "STR2" +string(9) "STR1 STR2" +===DONE=== diff --git a/ext/oci8/tests/driver_name.phpt b/ext/oci8/tests/driver_name.phpt index 9814703159..d24044e68e 100644 --- a/ext/oci8/tests/driver_name.phpt +++ b/ext/oci8/tests/driver_name.phpt @@ -57,11 +57,11 @@ function get_attr($conn) ?> --EXPECT-- **Test 1.1 - Default values for the attribute ************** -The value of DRIVER_NAME is PHP OCI8 : 2.1.2 +The value of DRIVER_NAME is PHP OCI8 : 2.1.3 ***Test 1.2 - Get the values from different connections ************** Testing with oci_pconnect() -The value of DRIVER_NAME is PHP OCI8 : 2.1.2 +The value of DRIVER_NAME is PHP OCI8 : 2.1.3 Testing with oci_new_connect() -The value of DRIVER_NAME is PHP OCI8 : 2.1.2 +The value of DRIVER_NAME is PHP OCI8 : 2.1.3 Done |