Bug #9401 type_timestamp segfaults mysqld
Submitted: 25 Mar 2005 9:04 Modified: 7 Apr 2005 2:05
Reporter: Guilhem Bichot Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server Severity:S3 (Non-critical)
Version:4.1 OS:Linux (linux)
Assigned to: Ramil Kalimullin CPU Architecture:Any

[25 Mar 2005 9:04] Guilhem Bichot
Description:
I have a 4.1 tree on a 4 Itanium2 Linux machine

Compilation:
'./configure' --prefix=3D/usr/local/mysql  '--prefix=3D/usr/local/mysql' '-=
-localstatedir=3D/usr/local/mysql/data' '--libexecdir=3D/usr/local/mysql/bi=
n' '--with-comment=3DMySQL Community Edition - Debug (GPL)' '--with-extra-c=
harsets=3Dcomplex' '--with-server-suffix=3D-debug' '--enable-thread-safe-cl=
ient' '--enable-local-infile' '--disable-shared' '--with-debug' '--with-rea=
dline' '--with-embedded-server' '--with-archive-storage-engine' '--with-inn=
odb' 'CXX=3Dgcc' 'CFLAGS=3D-g -O0 -DDBUG_ON -DSAFE_MUTEX ' 'CXXFLAGS=3D-g -=
O0 -DDBUG_ON -DSAFE_MUTEX -fno-implicit-templates -fno-exceptions -fno-rtti=
 -DUSE_MYSYS_NEW -DDEFINE_CXA_PURE_VIRTUAL' '--cache-file=3D/dev/null' '--s=
rcdir=3D.' CFLAGS=3D'-g -O0 -DDBUG_ON -DSAFE_MUTEX -g -O0 -DDBUG_ON -DSAFE_=
MUTEX ' CXXFLAGS=3D'-g -O0 -DDBUG_ON -DSAFE_MUTEX -g -O0 -DDBUG_ON -DSAFE_M=
UTEX -fno-implicit-templates -fno-exceptions -fno-rtti -DUSE_MYSYS_NEW -DDE=
FINE_CXA_PURE_VIRTUAL -fno-implicit-templates -fno-exceptions -fno-rtti -DU=
SE_MYSYS_NEW -DDEFINE_CXA_PURE_VIRTUAL' --cache-file=3D/dev/null --srcdir=
=3D.

Then I run test type_timestamp and mysqld crashes (func_date_add too,
but I haven't looked).

Can't reproduce it on my personal machine. But on this machine it's 100%
repeatable.

I simplified type_timestamp.test:

cat t/type_timestamp2.test
#
# Test timestamp
#

#
# Test for bug #4131, TIMESTAMP columns missing minutes and seconds when
# using GROUP BY in @@new=3D1 mode.
#
create temporary table t1 (a char(2), t timestamp);
insert into t1 values ('a', '2004-01-01 00:00:00');
insert into t1 values ('a', '2004-01-01 00:00:00');
select max(t) from t1 group by a;

is enough to crash.

The crash is in Field_timestamp::val_str():

Field_timestamp::val_str (this=3D0x6000000000aa4088, val_buffer=3D0x6000000=
000aa2678, val_ptr=3D0x6000000000aa2678)
    at field.cc:3146
3146        *to++=3D '2';
(gdb) bt
#0  Field_timestamp::val_str (this=3D0x6000000000aa4088, val_buffer=3D0x600=
0000000aa2678, val_ptr=3D0x6000000000aa2678)
    at field.cc:3146
#1  0x40000000002b3fa0 in Field::val_str (this=3D0x6000000000aa4088, str=3D=
0x6000000000aa2678) at field.h:106
#2  0x40000000001731c0 in Item_sum_hybrid::min_max_update_str_field (this=
=3D0x6000000000aa25d8) at item_sum.cc:934
#3  0x4000000000172fb0 in Item_sum_hybrid::update_field (this=3D0x600000000=
0aa25d8) at item_sum.cc:918
#4  0x4000000000415ba0 in update_tmptable_sum_func (func_ptr=3D0x6000000000=
aa38c8, tmp_table=3D0x6000000000aa66b0)
    at sql_select.cc:8891
#5  0x4000000000403ae0 in end_update (join=3D0x6000000000aa28e0, join_tab=
=3D0x6000000000aa3e98, end_of_records=3Dfalse)
    at sql_select.cc:6641
#6  0x40000000003fc480 in sub_select (join=3D0x6000000000aa28e0, join_tab=
=3D0x6000000000aa3cb8, end_of_records=3Dfalse)
    at sql_select.cc:5821
#7  0x40000000003fb310 in do_select (join=3D0x6000000000aa28e0, fields=3D0x=
0, table=3D0x6000000000aa66b0, procedure=3D0x0)
    at sql_select.cc:5705
#8  0x40000000003d1870 in JOIN::exec (this=3D0x6000000000aa28e0) at sql_sel=
ect.cc:1149
#9  0x40000000003d5e70 in mysql_select (thd=3D0x6000000000a81610, rref_poin=
ter_array=3D0x6000000000a819f0,
    tables=3D0x6000000000aa2728, wild_num=3D0, fields=3D@0x6000000000a818f0=
, conds=3D0x0, og_num=3D1, order=3D0x0,
    group=3D0x6000000000aa2880, having=3D0x0, proc_param=3D0x0, select_opti=
ons=3D2156153344, result=3D0x6000000000aa28c8,
    unit=3D0x6000000000a81688, select_lex=3D0x6000000000a81828) at sql_sele=
ct.cc:1603
#10 0x40000000003c81d0 in handle_select (thd=3D0x6000000000a81610, lex=3D0x=
6000000000a81678, result=3D0x6000000000aa28c8)
    at sql_select.cc:182
#11 0x400000000035df90 in mysql_execute_command (thd=3D0x6000000000a81610) =
at sql_parse.cc:2082
#12 0x400000000036cfa0 in mysql_parse (thd=3D0x6000000000a81610,
    inBuf=3D0x6000000000aa24c0 "select max(t) from t1 group by a", length=
=3D32) at sql_parse.cc:4187

because "to" is 0.
"to" here is the tmp_value.ptr() of an Item_sum_max which was created
in sql_yacc.yy.
I have observed that when this Item_sum_max is created, the tmp_value
String is correctly set (it has Ptr=3D0, Alloced_length=3D0 etc, as the
String::String() constructor says).
Later (see below) this String (tmp_value) becomes garbage hence the
bad value of tmp_value.ptr() and then of 'to'.

Below the variable which I display (*(String*) 69175...) is the
tmp_value which I want to monitor (to see where it becomes wrong).
6917529027652232824 is 0x6000000000aa2678.
Here I break gdb exactly at the line where tmp_value becomes wrong:

Breakpoint 10, create_tmp_field_from_field (thd=3D0x6000000000a81610, org_f=
ield=3D0x6000000000a83a88, item=3D0x6000000000aa25d8,
    table=3D0x6000000000aa66b0, modify_item=3Dtrue, convert_blob_length=3D0=
) at sql_select.cc:4640
4640          ((Item_field *)item)->result_field=3D new_field;
1: *(String *) 6917529027652232824 =3D {Ptr =3D 0x0, str_length =3D 0, Allo=
ced_length =3D 0, alloced =3D false,
  str_charset =3D 0x6000000000150bb0}
(gdb) p item
$31 =3D (class Item *) 0x6000000000aa25d8
(gdb) p &((Item_field *)item)->result_field
$32 =3D (class Field **) 0x6000000000aa2680

^^^^^^ this points right into tmp_value !!! ^^^^^^^

(gdb) x/10 0x6000000000aa2678
0x6000000000aa2678:     0x00000000      0x00000000      0x00000000      0x0=
0000000
0x6000000000aa2688:     0x00aa2700      0x60000000      0x00150bb0      0x6=
0000000
0x6000000000aa2698:     0x00000000      0x00000000

^^^ still correct, as we haven't executed the assignment ^^^^

(gdb) n
4643        if (org_field->maybe_null())
1: *(String *) 6917529027652232824 =3D {Ptr =3D 0x0, str_length =3D 1115764=
0, Alloced_length =3D 1610612736, alloced =3D false,
  str_charset =3D 0x6000000000150bb0}
(gdb) x/10 0x6000000000aa2678
0x6000000000aa2678:     0x00000000      0x00000000      0x00aa4088      0x6=
0000000
0x6000000000aa2688:     0x00aa2700      0x60000000      0x00150bb0      0x6=
0000000
0x6000000000aa2698:     0x00000000      0x00000000

^^^^^^^ that's it: starting from position aa2680 tmp_value has been overwri=
tten. ^^^
Alloced_length has gotten enormous, which makes String::alloc()
(called in String *Field_timestamp::val_str(String *val_buffer, String
*val_ptr)) believe this String is already alloced (of course it's not:
Ptr is 0) so tries to write to Ptr.

How come this happens? Well 'item' is cast to Item_field in the
assignment. But 'item' is Item_sum_max, which derives from
Item_sum_hybrid which derives from Item_sum which derives from
Item_result_field which derives from Item. Nowhere in this chain you
can see Item_field. So this is an INVALID CAST.

Here's how we come to the faulty assignment.
(gdb) bt
#0  create_tmp_field_from_field (thd=3D0x6000000000a81610, org_field=3D0x60=
00000000a83a88, item=3D0x6000000000aa25d8,
    table=3D0x6000000000aa66b0, modify_item=3Dtrue, convert_blob_length=3D0=
) at sql_select.cc:4643
#1  0x40000000003f2bf0 in create_tmp_field (thd=3D0x6000000000a81610, table=
=3D0x6000000000aa66b0, item=3D0x6000000000aa25d8,
    type=3DSUM_FUNC_ITEM, copy_func=3D0x2000000003bba008, from_field=3D0x60=
00000000aa6ef8, group=3Dtrue, modify_item=3Dtrue,
    convert_blob_length=3D0) at sql_select.cc:4782
#2  0x40000000003f4fb0 in create_tmp_table (thd=3D0x6000000000a81610, param=
=3D0x6000000000aa35c0, fields=3D@0x6000000000aa36d8,
    group=3D0x6000000000aa2880, distinct=3Dfalse, save_sum_fields=3Dfalse, =
select_options=3D2156153344,
    rows_limit=3D18446744073709551615, table_alias=3D0x40000000009d5cb0 "")=
 at sql_select.cc:5048
#3  0x40000000003cea80 in JOIN::optimize (this=3D0x6000000000aa28e0) at sql=
_select.cc:868

I would be happy to test your changes if you want me too.

How to repeat:
run type_timestamp in a 4.1 build (using configure of above, which is standard configure we use for gcc binaries on this machine) on this machine.

Suggested fix:
fix wrong cast?
[28 Mar 2005 9:31] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/internals/23410
[30 Mar 2005 5:18] Sergey Petrunya
According to Ramil (and Serg and Sanja) feedback the fix isn't right, working on a better one.
[30 Mar 2005 9:43] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/internals/23465
[7 Apr 2005 2:04] Paul DuBois
Noted in 4.1.11 changelog.