Bug #37162 Double free glib error in hp_free_level
Submitted: 3 Jun 2008 14:44 Modified: 17 Dec 2008 13:09
Reporter: Sharan RM Email Updates:
Status: No Feedback Impact on me:
None 
Category:MySQL Server: Embedded Library ( libmysqld ) Severity:S1 (Critical)
Version:5.1.24 OS:Linux (64-Bit)
Assigned to: CPU Architecture:Any

[3 Jun 2008 14:44] Sharan RM
Description:
I am using MySQL5.1 release embedded SQL.
when i enter SQL commands fast, i use to get double free in hp_free_level.
below is the stack trace

GNU Library version is 2.5

#0  0x0071f402 in __kernel_vsyscall ()
#1  0x00a9cc00 in raise () from /lib/libc.so.6
#2  0x00a9e451 in abort () from /lib/libc.so.6
#3  0x00ad221b in __libc_message () from /lib/libc.so.6
#4  0x00ad9f7d in _int_free () from /lib/libc.so.6
#5  0x00add5d0 in free () from /lib/libc.so.6
#6  0x08368595 in hp_free_level (block=0xa13c5c8, level=1, pos=0xa152ff0, 
    last_pos=0x0) at hp_block.c:148
#7  0x082e5b8b in hp_clear (info=0xa13c5c8) at hp_clear.c:34
#8  0x082e5df8 in hp_free (share=0xa13c5c8) at hp_create.c:298
#9  0x082e5c98 in hp_close (info=0xa149698) at hp_close.c:48
#10 0x0810ebb1 in free_tmp_table (thd=0xa12d728, entry=0xa14dd38)
    at sql_select.cc:10516
#11 0x080e985b in Materialized_cursor::close (this=0xa14e828) at sql_cursor.cc:686
#12 0x08108c61 in mysql_stmt_fetch (thd=0xa12d728, packet=0xbfddde60 "S", 
    packet_length=8) at sql_prepare.cc:2477
#13 0x08100ef1 in dispatch_command (command=COM_STMT_FETCH, thd=0xa12d728, 
    packet=<value optimized out>, packet_length=8) at sql_parse.cc:1081
#14 0x080a73e0 in emb_advanced_command (mysql=0x9d8f748, command=COM_STMT_FETCH, 
    header=0xbfddde60 "S", header_length=8, arg=0x0, arg_length=8, 
    skip_check=1 '\001', stmt=0x9d8ff28) at lib_sql.cc:121
#15 0x08053fd9 in stmt_read_row_from_cursor (stmt=0x9d8ff28, row=0xbfdddea8)
    at libmysql.c:2684
#16 0x08053a69 in mysql_stmt_fetch (stmt=0x9d8ff28) at libmysql.c:4564
#17 0x0804de1a in -[Queryobj m:fetch:data] (self=0x9d75218, _cmd=0x85e5bd0)
    at queryobj.m:403
---Type <return> to continue, or q <return> to quit---
#18 0x0804d497 in seriesxsql (ai_input_width=80, namptr=0xbfddfbc1 "ipc", 
    ai_silent=0, ac_delim=32 ' ') at xsql.m:264
#19 0x0804d876 in main (argc=2, argv=0xbfdde074, envp=0xbfdde080) at main_xsql.c:78

How to repeat:
This problem is reported earlier(Bug #27773) and the explanation was given to check in 5.1 release. This problem is reproducible in release5.1

How to repeat:

use prepare statement to prepare SQL statement.
bind the result
execute the statement and call mysql_fetch_data

run the application and enter the commands very fast.
[3 Jun 2008 19:50] Valeriy Kravchuk
Thank you for a problem report. What exact version, 5.1.x, you had used? Is it 5.1.24? Please, confirm.
[4 Jun 2008 6:11] Sharan RM
yes i am using 5.1.24 version.
downloaded the rpm from mysql section 
"Red Hat Enterprise Linux 5 RPM (x86) downloads"
[18 Jun 2008 15:14] MySQL Verification Team
Thank you for the bug report. Could you please provide a test case the bug you have mentioned looks is for the normal server. Thanks in advance.
[20 Jun 2008 9:27] Sharan RM
Test Case steps:
1) prepare an select statement using mysql_stmt_prepare.
2) dynamically find out the number of columns and dynamically allocate bind structure.
3) bind a character buffer to all the columns to same buffer using mysql_stmt_bind.
   ex: bind[0].data=(buffer + 0)
       bind[1].data=(buffer + length of first coloumn)
       ....
4)execute using mysql_stmt_execute
5)use mysql_stmt_fetch to fetch each row.
6)display the character buffer for each row.

include the above steps in a loop and enter select command for different tables

Note: mysql_stmt_init is called only once.
[20 Jun 2008 14:23] MySQL Verification Team
I've seen this crash before using Pentaho software and it went away when removing the cursor read options or prepared statements altogether.

A theory to make C testcase for this, we will need:

val=CURSOR_TYPE_READ_ONLY;
mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*)&val);
val=5000;
mysql_stmt_attr_set(stmt, STMT_ATTR_PREFETCH_ROWS, (void*)&val);

then run a few queries selecting different number of cols..
[24 Jun 2008 22:48] MySQL Verification Team
sample testcase according to description, but it don't crash...

Attachment: bug37162.c (text/plain), 16.29 KiB.

[24 Jun 2008 22:50] MySQL Verification Team
Hi Sharan, I attached a testcase here http://bugs.mysql.com/file.php?id=9563
I had tried to follow your descriptions, but didn't yet the crash.  Any suggestions or changes I can make to improve the testcase?
[25 Jun 2008 7:39] Sharan RM
Hi Shane, thanks for the suggestion.
after adding the below two lines. i am not facing crash anymore. 

val=5000;
mysql_stmt_attr_set(stmt, STMT_ATTR_PREFETCH_ROWS, (void*)&val);

I am not sure when it will occure next time. i ran almost 300 queries in less than 30 sec. 
could you please answer me, what above two lines means for crash to stop?
Thanks once again.
[25 Jun 2008 8:13] MySQL Verification Team
Sharan, I don't know how to repeat the crash yet, so cannot answer for sure.
Can you post a snippet of code indicating which mysql_stmt_* calls are made?   You can see my uploaded testcase for example.
[30 Jul 2008 9:37] Sharan RM
Please find the code below
(int)fech_from_db:(char *)ac_sql_string into:(char *)as_list
{
 unsigned long vl_type;
  MYSQL_RES *vs_prepare_meta_result;
  MYSQL_FIELD *vs_field;
  int vi_column_count, vi_pos;
  int vi_i;

  vl_type = (unsigned long) CURSOR_TYPE_READ_ONLY;
  mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &vl_type);

  vl_type=5000;
  mysql_stmt_attr_set(stmt, STMT_ATTR_PREFETCH_ROWS, (void*)&vl_type);

  if( mysql_stmt_prepare(stmt, ac_sql_string, strlen(ac_sql_string)) > 0)
  {
     printf("XSQL - ERROR -  Error in preparing statement \n");
     return ERROR;
  }
/* initialize the number of rows for SELECT statement */
  num_rows = 0;

  vs_prepare_meta_result = mysql_stmt_result_metadata(stmt);
  if (!vs_prepare_meta_result)
  {
     printf("XSQL - ERROR -  mysql_stmt_result_metadata(), returned no meta information\n");
     return ERROR;
  }
  /* Get total columns in the query */
  vi_column_count= mysql_num_fields(vs_prepare_meta_result);

  /* store the number of column in object structure */
  num_columns = vi_column_count;

  bind = (MYSQL_BIND *)malloc(vi_column_count * sizeof(MYSQL_BIND));
  is_null = (my_bool *)malloc(vi_column_count * sizeof(my_bool));
  length = (int *)malloc(vi_column_count * sizeof(int));
 ecp_buffer = as_list;
  vi_pos = 0;

  es_field = mysql_fetch_fields(vs_prepare_meta_result);
  vs_field = es_field;
  if(vs_field == NULL)
  {
    printf("XSQL - ERROR - Error in fetching field\n");
    return ERROR;
  }
  else
  {
     for(vi_i = 0; vi_i< vi_column_count; vi_i++,vs_field++)
     {
       bind[vi_i].buffer_type= vs_field->type;
       bind[vi_i].buffer= (ecp_buffer + vi_pos);
       bind[vi_i].buffer_length= vs_field->length;
       bind[vi_i].length= (length + vi_i);
       bind[vi_i].is_null= (is_null + vi_i);

       switch(vs_field->type)
       {
          case MYSQL_TYPE_VAR_STRING:
          case MYSQL_TYPE_STRING:
          case MYSQL_TYPE_VARCHAR:
                vi_pos += vs_field->length;
                break;
          case MYSQL_TYPE_TINY:
                vi_pos += sizeof(unsigned char);
                break;
          case MYSQL_TYPE_BIT:
                vi_pos += sizeof(unsigned long long int);
                break;
          case MYSQL_TYPE_SHORT:
                vi_pos += sizeof(short int);
                break;
          case MYSQL_TYPE_LONG:
                vi_pos += sizeof(int);
                break;
          case MYSQL_TYPE_FLOAT:
                vi_pos += sizeof(float);
                break;
          case MYSQL_TYPE_DOUBLE:
                vi_pos += sizeof(double);
                break;
          case MYSQL_TYPE_LONGLONG:
                vi_pos += sizeof(long long int);
                break;
          case MYSQL_TYPE_DATETIME:
                vi_pos += sizeof(MYSQL_TIME);
                break;
          case MYSQL_TYPE_DECIMAL:
                vi_pos += sizeof(MYSQL_TYPE_DECIMAL);
                break;

/* yet to be add Date time format */

          default:
                return ERROR;
        }

     }
  }
(int) fetch
{
   int vi_retCode;
   vi_retCode = mysql_stmt_fetch(stmt);
}
[17 Nov 2008 13:09] MySQL Verification Team
It is still repeatable with 5.1.29?. Thanks in advance.
[18 Dec 2008 0: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".