]> granicus.if.org Git - php/commitdiff
Fixed bug #71148 (Bind reference overwritten on PHP 7)
authorChristopher Jones <christopher.jones@oracle.com>
Mon, 17 Oct 2016 01:40:14 +0000 (12:40 +1100)
committerChristopher Jones <christopher.jones@oracle.com>
Mon, 17 Oct 2016 01:40:14 +0000 (12:40 +1100)
NEWS
ext/oci8/oci8.c
ext/oci8/oci8_interface.c
ext/oci8/oci8_statement.c
ext/oci8/package.xml
ext/oci8/php_oci8.h
ext/oci8/php_oci8_int.h
ext/oci8/tests/bug71148.phpt [new file with mode: 0644]
ext/oci8/tests/driver_name.phpt

diff --git a/NEWS b/NEWS
index 08b4f64ac3b1ed5e247485e797b1f08ac79f9fba..e5049b515ded19bf7d0b930ac31a159b4816e0cf 100644 (file)
--- 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.
index 0527b558474b9602dac1cbae9d6544f6d1ee3f7e..59f993160cf983dd24bb391b68a65a17303d2dba 100644 (file)
@@ -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;
index 727ec3e1c7aefa0bc1a58bb6795f343dc9a2638a..18714d16ed81fc65db2fe0d96e7808663d81fc04 100644 (file)
@@ -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;
        }
 
index d4f08150e7cc153d44cf23fae8bd0a3d47671f79..2b1fc4c1f1b1f45a542d193da7602b2fa12f0c21 100644 (file)
@@ -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
index 29b5d6db0bf552717b37b12d803b3e39e9db6421..da54dfa707eee71a4c6aaa6b7af4df78415b6b17 100644 (file)
@@ -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="/">
@@ -469,6 +468,23 @@ Fixed bug #72524 (Binding null values triggers ORA-24816 error)
  </extsrcrelease>
  <changelog>
 
+<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>
index 70200e452dfe7fbac94c26079200438330210f11..ef9b35dcd409c8f8d8bccdb00d72249f251fb149 100644 (file)
@@ -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
index 3a63504e05704d9b259c17de83045068148b0513..1d66f052161ae0563edb11ac6ddd9cff5e97a88f 100644 (file)
@@ -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 (file)
index 0000000..44bd0e8
--- /dev/null
@@ -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===
index 98147031590d55295e0b6eb5f5bd6bc2eea9b049..d24044e68e958f22519e6d06c515a719119eb588 100644 (file)
@@ -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