]> granicus.if.org Git - php/commitdiff
Fix (by Andrey) and test for bug #49442 . Don't use efree() for memory allocated...
authorUlf Wendel <uw@php.net>
Wed, 16 Sep 2009 17:03:44 +0000 (17:03 +0000)
committerUlf Wendel <uw@php.net>
Wed, 16 Sep 2009 17:03:44 +0000 (17:03 +0000)
ext/mysqli/tests/bug49442.phpt [new file with mode: 0644]
ext/mysqlnd/mysqlnd.h
ext/mysqlnd/mysqlnd_priv.h
ext/mysqlnd/mysqlnd_wireprotocol.c

diff --git a/ext/mysqli/tests/bug49442.phpt b/ext/mysqli/tests/bug49442.phpt
new file mode 100644 (file)
index 0000000..089e7dc
--- /dev/null
@@ -0,0 +1,119 @@
+--TEST--
+Bug #49422 (mysqlnd: mysqli_real_connect() and LOAD DATA INFILE crash)
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifconnectfailure.inc');
+?>
+--INI--
+mysqli.allow_local_infile=1
+mysqli.allow_persistent=1
+mysqli.max_persistent=1
+--FILE--
+<?php
+       include ("connect.inc");
+
+       $link = mysqli_init();
+       if (!mysqli_real_connect($link, $host, $user, $passwd, $db, $port, $socket)) {
+               printf("[001] Connect failed, [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
+       }
+
+       if (!mysqli_query($link, 'DROP TABLE IF EXISTS test')) {
+               printf("[002] Failed to drop old test table: [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+       }
+
+       if (!mysqli_query($link, 'CREATE TABLE test(id INT, label CHAR(1), PRIMARY KEY(id)) ENGINE=' . $engine)) {
+               printf("[003] Failed to create test table: [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+       }
+
+       include("local_infile_tools.inc");
+       $file = create_standard_csv(4);
+
+       if (!@mysqli_query($link, sprintf("LOAD DATA LOCAL INFILE '%s'
+                       INTO TABLE test
+                       FIELDS TERMINATED BY ';' OPTIONALLY ENCLOSED BY '\''
+                       LINES TERMINATED BY '\n'",
+                       mysqli_real_escape_string($link, $file)))) {
+                       printf("[005] [%d] %s\n",  mysqli_errno($link), mysqli_error($link));
+       }
+
+       if (!$res = mysqli_query($link, "SELECT * FROM test ORDER BY id"))
+               printf("[006] [%d] %s\n",  mysqli_errno($link), mysqli_error($link));
+
+       $rows = array();
+       while ($row = mysqli_fetch_assoc($res)) {
+               var_dump($row);
+               $rows[] = $row;
+       }
+
+       mysqli_free_result($res);
+
+       mysqli_query($link, "DELETE FROM test");
+       mysqli_close($link);
+
+       if ($IS_MYSQLND) {
+               /*
+                       mysqlnd makes a connection created through mysql_init()/mysqli_real_connect() always a 'persistent' one.
+                       At this point 'persistent' is not to be confused with what a user calls a 'persistent' - in this case
+                       'persistent' means that mysqlnd uses malloc() instead of emalloc(). nothing else. ext/mysqli will
+                       not consider it as a 'persistent' connection in a user sense, ext/mysqli will not appy max_persistent etc.
+                       Its only about malloc() vs. emalloc().
+
+                       However, the bug is about malloc() and efree(). You can make make mysqlnd use malloc() by either using
+                       pconnect or mysql_init() - so we should test pconnect as well..
+               */
+               $host = 'p:' . $host;
+               if (!$link = mysqli_connect($host, $user, $passwd, $db, $port, $socket)) {
+                       printf("[007] Connect failed, [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error());
+               }
+
+               /* bug happened during query processing */
+               if (!@mysqli_query($link, sprintf("LOAD DATA LOCAL INFILE '%s'
+                       INTO TABLE test
+                       FIELDS TERMINATED BY ';' OPTIONALLY ENCLOSED BY '\''
+                       LINES TERMINATED BY '\n'",
+                       mysqli_real_escape_string($link, $file)))) {
+                       printf("[008] [%d] %s\n",  mysqli_errno($link), mysqli_error($link));
+               }
+
+               /* we survived? that's good enough... */
+
+               if (!$res = mysqli_query($link, "SELECT * FROM test ORDER BY id"))
+                       printf("[009] [%d] %s\n",  mysqli_errno($link), mysqli_error($link));
+
+               $i = 0;
+               while ($row = mysqli_fetch_assoc($res)) {
+                       if (($row['id'] != $rows[$i]['id']) || ($row['label'] != $rows[$i]['label'])) {
+                               printf("[010] Wrong values, check manually!\n");
+                       }
+                       $i++;
+               }
+               mysqli_close($link);
+       }
+
+       print "done!";
+?>
+--CLEAN--
+<?php
+       require_once("clean_table.inc");
+?>
+--EXPECTF--
+array(2) {
+  [%u|b%"id"]=>
+  %unicode|string%(2) "97"
+  [%u|b%"label"]=>
+  %unicode|string%(1) "x"
+}
+array(2) {
+  [%u|b%"id"]=>
+  %unicode|string%(2) "98"
+  [%u|b%"label"]=>
+  %unicode|string%(1) "y"
+}
+array(2) {
+  [%u|b%"id"]=>
+  %unicode|string%(2) "99"
+  [%u|b%"label"]=>
+  %unicode|string%(1) "z"
+}
+done!
\ No newline at end of file
index 79ce62f3ea8fc018b5506e4baaf237a3bbcecd30..b85a1380dcddc1ea4d6838be2d918dfddf618832 100644 (file)
@@ -26,7 +26,7 @@
 #define MYSQLND_VERSION_ID 50005
 
 /* This forces inlining of some accessor functions */
-#define MYSQLND_USE_OPTIMISATIONS 1
+#define MYSQLND_USE_OPTIMISATIONS 0
 
 #define MYSQLND_STRING_TO_INT_CONVERSION
 /*
index ae3752e6d3a5c9c09ae48dab069a95f1e67a9a83..856b7076c65840ddb10c5804aaf1018bcf92e866 100644 (file)
                if ((buf)) { \
                        pefree((buf), (persistent)); \
                } \
-               (buf) = (message); \
+               if ((message)) { \
+                       (buf) = pestrndup((message), (len), (persistent)); \
+               } else { \
+                       buf = NULL; \
+               } \
                (buf_len) = (len); \
-               /* Transfer ownership*/ \
-               (message) = NULL; \
        }
 
 #define SET_EMPTY_MESSAGE(buf, buf_len, persistent) \
index 79c98741e8f84b185d1f491f33304d0c228f0d96..d3f668cd16c89946bb70520180eb1faaa01071c4 100644 (file)
@@ -813,7 +813,7 @@ php_mysqlnd_ok_read(void *_packet, MYSQLND *conn TSRMLS_DC)
 
        /* There is a message */
        if (packet->header.size > p - buf && (i = php_mysqlnd_net_field_length(&p))) {
-               packet->message = pestrndup((char *)p, MIN(i, sizeof(buf) - (p - buf)), conn->persistent);
+               packet->message = estrndup((char *)p, MIN(i, sizeof(buf) - (p - buf)));
                packet->message_len = i;
        } else {
                packet->message = NULL;
@@ -1032,7 +1032,7 @@ php_mysqlnd_rset_header_read(void *_packet, MYSQLND *conn TSRMLS_DC)
                          Thus, the name is size - 1. And we add 1 for a trailing \0.
                        */
                        len = packet->header.size - 1;
-                       packet->info_or_local_file = mnd_pemalloc(len + 1, conn->persistent);
+                       packet->info_or_local_file = mnd_emalloc(len + 1);
                        memcpy(packet->info_or_local_file, p, len);
                        packet->info_or_local_file[len] = '\0';
                        packet->info_or_local_file_len = len;
@@ -1867,7 +1867,7 @@ php_mysqlnd_stats_read(void *_packet, MYSQLND *conn TSRMLS_DC)
 
        PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "statistics", PROT_STATS_PACKET);
 
-       packet->message = mnd_pemalloc(packet->header.size + 1, conn->persistent);
+       packet->message = mnd_emalloc(packet->header.size + 1);
        memcpy(packet->message, buf, packet->header.size);
        packet->message[packet->header.size] = '\0';
        packet->message_len = packet->header.size;