]> granicus.if.org Git - php/commitdiff
Fixed bug #77597
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 21 Feb 2019 12:42:47 +0000 (13:42 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 21 Feb 2019 12:42:47 +0000 (13:42 +0100)
The same variable was reused in two nested loops... The test doesn't
fail on 7.2, but I'm fixing this here anyway as the code is clearly
wrong, and probably erroneous in other situations.

NEWS
ext/mysqli/tests/bug77597.phpt [new file with mode: 0644]
ext/mysqlnd/mysqlnd_result.c

diff --git a/NEWS b/NEWS
index 6781f8f409421a8ec935bd17eccc4ad86a31b911..72d8fac99d200bff245712f7bbe25327c80b9ffc 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,9 @@ PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? ??? 2019, PHP 7.2.17
 
+- MySQLi:
+  . Fixed bug #77597 (mysqli_fetch_field hangs scripts). (Nikita)
+
 07 Mar 2019, PHP 7.2.16
 
 - Core:
diff --git a/ext/mysqli/tests/bug77597.phpt b/ext/mysqli/tests/bug77597.phpt
new file mode 100644 (file)
index 0000000..ef3cb0f
--- /dev/null
@@ -0,0 +1,27 @@
+--TEST--
+Bug #77597: mysqli_fetch_field hangs scripts
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifconnectfailure.inc');
+?>
+--FILE--
+<?php
+
+require_once("connect.inc");
+$mysqli = new my_mysqli($host, $user, $passwd, $db, $port, $socket);
+
+$mysqli->query('DROP TABLE IF EXISTS a');
+$mysqli->query('CREATE TABLE a (b int)');
+$mysqli->query('INSERT INTO a VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9)');
+
+$mysqli->real_query("SELECT * FROM a");
+
+$result = $mysqli->store_result(MYSQLI_STORE_RESULT_COPY_DATA);
+
+$field = $result->fetch_field();
+var_dump($field->name);
+
+?>
+--EXPECT--
+string(1) "b"
index 030ee1e020b7facbb7875a674c7c7a47e784e7b9..5e8360994796859653658e92a0b1ebfe7903dd5b 100644 (file)
@@ -91,7 +91,7 @@ MYSQLND_METHOD(mysqlnd_result_buffered_c, initialize_result_set_rest)(MYSQLND_RE
                                                                                                                                          MYSQLND_STATS * stats,
                                                                                                                                          zend_bool int_and_float_native)
 {
-       unsigned int i;
+       unsigned int row, field;
        enum_func_status ret = PASS;
        const unsigned int field_count = meta->field_count;
        const uint64_t row_count = result->row_count;
@@ -106,33 +106,33 @@ MYSQLND_METHOD(mysqlnd_result_buffered_c, initialize_result_set_rest)(MYSQLND_RE
                        DBG_RETURN(FAIL);
                }
 
-               for (i = 0; i < result->row_count; i++) {
+               for (row = 0; row < result->row_count; row++) {
                        /* (i / 8) & the_bit_for_i*/
-                       if (initialized[i >> 3] & (1 << (i & 7))) {
+                       if (initialized[row >> 3] & (1 << (row & 7))) {
                                continue;
                        }
 
-                       rc = result->m.row_decoder(result->row_buffers[i], current_row, field_count, meta->fields, int_and_float_native, stats);
+                       rc = result->m.row_decoder(result->row_buffers[row], current_row, field_count, meta->fields, int_and_float_native, stats);
 
                        if (rc != PASS) {
                                ret = FAIL;
                                break;
                        }
                        result->initialized_rows++;
-                       initialized[i >> 3] |= (1 << (i & 7));
-                       for (i = 0; i < field_count; i++) {
+                       initialized[row >> 3] |= (1 << (row & 7));
+                       for (field = 0; field < field_count; field++) {
                                /*
                                  NULL fields are 0 length, 0 is not more than 0
                                  String of zero size, definitely can't be the next max_length.
                                  Thus for NULL and zero-length we are quite efficient.
                                */
-                               if (Z_TYPE(current_row[i]) == IS_STRING) {
-                                       const size_t len = Z_STRLEN(current_row[i]);
-                                       if (meta->fields[i].max_length < len) {
-                                               meta->fields[i].max_length = len;
+                               if (Z_TYPE(current_row[field]) == IS_STRING) {
+                                       const size_t len = Z_STRLEN(current_row[field]);
+                                       if (meta->fields[field].max_length < len) {
+                                               meta->fields[field].max_length = len;
                                        }
                                }
-                               zval_ptr_dtor_nogc(&current_row[i]);
+                               zval_ptr_dtor_nogc(&current_row[field]);
                        }
                }
                mnd_efree(current_row);