summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Jones <christopher.jones@oracle.com>2016-10-17 12:40:14 +1100
committerChristopher Jones <christopher.jones@oracle.com>2016-10-17 12:40:14 +1100
commit8be59a13017f16396e862a8e50c888afafe1952d (patch)
treeb329a36c0caf04d30b958dc537665aa83fee965b
parentd82da7de3a460f1eee3d34448be79bca3de7abc1 (diff)
downloadphp-git-8be59a13017f16396e862a8e50c888afafe1952d.tar.gz
Fixed bug #71148 (Bind reference overwritten on PHP 7)
-rw-r--r--NEWS3
-rw-r--r--ext/oci8/oci8.c5
-rw-r--r--ext/oci8/oci8_interface.c2
-rw-r--r--ext/oci8/oci8_statement.c61
-rw-r--r--ext/oci8/package.xml26
-rw-r--r--ext/oci8/php_oci8.h2
-rw-r--r--ext/oci8/php_oci8_int.h1
-rw-r--r--ext/oci8/tests/bug71148.phpt191
-rw-r--r--ext/oci8/tests/driver_name.phpt6
9 files changed, 264 insertions, 33 deletions
diff --git a/NEWS b/NEWS
index 08b4f64ac3..e5049b515d 100644
--- a/NEWS
+++ b/NEWS
@@ -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