Commit 43dd5f39 authored by unknown's avatar unknown

BUG#31277 - myisamchk --unpack corrupts a table

With certain data sets (when compressed record length gets bigger than
uncompressed) myisamchk --unpack may corrupt data file.

Fixed that record length was wrongly restored from compressed table.


myisam/mi_check.c:
  With compressed tables compressed record length may be bigger than
  pack_reclength, thus we may allocate insufficient memory for record
  buffer.
  
  Let single function allocate record buffer, performing needed record
  length calculations.
  
  Still, it is not doable with parallel repair, as it allocates needed
  record buffers at once. For parellel repair added better record length
  calculation.
myisam/mi_open.c:
  When calculating record buffer size, take into account that compressed
  record length may be bigger than uncompressed.
myisam/mi_packrec.c:
  With certain data set share->max_pack_length (compressed record length)
  may be bigger than share->base.pack_reclength (packed record length).
  
  set_if_bigger(pack_reclength, max_pack_length) in this case causes
  myisamchk --unpack to write extra garbage, whereas pack_reclength
  remains the same in new index file. As a result we get unreadable
  table.
myisam/myisamchk.c:
  With compressed tables compressed record length may be bigger than
  pack_reclength, thus we may allocate insufficient memory for record
  buffer.
  
  Let single function allocate record buffer, performing needed record
  length calculations.
mysql-test/mysql-test-run.pl:
  Environment variables to execute myisamchk and myisampack.
mysql-test/r/myisampack.result:
  New BitKeeper file ``mysql-test/r/myisampack.result''
mysql-test/t/myisampack.test:
  New BitKeeper file ``mysql-test/t/myisampack.test''
parent de14c6ac
......@@ -940,7 +940,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
ha_rows records,del_blocks;
my_off_t used,empty,pos,splits,start_recpos,
del_length,link_used,start_block;
byte *record,*to;
byte *record= 0, *to;
char llbuff[22],llbuff2[22],llbuff3[22];
ha_checksum intern_record_checksum;
ha_checksum key_checksum[MI_MAX_POSSIBLE_KEY];
......@@ -957,7 +957,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
puts("- check record links");
}
if (!(record= (byte*) my_malloc(info->s->base.pack_reclength,MYF(0))))
if (!mi_alloc_rec_buff(info, -1, &record))
{
mi_check_print_error(param,"Not enough memory for record");
DBUG_RETURN(-1);
......@@ -1364,12 +1364,12 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
printf("Lost space: %12s Linkdata: %10s\n",
llstr(empty,llbuff),llstr(link_used,llbuff2));
}
my_free((gptr) record,MYF(0));
my_free(mi_get_rec_buff_ptr(info, record), MYF(0));
DBUG_RETURN (error);
err:
mi_check_print_error(param,"got error: %d when reading datafile at record: %s",my_errno, llstr(records,llbuff));
err2:
my_free((gptr) record,MYF(0));
my_free(mi_get_rec_buff_ptr(info, record), MYF(0));
param->testflag|=T_RETRY_WITHOUT_QUICK;
DBUG_RETURN(1);
} /* chk_data_link */
......@@ -1428,8 +1428,7 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
MYF(MY_WME | MY_WAIT_IF_FULL)))
goto err;
info->opt_flag|=WRITE_CACHE_USED;
if (!(sort_param.record=(byte*) my_malloc((uint) share->base.pack_reclength,
MYF(0))) ||
if (!mi_alloc_rec_buff(info, -1, &sort_param.record) ||
!mi_alloc_rec_buff(info, -1, &sort_param.rec_buff))
{
mi_check_print_error(param, "Not enough memory for extra record");
......@@ -1631,7 +1630,8 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
}
my_free(mi_get_rec_buff_ptr(info, sort_param.rec_buff),
MYF(MY_ALLOW_ZERO_PTR));
my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR));
my_free(mi_get_rec_buff_ptr(info, sort_param.record),
MYF(MY_ALLOW_ZERO_PTR));
my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
VOID(end_io_cache(&param->read_cache));
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
......@@ -2129,8 +2129,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
info->opt_flag|=WRITE_CACHE_USED;
info->rec_cache.file=info->dfile; /* for sort_delete_record */
if (!(sort_param.record=(byte*) my_malloc((uint) share->base.pack_reclength,
MYF(0))) ||
if (!mi_alloc_rec_buff(info, -1, &sort_param.record) ||
!mi_alloc_rec_buff(info, -1, &sort_param.rec_buff))
{
mi_check_print_error(param, "Not enough memory for extra record");
......@@ -2415,7 +2414,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
my_free(mi_get_rec_buff_ptr(info, sort_param.rec_buff),
MYF(MY_ALLOW_ZERO_PTR));
my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR));
my_free(mi_get_rec_buff_ptr(info, sort_param.record),
MYF(MY_ALLOW_ZERO_PTR));
my_free((gptr) sort_info.key_block,MYF(MY_ALLOW_ZERO_PTR));
my_free((gptr) sort_info.ft_buf, MYF(MY_ALLOW_ZERO_PTR));
my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
......@@ -2493,6 +2493,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
SORT_INFO sort_info;
ulonglong key_map=share->state.key_map;
pthread_attr_t thr_attr;
ulong max_pack_reclength;
DBUG_ENTER("mi_repair_parallel");
start_records=info->state->records;
......@@ -2649,10 +2650,13 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
del=info->state->del;
param->glob_crc=0;
/* for compressed tables */
max_pack_reclength= share->base.pack_reclength;
if (share->options & HA_OPTION_COMPRESS_RECORD)
set_if_bigger(max_pack_reclength, share->max_pack_length);
if (!(sort_param=(MI_SORT_PARAM *)
my_malloc((uint) share->base.keys *
(sizeof(MI_SORT_PARAM) + share->base.pack_reclength),
(sizeof(MI_SORT_PARAM) + max_pack_reclength),
MYF(MY_ZEROFILL))))
{
mi_check_print_error(param,"Not enough memory for key!");
......@@ -2704,7 +2708,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
sort_param[i].max_pos=sort_param[i].pos=share->pack.header_length;
sort_param[i].record= (((char *)(sort_param+share->base.keys))+
(share->base.pack_reclength * i));
(max_pack_reclength * i));
if (!mi_alloc_rec_buff(info, -1, &sort_param[i].rec_buff))
{
mi_check_print_error(param,"Not enough memory!");
......@@ -4320,7 +4324,7 @@ int update_state_info(MI_CHECK *param, MI_INFO *info,uint update)
void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
my_bool repair_only)
{
byte *record;
byte *record= 0;
DBUG_ENTER("update_auto_increment_key");
if (!info->s->base.auto_key ||
......@@ -4340,8 +4344,7 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
We have to use an allocated buffer instead of info->rec_buff as
_mi_put_key_in_record() may use info->rec_buff
*/
if (!(record= (byte*) my_malloc((uint) info->s->base.pack_reclength,
MYF(0))))
if (!mi_alloc_rec_buff(info, -1, &record))
{
mi_check_print_error(param,"Not enough memory for extra record");
DBUG_VOID_RETURN;
......@@ -4353,7 +4356,7 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
if (my_errno != HA_ERR_END_OF_FILE)
{
mi_extra(info,HA_EXTRA_NO_KEYREAD,0);
my_free((char*) record, MYF(0));
my_free(mi_get_rec_buff_ptr(info, record), MYF(0));
mi_check_print_error(param,"%d when reading last record",my_errno);
DBUG_VOID_RETURN;
}
......@@ -4369,7 +4372,7 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
set_if_bigger(info->s->state.auto_increment,auto_increment);
}
mi_extra(info,HA_EXTRA_NO_KEYREAD,0);
my_free((char*) record, MYF(0));
my_free(mi_get_rec_buff_ptr(info, record), MYF(0));
update_state_info(param, info, UPDATE_AUTO_INC);
DBUG_VOID_RETURN;
}
......
......@@ -659,8 +659,11 @@ byte *mi_alloc_rec_buff(MI_INFO *info, ulong length, byte **buf)
/* to simplify initial init of info->rec_buf in mi_open and mi_extra */
if (length == (ulong) -1)
{
length= max(info->s->base.pack_reclength,
info->s->base.max_key_length);
if (info->s->options & HA_OPTION_COMPRESS_RECORD)
length= max(info->s->base.pack_reclength, info->s->max_pack_length);
else
length= info->s->base.pack_reclength;
length= max(length, info->s->base.max_key_length);
/* Avoid unnecessary realloc */
if (newptr && length == old_length)
return newptr;
......
......@@ -164,7 +164,6 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys)
share->pack.header_length= uint4korr(header+4);
share->min_pack_length=(uint) uint4korr(header+8);
share->max_pack_length=(uint) uint4korr(header+12);
set_if_bigger(share->base.pack_reclength,share->max_pack_length);
elements=uint4korr(header+16);
intervall_length=uint4korr(header+20);
trees=uint2korr(header+24);
......
......@@ -1543,8 +1543,8 @@ static int mi_sort_records(MI_CHECK *param,
mi_check_print_error(param,"Not enough memory for key block");
goto err;
}
if (!(sort_param.record=(byte*) my_malloc((uint) share->base.pack_reclength,
MYF(0))))
if (!mi_alloc_rec_buff(info, -1, &sort_param.record))
{
mi_check_print_error(param,"Not enough memory for record");
goto err;
......@@ -1639,7 +1639,8 @@ static int mi_sort_records(MI_CHECK *param,
{
my_afree((gptr) temp_buff);
}
my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR));
my_free(mi_get_rec_buff_ptr(info, sort_param.record),
MYF(MY_ALLOW_ZERO_PTR));
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
VOID(end_io_cache(&info->rec_cache));
my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
......
......@@ -1880,6 +1880,21 @@ sub environment_setup () {
($lib_udf_example ? dirname($lib_udf_example) : "") .
($ENV{'LD_LIBRARY_PATH'} ? ":$ENV{'LD_LIBRARY_PATH'}" : "");
# ----------------------------------------------------
# Setup env so childs can execute myisampack and myisamchk
# ----------------------------------------------------
$ENV{'MYISAMCHK'}= mtr_native_path(mtr_exe_exists(
vs_config_dirs('storage/myisam', 'myisamchk'),
vs_config_dirs('myisam', 'myisamchk'),
"$path_client_bindir/myisamchk",
"$glob_basedir/storage/myisam/myisamchk",
"$glob_basedir/myisam/myisamchk"));
$ENV{'MYISAMPACK'}= mtr_native_path(mtr_exe_exists(
vs_config_dirs('storage/myisam', 'myisampack'),
vs_config_dirs('myisam', 'myisampack'),
"$path_client_bindir/myisampack",
"$glob_basedir/storage/myisam/myisampack",
"$glob_basedir/myisam/myisampack"));
# ----------------------------------------------------
# We are nice and report a bit about our settings
......
CREATE TABLE t1(c1 DOUBLE, c2 DOUBLE, c3 DOUBLE, c4 DOUBLE, c5 DOUBLE,
c6 DOUBLE, c7 DOUBLE, c8 DOUBLE, c9 DOUBLE, a INT PRIMARY KEY);
INSERT INTO t1 VALUES
(-3.31168791059336e-06,-3.19054655887874e-06,-1.06528081684847e-05,-1.227278240089e-06,-1.66718069164799e-06,-2.59038972510885e-06,-2.83145227805303e-06,-4.09678491270648e-07,-2.22610091291797e-06,6),
(0.0030743000272545,2.53222044316438e-05,2.78674650061845e-05,1.95914465544536e-05,1.7347572525984e-05,1.87513810069614e-05,1.69882826885005e-05,2.44449336987598e-05,1.89914629921774e-05,9),
(2.85229319423495e-05,3.05970988282259e-05,3.77161100113133e-05,2.3055238978766e-05,2.08241267364615e-05,2.28009504270553e-05,2.12070165658947e-05,2.84350091565409e-05,2.3366822910704e-05,3),
(0,0,0,0,0,0,0,0,0,12),
(3.24544577570754e-05,3.44619021870993e-05,4.37561613201124e-05,2.57556808726748e-05,2.3195354640561e-05,2.58532400758869e-05,2.34934241667179e-05,3.1621640063232e-05,2.58229982746189e-05,19),
(2.53222044316438e-05,0.00445071933455582,2.97447268116016e-05,2.12379514059868e-05,1.86777776502663e-05,2.0170058676712e-05,1.8946030385445e-05,2.66040037173511e-05,2.09161899668946e-05,20),
(3.03462382611645e-05,3.26517930083994e-05,3.5242025468662e-05,2.53219745106391e-05,2.24384532945004e-05,2.4052346047657e-05,2.23865572957053e-05,3.1634313969082e-05,2.48285463481801e-05,21),
(1.95914465544536e-05,2.12379514059868e-05,2.27808649037128e-05,0.000341724375366877,1.4512761275113e-05,1.56475828693953e-05,1.44372366441415e-05,2.07952121981765e-05,1.61488256935919e-05,28),
(1.7347572525984e-05,1.86777776502663e-05,2.04116907052727e-05,1.4512761275113e-05,0.000432162526082388,1.38116514014465e-05,1.2712914948904e-05,1.82503165178506e-05,1.43043075345922e-05,30),
(1.68339762136661e-05,1.77836497166611e-05,2.36328309295222e-05,1.30183423732016e-05,1.18674654241553e-05,1.32467273128652e-05,1.24581739117775e-05,1.55624190959406e-05,1.33010638508213e-05,31),
(1.89643062824415e-05,2.06997140070717e-05,2.29045490159364e-05,1.57918175731019e-05,1.39864987449492e-05,1.50580274578455e-05,1.45908734129609e-05,1.95329296993327e-05,1.5814709481221e-05,32),
(1.69882826885005e-05,1.8946030385445e-05,2.00820439721439e-05,1.44372366441415e-05,1.2712914948904e-05,1.35209686474184e-05,0.00261563314789896,1.78285095864627e-05,1.46699314500019e-05,34),
(2.0278186540684e-05,2.18923409729654e-05,2.39981539939738e-05,1.71774589459438e-05,1.54654355357383e-05,1.62731485707636e-05,1.49253140625051e-05,2.18229800160297e-05,1.71923561673718e-05,35),
(2.44449336987598e-05,2.66040037173511e-05,2.84860148925308e-05,2.07952121981765e-05,1.82503165178506e-05,1.97667730441441e-05,1.78285095864627e-05,0.00166478601822712,2.0299952103232e-05,36),
(1.89914629921774e-05,2.09161899668946e-05,2.26026841007872e-05,1.61488256935919e-05,1.43043075345922e-05,1.52609063290127e-05,1.46699314500019e-05,2.0299952103232e-05,0.00306670170971682,39),
(0,0,0,0,0,0,0,0,0,41),
(0,0,0,0,0,0,0,0,0,17),
(0,0,0,0,0,0,0,0,0,18),
(2.51880677333017e-05,2.63051795435778e-05,2.79874748974906e-05,2.02888886670845e-05,1.8178636318197e-05,1.91308527003585e-05,1.83260023644133e-05,2.4422300558171e-05,1.96411467520551e-05,44),
(2.22402118719591e-05,2.37546284320705e-05,2.58463051055541e-05,1.83391609130854e-05,1.6300720519646e-05,1.74559091886791e-05,1.63733785575587e-05,2.26616253279828e-05,1.79541237435621e-05,45),
(3.01092775359837e-05,3.23865212934412e-05,4.09444584045994e-05,0,2.15470966302776e-05,2.39082636344032e-05,2.28296706429177e-05,2.9007671511595e-05,2.44201138973326e-05,46);
FLUSH TABLES;
CHECK TABLE t1 EXTENDED;
Table Op Msg_type Msg_text
test.t1 check status OK
DROP TABLE t1;
#
# BUG#31277 - myisamchk --unpack corrupts a table
#
CREATE TABLE t1(c1 DOUBLE, c2 DOUBLE, c3 DOUBLE, c4 DOUBLE, c5 DOUBLE,
c6 DOUBLE, c7 DOUBLE, c8 DOUBLE, c9 DOUBLE, a INT PRIMARY KEY);
INSERT INTO t1 VALUES
(-3.31168791059336e-06,-3.19054655887874e-06,-1.06528081684847e-05,-1.227278240089e-06,-1.66718069164799e-06,-2.59038972510885e-06,-2.83145227805303e-06,-4.09678491270648e-07,-2.22610091291797e-06,6),
(0.0030743000272545,2.53222044316438e-05,2.78674650061845e-05,1.95914465544536e-05,1.7347572525984e-05,1.87513810069614e-05,1.69882826885005e-05,2.44449336987598e-05,1.89914629921774e-05,9),
(2.85229319423495e-05,3.05970988282259e-05,3.77161100113133e-05,2.3055238978766e-05,2.08241267364615e-05,2.28009504270553e-05,2.12070165658947e-05,2.84350091565409e-05,2.3366822910704e-05,3),
(0,0,0,0,0,0,0,0,0,12),
(3.24544577570754e-05,3.44619021870993e-05,4.37561613201124e-05,2.57556808726748e-05,2.3195354640561e-05,2.58532400758869e-05,2.34934241667179e-05,3.1621640063232e-05,2.58229982746189e-05,19),
(2.53222044316438e-05,0.00445071933455582,2.97447268116016e-05,2.12379514059868e-05,1.86777776502663e-05,2.0170058676712e-05,1.8946030385445e-05,2.66040037173511e-05,2.09161899668946e-05,20),
(3.03462382611645e-05,3.26517930083994e-05,3.5242025468662e-05,2.53219745106391e-05,2.24384532945004e-05,2.4052346047657e-05,2.23865572957053e-05,3.1634313969082e-05,2.48285463481801e-05,21),
(1.95914465544536e-05,2.12379514059868e-05,2.27808649037128e-05,0.000341724375366877,1.4512761275113e-05,1.56475828693953e-05,1.44372366441415e-05,2.07952121981765e-05,1.61488256935919e-05,28),
(1.7347572525984e-05,1.86777776502663e-05,2.04116907052727e-05,1.4512761275113e-05,0.000432162526082388,1.38116514014465e-05,1.2712914948904e-05,1.82503165178506e-05,1.43043075345922e-05,30),
(1.68339762136661e-05,1.77836497166611e-05,2.36328309295222e-05,1.30183423732016e-05,1.18674654241553e-05,1.32467273128652e-05,1.24581739117775e-05,1.55624190959406e-05,1.33010638508213e-05,31),
(1.89643062824415e-05,2.06997140070717e-05,2.29045490159364e-05,1.57918175731019e-05,1.39864987449492e-05,1.50580274578455e-05,1.45908734129609e-05,1.95329296993327e-05,1.5814709481221e-05,32),
(1.69882826885005e-05,1.8946030385445e-05,2.00820439721439e-05,1.44372366441415e-05,1.2712914948904e-05,1.35209686474184e-05,0.00261563314789896,1.78285095864627e-05,1.46699314500019e-05,34),
(2.0278186540684e-05,2.18923409729654e-05,2.39981539939738e-05,1.71774589459438e-05,1.54654355357383e-05,1.62731485707636e-05,1.49253140625051e-05,2.18229800160297e-05,1.71923561673718e-05,35),
(2.44449336987598e-05,2.66040037173511e-05,2.84860148925308e-05,2.07952121981765e-05,1.82503165178506e-05,1.97667730441441e-05,1.78285095864627e-05,0.00166478601822712,2.0299952103232e-05,36),
(1.89914629921774e-05,2.09161899668946e-05,2.26026841007872e-05,1.61488256935919e-05,1.43043075345922e-05,1.52609063290127e-05,1.46699314500019e-05,2.0299952103232e-05,0.00306670170971682,39),
(0,0,0,0,0,0,0,0,0,41),
(0,0,0,0,0,0,0,0,0,17),
(0,0,0,0,0,0,0,0,0,18),
(2.51880677333017e-05,2.63051795435778e-05,2.79874748974906e-05,2.02888886670845e-05,1.8178636318197e-05,1.91308527003585e-05,1.83260023644133e-05,2.4422300558171e-05,1.96411467520551e-05,44),
(2.22402118719591e-05,2.37546284320705e-05,2.58463051055541e-05,1.83391609130854e-05,1.6300720519646e-05,1.74559091886791e-05,1.63733785575587e-05,2.26616253279828e-05,1.79541237435621e-05,45),
(3.01092775359837e-05,3.23865212934412e-05,4.09444584045994e-05,0,2.15470966302776e-05,2.39082636344032e-05,2.28296706429177e-05,2.9007671511595e-05,2.44201138973326e-05,46);
FLUSH TABLES;
--exec $MYISAMPACK -s $MYSQLTEST_VARDIR/master-data/test/t1
--exec $MYISAMCHK -srq $MYSQLTEST_VARDIR/master-data/test/t1
--exec $MYISAMCHK -s --unpack $MYSQLTEST_VARDIR/master-data/test/t1
CHECK TABLE t1 EXTENDED;
DROP TABLE t1;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment