Bug #50046 Program crash after using getString for a string longer than 15 chars
Submitted: 4 Jan 2010 11:26 Modified: 23 Apr 2014 10:03
Reporter: Sushi Fish Email Updates:
Status: Can't repeat Impact on me:
None 
Category:Connector / C++ Severity:S2 (Serious)
Version:1.0.5 OS:Windows (7)
Assigned to: Sveta Smirnova CPU Architecture:Any
Tags: C++, getstring, MySQL

[4 Jan 2010 11:26] Sushi Fish
Description:
My Program is running "executeQuery" with the following SQL query: "SELECT username FROM users WHERE username='testtesttesttest';". Of course its for testing reasons.
In the database its a VARCHAR(32)... nothing special and the entry exists of course.
after this my resultset is created (im using the dynamic stuff) and i want to check the entry if it exists. Im using the "next()" function for it and at the same time i jump to my entry. Now want to return the username so i use "getString("username")" and output it via cout:

cout << results->getString("username");

after this i get the output as it should be. On my scren stands "testtesttesttest".
Right after the cout command i have another cout command:

cout << "test";

This wont show up on my screeen.

The funny thing is. When the user name is "testtesttesttes"... so only 15 chars long it works without problem but i actually need to read a hash 32 chars long but i cant.

How to repeat:
Please test it and give a solution how to avoid it.
[1 Feb 2010 10:33] Tonci Grgin
Hi Sushi (or is it Fish ;-) ) and thanks for your report.

This all makes little sense to me but I'd try something like:
cout << results->getString("username") << endl;

Please attach full test case (if you think there's a bug here) including DDL/DML statements. And do try using something other than "testtest..." as it's easy to get mixed up.
[2 Feb 2010 13:31] Sushi Fish
well its crashing every time using a string longer than 15 chars so you will see it when just testing it.

Anyways... here is the code causing the crash:

// login stuff
void static login_thread(void *user)
{
	lock_wait(sql_lock);
	
	SQL_DATA *data = (SQL_DATA *)user;
	
	if(game.players[data->client_id] && !game.account_data->logged_in[data->client_id])
	{
		// Connect to database
		if(data->sql_data->connect())
		{
			try
			{		
				// check if account exists
				char buf[512];
				str_format(buf, sizeof(buf), "SELECT * FROM %s_account WHERE Name='%s';", data->sql_data->prefix, data->name);
				data->sql_data->results = data->sql_data->statement->executeQuery(buf);
				if(data->sql_data->results->next())
				{
					// check for right pw and get data
					str_format(buf, sizeof(buf), "SELECT ID, Kills, Deaths, Betrayals FROM %s_account WHERE Name='%s' AND Pass=MD5('%s');", data->sql_data->prefix, data->name, data->pass);
					
					// create results
					data->sql_data->results = data->sql_data->statement->executeQuery(buf);
					
					// if match jump to it
					if(data->sql_data->results->next())
					{
						// never use player directly!
						// finally save the result to account_data \o/
						
						// check if account allready is logged in
						for(int i = 0; i < MAX_CLIENTS; i++)
						{
							if(game.account_data->id[i] == data->sql_data->results->getInt("ID"))
							{
								dbg_msg("SQL", "Account '%s' allready is logged in", data->name);
								
								game.send_chat_target(data->client_id, "This account is already logged in.");
								
								// delete statement and results
								delete data->sql_data->statement;
								delete data->sql_data->results;
								
								// disconnect from database
								data->sql_data->disconnect();
								
								// delete data
								delete data;
	
								// release lock
								lock_release(sql_lock);
								
								return;
							}
						}
						
						game.account_data->id[data->client_id] = data->sql_data->results->getInt("ID");
						game.account_data->kills[data->client_id] = data->sql_data->results->getInt("Kills");
						game.account_data->deaths[data->client_id] = data->sql_data->results->getInt("Deaths");
						game.account_data->betrayals[data->client_id] = data->sql_data->results->getInt("Betrayals");
						
						// login should be the last thing
						game.account_data->logged_in[data->client_id] = true;
						dbg_msg("SQL", "Account '%s' logged in sucessfully", data->name);
						
						game.send_chat_target(data->client_id, "You are now logged in.");
					}
					else
					{
						// wrong password
						dbg_msg("SQL", "Account '%s' is not logged in due to wrong password", data->name);
						
						game.send_chat_target(data->client_id, "The password you entered is wrong.");
					}
				}
				else
				{
					// no account
					dbg_msg("SQL", "Account '%s' does not exists", data->name);
					
					game.send_chat_target(data->client_id, "This account does not exists.");
					game.send_chat_target(data->client_id, "Please register first. (/register <user> <pass>)");
				}
				
				// delete statement and results
				delete data->sql_data->statement;
				delete data->sql_data->results;
			}
			catch (sql::SQLException &e)
			{
				dbg_msg("SQL", "ERROR: Could not login account");
			}
			
			// disconnect from database
			data->sql_data->disconnect();
		}
	}
	
	delete data;
	
	lock_release(sql_lock);
}

I guess you wont see anything here since its not very standard.

For the whole source code with function defintions and stuff see "http://twsql.sushitee.de/browser/trunk".

Even i limited it to 15 chars so it wont crash its still a bug ;)
[12 Feb 2010 12:56] Tonci Grgin
No node /trunk" at revision 31
[22 Mar 2010 20:02] Sveta Smirnova
Thank you for the report.

Please provide output of SHOW CREATE TABLE %s_account.
[22 Apr 2010 23:00] Bugs System
No feedback was provided for this bug for over a month, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
[23 Apr 2010 6:01] Tonci Grgin
Sushi, Sveta is still waiting on feedback.
[23 Apr 2010 10:20] Sushi Fish
sry, i was kind of busy last few month.

I dont really get the question bt u can see the whole file here:
http://twsql.sushitee.de/browser/trunk/src/game/server/sql.cpp

The created DB looks like this (sreenshot out of phpmyadmin):
http://img341.imageshack.us/img341/3093/57208437.jpg

Translation of few words:
Nein = no
Ja = yes
keine = none

- Thx in advance ...Sushi
[24 Apr 2010 7:16] Sveta Smirnova
Thank you for the feedback.

By output of SHOW CREATE TABLE I mean following sequence of actions:

1. Connect to MySQL via any client, for example, PHPMyAdmin
2. Open interface where you can run queries
3. Run query SHOW CREATE TABLE table_you_really_use
4. Send us result

Anyway I was able to recreate table from the screenshot provided.

But in the initial description you mention problems with:

> cout << results->getString("username");

But I see no such call in the code provided. Also I can not just compile your code and look, because it uses libraries from your project. Please provide example of code demonstrating the problem. We need:

1. Code which we are able to compile or part of code which doesn't use not-MySQL and not-standard libraries and demonstrates the problem
2. Expected output
3. What you really get
[24 Apr 2010 10:22] Sushi Fish
ok here the output

CREATE TABLE `tw_account` (
 `ID` int(11) NOT NULL auto_increment,
 `Name` varchar(31) NOT NULL,
 `Pass` varchar(32) NOT NULL,
 `Kills` bigint(20) default NULL,
 `Deaths` bigint(20) default NULL,
 `Betrayals` bigint(20) default NULL,
 `last_logged_in` datetime NOT NULL,
 `register_date` datetime NOT NULL,
 PRIMARY KEY  (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
[24 Apr 2010 10:36] Sushi Fish
it doesnt matter if i use cout or something else... it allways will crash. I just tested with cout but in the end cout is kind of pointless in this project.

Anyway... about compiling. Here is descriped how to compile it. It needs a special build system provided by the game autor.

http://teeworlds.com/trac/teeworlds/wiki/CompilingEverything

important ist, that u do NOT use bam-0.3.2 as descriped there. You have to use bam-0.2.0
You can download it here: http://teeworlds.com/trac/bam/browser/releases/bam-0.2.0.zip?format=raw

Since its a game server using SQL u dont want to really get into the code. Just download the client from teeworlds.com and compile the server from my code.
You dont need any additional libs or stuff. Its all in it :)

You can use the commands for SQL ingame via chat like "/register name password". in code u can find all commands in src/game/server/hooks.cpp.
[23 Jun 2010 10:16] Sveta Smirnova
Thank you for the feedback.

What I saw in your code you use own functions to output data.

Please try to create isolate test case. For example:

#include "stdafx.h"
#include <stdlib.h>
#include <iostream>

#include "mysql_connection.h"

#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/prepared_statement.h>

using namespace std;

void	testInsert()
{
	cout << endl;
	cout << "testInsert() begin" << endl;

	try { 
		sql::Driver *driver;
		sql::Connection *con;
		sql::Statement *stmt;
		sql::PreparedStatement *pstmt;
		sql::ResultSet *res;

		/* Create a connection */
		driver = get_driver_instance();
		con = driver->connect("tcp://127.0.0.1:3306", "root", "");	

		stmt = con->createStatement();
		
		char cc;
		/* Connect to the MySQL test database */
		con->setSchema("test");						

		res = stmt->executeQuery("SHOW TABLES LIKE '%tw_account%'");	
		if(res->rowsCount() > 0)
		{
				cout << "delete old data? y/n" << endl;
				cin >> cc;
				if(cc == 'y'
					|| cc == 'Y')
				{
					stmt->execute("DELETE FROM tw_account");		
					
				}
				else
				{
					cout << "Not deleting" << endl;
				}
		}
		else
		{
		
			stmt->execute("DROP TABLE IF EXISTS tw_account");	
			stmt->execute("CREATE TABLE `tw_account` ( `ID` int(11) NOT NULL auto_increment, `Name` varchar(31) NOT NULL, `Pass` varchar(32) NOT NULL, `Kills` bigint(20) default NULL, `Deaths` bigint(20) default NULL, `Betrayals` bigint(20) default NULL, `last_logged_in` datetime NOT NULL, `register_date` datetime NOT NULL, PRIMARY KEY  (`ID`)) ENGINE=MyISAM DEFAULT CHARSET=latin1");			
		}

		stmt->execute("INSERT INTO tw_account(Name, Pass, last_logged_in, register_date) values('testtesttesttest', 'testtesttesttest', now(), now())");
		stmt->execute("INSERT INTO tw_account(Name, Pass, last_logged_in, register_date) values('testtesttesttes', 'testtesttesttest', now(), now())");

		cout << "Prepare finished" << endl;
		
		delete res;

		//20100420124917
		cout << "searching ? y/n" << endl;
		cin >> cc;
		if(cc == 'y' || cc == 'Y')
		{
			char szSqlQueryCmd[256] = {0};
			sprintf(szSqlQueryCmd, "SELECT Name as username FROM tw_account WHERE Name='testtesttesttest'");
			pstmt = con->prepareStatement(szSqlQueryCmd);
			res = pstmt->executeQuery();

			printf("searched %d count record", res->rowsCount());
			cout << endl;

			if(res->rowsCount() > 0)
			{
					res->beforeFirst();
					while (res->next())
					{
						cout << "\tusername: " << (res->getString("username"));
						cout << "test";
						cout << endl;
					}

			}
			delete pstmt;
			delete res;
		}

		
		delete stmt;
		delete con;

	} 
	catch (sql::SQLException &e) 
	{
		cout << "# ERR: SQLException in " << __FILE__;
		cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
		cout << "# ERR: " << e.what();
		cout << " (MySQL error code: " << e.getErrorCode();
		cout << ", SQLState: " << e.getSQLState() << " )" << endl;
	}
	cout << "testInsert() end" << endl;
	cout << "press any key to exit" <<endl;
	char e;
	cin >> e;
}

int _tmain(int argc, _TCHAR* argv[])
{
	testInsert();
	return 0;
}

Please inform us what this code outputs in your case. Don't run it on production database! This can remove all data.
[23 Jul 2010 23:00] Bugs System
No feedback was provided for this bug for over a month, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
[28 Feb 2011 15:56] Shereef Marzouk
I have the same problem
https://github.com/GreYFoX/DDRace/blob/master/src/game/server/score/sql_score.cpp

so for windows i have limited the names to 16 there https://github.com/GreYFoX/DDRace/blob/master/src/game/server/score/sql_score.h#L72
[15 Mar 2011 5:51] KAs dewd
same problem 
 on visual c ++  2010 express
[7 Jul 2011 18:59] Sveta Smirnova
Shereef,

thank you for the feedback. Please isolate your test case from other code of your application. So we can just download source, compile and run to see the problem.
[7 Aug 2011 23:00] Bugs System
No feedback was provided for this bug for over a month, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
[23 Apr 2014 10:02] Bogdan Degtyariov
Posted by developer:
 
Cannot repeat
[23 Apr 2014 10:12] Bogdan Degtyariov
Posted by developer:
 
Cannot repeat with Connector/C++ v 1.1.3.
Please reopen the bug if the problem still happens for you.