Bug #2099 mysqld crashes when executing simple prepared statement.
Submitted: 11 Dec 2003 11:37 Modified: 14 Dec 2003 16:01
Reporter: Richard Tibbetts Email Updates:
Status: Duplicate Impact on me:
None 
Category:MySQL Server Severity:S2 (Serious)
Version:mysql-4.1.1-alpha (Source distribution) OS:Linux (Linux/Windows)
Assigned to: Assigned Account CPU Architecture:Any

[11 Dec 2003 11:37] Richard Tibbetts
Description:
When executing a simple prepared statement with two int parameters
against the server, the second execution causes the server to crash.
While I might not be using the API quite properly (though I think I
am), the server crashing seems poor.

This bug may be related to bug number 1663.

How to repeat:
The following C++ program (which could easily be turned into a C
program) causes the server to crash:

#include "mysql.h"
#include "iostream"
#include "string"

using namespace std;

int main(int argc, char *const argv[])
{
    MYSQL real_mysql;
    MYSQL *mysql;
    
    MYSQL_STMT *stmt;
    MYSQL_BIND bind[2];
    int        rc;
    long       int_data[2];

    mysql = &real_mysql;
    mysql_init(mysql);

    mysql_real_connect(mysql, "127.0.0.1", "", "", "test", 3306, NULL, 0);
    
    mysql_query(mysql,"DROP TABLE IF EXISTS test");
    mysql_query(mysql,"CREATE TABLE test (a INT, b INT, c INT, d INT)");
    mysql_query(mysql,"INSERT INTO test VALUES (1,1,1,1),(2,2,2,2),(3,3,3,3),(4,4,4,4),(5,5,5,5)");
    mysql_commit(mysql);

    string query("SELECT a FROM test_bg1500 WHERE a = ? and b = ?");
    stmt= mysql_prepare(mysql, query.c_str(), query.length());
    if (!stmt) {
        cerr << "Statement did not prepare: " << mysql_error(mysql) << endl;
        exit(1);
    }
    bind[0].buffer= (char *)&int_data[0];
    bind[0].buffer_type= FIELD_TYPE_LONG;
    bind[0].is_null= 0;
    bind[0].length=0;
    bind[1] = bind[0];
    bind[1].buffer = (char *)&int_data[1];
    
    rc= mysql_bind_param(stmt, bind);

    int_data[0] = int_data[1] = 2;
    rc= mysql_execute(stmt);
    cerr << "Executed, rc = " << rc << " error=" << mysql_error(mysql) << endl;
    mysql_stmt_store_result(stmt);
    mysql_stmt_reset(stmt);

    int_data[0] = int_data[1] = 5;
    rc= mysql_execute(stmt);
    cerr << "Executed, rc = " << rc << " error=" << mysql_error(mysql) << endl;
}

Suggested fix:
Unknown.
[11 Dec 2003 11:58] MySQL Verification Team
Thank you for the bug report I was able to repeat on Windows too.
Below call stack:

00000000()	
mysqld.exe!add_key_field(key_field_t * * key_fields=0x045eea14, unsigned int and_level=0, Field * field=0x036f5528, int eq_func=1, Item * * value=0x036f5f00, unsigned int num_values=1, unsigned __int64 usable_tables=18446744073709551615)  Line 2128 + 0x15	C++

mysqld.exe!add_key_fields(st_join_table * stat=0x036fa7a0, key_field_t * * key_fields=0x045eea14, unsigned int * and_level=0x045eea08, Item * cond=0x036f5ec0, unsigned __int64 usable_tables=18446744073709551615)  Line 2267 + 0x48	C++

mysqld.exe!add_key_fields(st_join_table * stat=0x036fa7a0, key_field_t * * key_fields=0x045eea14, unsigned int * and_level=0x045eea08, Item * cond=0x036f9cf8, unsigned __int64 usable_tables=18446744073709551615)  Line 2217 + 0x1d	C++

mysqld.exe!update_ref_and_keys(THD * thd=0x036ef040, st_dynamic_array * keyuse=0x036fa6e0, st_join_table * join_tab=0x036fa7a0, unsigned int tables=1, Item * cond=0x036f9cf8, unsigned __int64 normal_tables=18446744073709551615, st_select_lex * select_lex=0x036ef3b0)  Line 2456 + 0x1d	C++

mysqld.exe!make_join_statistics(JOIN * join=0x036f9da0, st_table_list * tables=0x00000000, Item * conds=0x036f9cf8, st_dynamic_array * keyuse_array=0x036fa6e0)  Line 1775 + 0x38	C++

mysqld.exe!JOIN::optimize()  Line 576 + 0x27	C++

mysqld.exe!mysql_select(THD * thd=0x036ef040, Item * * * rref_pointer_array=0x036ef498, st_table_list * tables=0x036f5d70, unsigned int wild_num=0, List<Item> & fields={...}, Item * conds=0x036f9cf8, unsigned int og_num=0, st_order * order=0x00000000, st_order * group=0x00000000, Item * having=0x00000000, st_order * proc_param=0x00000000, unsigned long select_options=8669696, select_result * result=0x036f9d90, st_select_lex_unit * unit=0x036ef2c4, st_select_lex * select_lex=0x036ef3b0)  Line 1587 + 0x8	C++

mysqld.exe!handle_select(THD * thd=0x036ef040, st_lex * lex=0x036ef2b8, select_result * result=0x036f9d90)  Line 193 + 0x89	C++
mysqld.exe!mysql_execute_command(THD * thd=0x036ef040)  Line 1916 + 0x11	C++

mysqld.exe!mysql_stmt_execute(THD * thd=0x036ef040, char * packet=0x036e7301)  Line 998 + 0x9	C++

mysqld.exe!dispatch_command(enum_server_command command=COM_EXECUTE, THD * thd=0x036ef040, char * packet=0x036e7301, unsigned int packet_length=15)  Line 1358 + 0xd	C++

mysqld.exe!do_command(THD * thd=0x036ef040)  Line 1217 + 0x31	C++
mysqld.exe!handle_one_connection(void * arg=0x036ef040)  Line 979 + 0x9	C++
mysqld.exe!pthread_start(void * param=0x036f2758)  Line 63 + 0x7	C
mysqld.exe!_threadstart(void * ptd=0x036f50f0)  Line 173 + 0xd	C
kernel32.dll!77e6d33b()
[11 Dec 2003 12:26] Richard Tibbetts
Oh, forgot to include it, here is the call stack on Linux:

0x8150b1d handle_segfault + 459
0x400427f5 _end + 934867109
0x80ee666 _ZN9Item_func8print_opEP6String + 278
0x8102b26 _ZN15Item_bool_func25printEP6String + 24
0x80ffb23 _ZN9Item_cond5printEP6String + 103
0x81b2ec5 _Z11print_whereP4ItemPKc + 89
0x819646e _Z13optimize_condP4ItemPNS_11cond_resultE + 276
0x818c6d0 _ZN4JOIN8optimizeEv + 174
0x818fa3f _Z12mysql_selectP3THDPPP4ItemP13st_table_listjR4ListIS1_ES2_jP8st_orderSB_S2_SB_mP13select_resultP18
st_select_lex_unitP13st_sel + 499
0x818bc8d _Z13handle_selectP3THDP6st_lexP13select_result + 261
0x8164798 _Z21mysql_execute_commandP3THD + 1808
0x81aa983 _Z18mysql_stmt_executeP3THDPc + 513
0x8163110 _Z16dispatch_command19enum_server_commandP3THDPcj + 1482
0x8162b3a _Z10do_commandP3THD + 500
0x8162017 handle_one_connection + 561
0x8152c4b _Z17create_new_threadP3THD + 435
0x81532e5 handle_connections_sockets + 1147
0x8152647 main + 843
0x401d1da6 _end + 936502870
0x80d8801 _start + 33
[13 Dec 2003 21:51] Richard Tibbetts
Explored further. It looks like what happens is that the parameters are allocated in the thread 
memory root, and that root is freed at the end of the first execution. This causes memory 
corruption of the Item_param structures when that memory gets allocated differently on the second 
execution. I validated this by commenting out the line:

free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC))

at the end of dispatch_command() in sql_parse.cc. Of course, this is a terrible memory leak. :)

Hope this helps.
[14 Dec 2003 16:01] Dmitry Lenev
Hi, Richard! 

Thank you for reporting this bug and for additional investigation!

Your last comment means that this bug is yet another manifestation of bug #1663
(At least they both have the same cause behind them - "Item"s just don't support prepared statements well.)

So I'm marking this bug report as duplicate of #1663 just for sake of having less entities to deal with. Feel free to post your comments there.

Thank you, once again!