Bug #11349 server crash when retrieving not all rows from a cursor
Submitted: 15 Jun 2005 12:41 Modified: 30 Jun 2005 18:29
Reporter: Georg Richter Email Updates:
Status: Can't repeat Impact on me:
None 
Category:MySQL Server Severity:S1 (Critical)
Version:5.1.8-beta OS:Linux (Linux)
Assigned to: Konstantin Osipov CPU Architecture:Any

[15 Jun 2005 12:41] Georg Richter
Description:
Retrieving not all data from a open cursor crashes server.

How to repeat:
#include <stdio.h>
#include <mysql.h>

MYSQL_STMT *open_cursor(MYSQL *mysql, char *query)
{
	ulong ctype = CURSOR_TYPE_READ_ONLY;
	MYSQL_STMT *stmt = mysql_stmt_init(mysql);

	mysql_stmt_prepare(stmt, query, strlen(query));
	mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, &ctype);

	return stmt;
}

int main() {
	MYSQL *mysql;
	MYSQL_STMT *stmt;
	MYSQL_BIND bind[3];
	long len[3];
	char buf[3][100];
	int i, rc;
	
	mysql = mysql_init(NULL);
	mysql_real_connect(mysql, "localhost", "root", "", "test", 0, NULL, 0);

	stmt = open_cursor(mysql, "SELECT TABNAME, TABFORM, REFNAME FROM DDNTT WHERE TABFORM <> 'J' AND TABFORM <> 'V' ORDER BY TABNAME LIMIT 10"); 
	mysql_stmt_execute(stmt);

	for (i=0; i < 1; i++) {
		memset(&bind[i], '\0', sizeof(MYSQL_BIND));
		bind[i].buffer_type= MYSQL_TYPE_STRING;
		bind[i].buffer= (gptr *)&buf[i];
		bind[i].buffer_length= 100;
		bind[i].length= &len[i];
	}

	mysql_stmt_bind_result(stmt, bind);

	/* we fetch only 5 records */
	for (i=0; i < 5; i++) {
	   rc = mysql_stmt_fetch(stmt);
	}

	printf("Server crash after client ends\n");
}
[15 Jun 2005 13:22] Georg Richter
patch:

+ for (i=0; i < 3; i++) {
-  for (i=0; i < 1; i++) {
[30 Jun 2005 18:29] Konstantin Osipov
Georg, I can't repeat this one on the latest tree.
I might have fixed it already.
Here is the output (I added printing of values):

kostja@dragonfly:~> ./bug11349
/BDL/BADHOST T 
/BDL/CUST T 
/BDL/CUSTSES T 
/BDL/INTSESS T 
/BDL/MSGLOG T 
Server crash after client ends
kostja@dragonfly:~> ./bug11349
/BDL/BADHOST T 
/BDL/CUST T 
/BDL/CUSTSES T 
/BDL/INTSESS T 
/BDL/MSGLOG T 
Server crash after client ends
kostja@dragonfly:~> ./bug11349
/BDL/BADHOST T 
/BDL/CUST T 
/BDL/CUSTSES T 
/BDL/INTSESS T 
/BDL/MSGLOG T 
Server crash after client ends
kostja@dragonfly:~> ./bug11349
/BDL/BADHOST T 
/BDL/CUST T 
/BDL/CUSTSES T 
/BDL/INTSESS T 
/BDL/MSGLOG T 
Server crash after client ends

Here is the C program that I modified:
kostja@dragonfly:~> cat bug11349.c 
#include <stdio.h>
#include <mysql.h>

MYSQL_STMT *open_cursor(MYSQL *mysql, char *query)
{
        ulong ctype = CURSOR_TYPE_READ_ONLY;
        MYSQL_STMT *stmt = mysql_stmt_init(mysql);

        mysql_stmt_prepare(stmt, query, strlen(query));
        mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, &ctype);

        return stmt;
}

int main() {
        MYSQL *mysql;
        MYSQL_STMT *stmt;
        MYSQL_BIND bind[3];
        long len[3];
        char buf[3][100];
        int i, rc;

        mysql = mysql_init(NULL);
        mysql_real_connect(mysql, 0, "kostja", "", "test", 0, "/opt/local/var/mysql/mysql.sock", 0);

        stmt = open_cursor(mysql, "SELECT TABNAME, TABFORM, REFNAME FROM DDNTT WHERE TABFORM <> 'J' AND TABFORM <> 'V' ORDER BY TABNAME LIMIT 10");
        mysql_stmt_execute(stmt);

        for (i=0; i < 3; i++) {
                memset(&bind[i], '\0', sizeof(MYSQL_BIND));
                bind[i].buffer_type= MYSQL_TYPE_STRING;
                bind[i].buffer= (gptr *)&buf[i];
                bind[i].buffer_length= 100;
                bind[i].length= &len[i];
        }
        mysql_stmt_bind_result(stmt, bind);

        /* we fetch only 5 records */
        for (i=0; i < 5; i++) {
           rc = mysql_stmt_fetch(stmt);
           printf("%s %s %s\n", buf[0], buf[1], buf[2]);
        }

        printf("Server crash after client ends\n");
}

Valgrind is silent as well.