Commit d2ce2d2e authored by unknown's avatar unknown

Fixed wrong memory references found by purify

(No really critical errors found, but a few possible wrong results)


innobase/dict/dict0dict.c:
  Replace memcmp with comparison of characters to avoid warnings from purify when 'sptr' points to a very short string
mysql-test/r/select_found.result:
  Add missing drop table
mysql-test/r/type_set.result:
  More tests
mysql-test/t/select_found.test:
  Add missing drop table
mysql-test/t/type_set.test:
  More tests
mysys/my_init.c:
  Avoid warning from purify (purify doesn't handle getrusage() properly)
sql/field.h:
  enum & set are sorted as numbers. This fixes an access to uninitialized memory when enum/set are multi-byte characters
sql/filesort.cc:
  enum & set are sorted as numbers. This fixes an access to uninitialized memory when enum/set are multi-byte characters
sql/item_cmpfunc.cc:
  Fixed warning from purify. (Not critical as the arguments are passed to a function but not used)
  Allocate Arg_comparator() with 'new' instead of sql_alloc() to ensure proper initialization
sql/mysqld.cc:
  Wait for signal handler to stop when running --bootstrap
  (Fixes warning from purify)
sql/sql_insert.cc:
  Initialize slot used by innodb.cc (not critical)
sql/sql_lex.h:
  Better comments
sql/sql_repl.cc:
  memcmp -> bcmp() to avoid warning from purify
sql/sql_select.cc:
  Fix for out-of-bound memory reference when doing DISTINCT on const expressions
strings/ctype-simple.c:
  Fixes to not access uninitialized memory
  (Not critical)
parent 43e566e6
......@@ -2671,7 +2671,8 @@ dict_strip_comments(
/* Starting quote: remember the quote character. */
quote = *sptr;
} else if (*sptr == '#'
|| (0 == memcmp("-- ", sptr, 3))) {
|| (sptr[0] == '-' && sptr[1] == '-' &&
sptr[2] == ' ')) {
for (;;) {
/* In Unix a newline is 0x0A while in Windows
it is 0x0D followed by 0x0A */
......
......@@ -254,3 +254,4 @@ a
SELECT FOUND_ROWS();
FOUND_ROWS()
1
DROP TABLE t1;
......@@ -29,6 +29,12 @@ a
A
a,A
a,A
select s from t1 order by concat(s);
s
A
a
a,A
a,A
drop table t1;
CREATE TABLE t1 (c set('ae','oe','ue','ss') collate latin1_german2_ci);
INSERT INTO t1 VALUES (''),(''),(''),('');
......@@ -47,4 +53,16 @@ ss
ss
ae,oe,ue,ss
ae,oe,ue,ss
SELECT c FROM t1 ORDER BY concat(c);
c
ae
ae
ae,oe,ue,ss
ae,oe,ue,ss
oe
oe
ss
ss
ue
ue
DROP TABLE t1;
......@@ -175,3 +175,4 @@ CREATE TABLE t1 (a int, b int);
INSERT INTO t1 VALUES (1,2), (1,3), (1,4), (1,5);
SELECT SQL_CALC_FOUND_ROWS DISTINCT 'a' FROM t1 GROUP BY b LIMIT 2;
SELECT FOUND_ROWS();
DROP TABLE t1;
......@@ -23,6 +23,7 @@ create table t1 (s set ('a','A') character set latin1 collate latin1_bin);
show create table t1;
insert into t1 values ('a'),('a,A'),('A,a'),('A');
select s from t1 order by s;
select s from t1 order by concat(s);
drop table t1;
#
......@@ -34,4 +35,5 @@ INSERT INTO t1 VALUES ('ae'),('oe'),('ue'),('ss');
INSERT INTO t1 VALUES (',,,');
INSERT INTO t1 VALUES ('ae,oe,ue,ss');
SELECT c FROM t1 ORDER BY c;
SELECT c FROM t1 ORDER BY concat(c);
DROP TABLE t1;
......@@ -145,6 +145,10 @@ void my_end(int infoflag)
{
#ifdef HAVE_GETRUSAGE
struct rusage rus;
#ifdef HAVE_purify
/* Purify assumes that rus is uninitialized after getrusage call */
bzero((char*) &rus, sizeof(rus));
#endif
if (!getrusage(RUSAGE_SELF, &rus))
fprintf(info_file,"\n\
User time %.2f, System time %.2f\n\
......
......@@ -277,6 +277,7 @@ class Field
virtual bool get_date(TIME *ltime,uint fuzzydate);
virtual bool get_time(TIME *ltime);
virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; }
virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
virtual bool has_charset(void) const { return FALSE; }
virtual void set_charset(CHARSET_INFO *charset) { }
bool set_warning(const unsigned int level, const unsigned int code,
......@@ -1152,6 +1153,8 @@ class Field_enum :public Field_str {
bool optimize_range(uint idx, uint part) { return 0; }
bool eq_def(Field *field);
bool has_charset(void) const { return TRUE; }
/* enum and set are sorted as integers */
CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
field_cast_enum field_cast_type() { return FIELD_CAST_ENUM; }
};
......
......@@ -1127,7 +1127,7 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
else
{
sortorder->length=sortorder->field->pack_length();
if (use_strnxfrm((cs=sortorder->field->charset())))
if (use_strnxfrm((cs=sortorder->field->sort_charset())))
{
sortorder->need_strxnfrm= 1;
*multi_byte_charset= 1;
......
......@@ -265,7 +265,7 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
comparators= 0;
return 1;
}
if (!(comparators= (Arg_comparator *) sql_alloc(sizeof(Arg_comparator)*n)))
if (!(comparators= new Arg_comparator[n]))
return 1;
for (uint i=0; i < n; i++)
{
......@@ -1528,6 +1528,12 @@ in_row::in_row(uint elements, Item * item)
size= sizeof(cmp_item_row);
compare= (qsort2_cmp) cmp_row;
tmp.store_value(item);
/*
We need to reset these as otherwise we will call sort() with
uninitialized (even if not used) elements
*/
used_count= elements;
collation= 0;
}
in_row::~in_row()
......
......@@ -530,6 +530,7 @@ extern "C" pthread_handler_decl(handle_slave,arg);
static ulong find_bit_type(const char *x, TYPELIB *bit_lib);
static void clean_up(bool print_message);
static void clean_up_mutexes(void);
static void wait_for_signal_thread_to_end(void);
static int test_if_case_insensitive(const char *dir_name);
static void create_pid_file();
......@@ -918,6 +919,7 @@ extern "C" void unireg_abort(int exit_code)
sql_print_error("Aborting\n");
clean_up(exit_code || !opt_bootstrap); /* purecov: inspected */
DBUG_PRINT("quit",("done with cleanup in unireg_abort"));
wait_for_signal_thread_to_end();
clean_up_mutexes();
my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
exit(exit_code); /* purecov: inspected */
......@@ -1023,6 +1025,29 @@ void clean_up(bool print_message)
} /* clean_up */
/*
This is mainly needed when running with purify, but it's still nice to
know that all child threads have died when mysqld exits
*/
static void wait_for_signal_thread_to_end()
{
#ifndef __NETWARE__
uint i;
/*
Wait up to 10 seconds for signal thread to die. We use this mainly to
avoid getting warnings that my_thread_end has not been called
*/
for (i= 0 ; i < 100 && signal_thread_in_use; i++)
{
if (pthread_kill(signal_thread, MYSQL_KILL_SIGNAL))
break;
my_sleep(100); // Give it time to die
}
#endif
}
static void clean_up_mutexes()
{
(void) pthread_mutex_destroy(&LOCK_mysql_create_db);
......@@ -2117,6 +2142,7 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
while ((error=my_sigwait(&set,&sig)) == EINTR) ;
if (cleanup_done)
{
DBUG_PRINT("quit",("signal_handler: calling my_thread_end()"));
my_thread_end();
signal_thread_in_use= 0;
pthread_exit(0); // Safety
......@@ -3111,21 +3137,7 @@ we force server id to 2, but this MySQL server will not act as a slave.");
CloseHandle(hEventShutdown);
}
#endif
#ifndef __NETWARE__
{
uint i;
/*
Wait up to 10 seconds for signal thread to die. We use this mainly to
avoid getting warnings that my_thread_end has not been called
*/
for (i= 0 ; i < 100 && signal_thread_in_use; i++)
{
if (pthread_kill(signal_thread, MYSQL_KILL_SIGNAL))
break;
my_sleep(100); // Give it time to die
}
}
#endif
wait_for_signal_thread_to_end();
clean_up_mutexes();
my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
......
......@@ -688,7 +688,8 @@ class delayed_insert :public ilink {
thd.current_tablenr=0;
thd.version=refresh_version;
thd.command=COM_DELAYED_INSERT;
thd.lex->current_select= 0; /* for my_message_sql */
thd.lex->current_select= 0; // for my_message_sql
thd.lex->sql_command= SQLCOM_INSERT; // For innodb::store_lock()
bzero((char*) &thd.net, sizeof(thd.net)); // Safety
bzero((char*) &table_list, sizeof(table_list)); // Safety
......
......@@ -125,27 +125,46 @@ enum tablespace_op_type
/*
The state of the lex parsing for selects
master and slaves are pointers to select_lex.
master is pointer to upper level node.
slave is pointer to lower level node
select_lex is a SELECT without union
unit is container of either
- One SELECT
- UNION of selects
select_lex and unit are both inherited form select_lex_node
neighbors are two select_lex or units on the same level
All select describing structures linked with following pointers:
- list of neighbors (next/prev) (prev of first element point to slave
- list of neighbors (next/prev) (prev of first element point to slave
pointer of upper structure)
- one level units for unit (union) structure
- member of one union(unit) for ordinary select_lex
- pointer to master
- outer select_lex for unit (union)
- unit structure for ordinary select_lex
- pointer to slave
- first list element of select_lex belonged to this unit for unit
- first unit in list of units that belong to this select_lex (as
subselects or derived tables) for ordinary select_lex
- list of all select_lex (for group operation like correcting list of opened
tables)
- if unit contain several selects (union) then it have special
select_lex called fake_select_lex. It used for storing global parameters
and executing union. subqueries of global ORDER BY clause will be
attached to this fake_select_lex, which will allow them correctly
resolve fields of 'upper' union and other more outer selects.
for example for following query:
- For select this is a list of UNION's (or one element list)
- For units this is a list of sub queries for the upper level select
- pointer to master (master), which is
If this is a unit
- pointer to outer select_lex
If this is a select_lex
- pointer to outer unit structure for select
- pointer to slave (slave), which is either:
If this is a unit:
- first SELECT that belong to this unit
If this is a select_lex
- first unit that belong to this SELECT (subquries or derived tables)
- list of all select_lex (link_next/link_prev)
This is to be used for things like derived tables creation, where we
go through this list and create the derived tables.
If unit contain several selects (UNION now, INTERSECT etc later)
then it have special select_lex called fake_select_lex. It used for
storing global parameters (like ORDER BY, LIMIT) and executing union.
Subqueries used in global ORDER BY clause will be attached to this
fake_select_lex, which will allow them correctly resolve fields of
'upper' UNION and outer selects.
For example for following query:
select *
from table1
......@@ -163,6 +182,11 @@ enum tablespace_op_type
we will have following structure:
select1: (select * from table1 ...)
select2: (select * from table2 ...)
select3: (select * from table3)
select1.1.1: (select * from table1_1_1)
...
main unit
fake0
......@@ -185,7 +209,12 @@ enum tablespace_op_type
relation in main unit will be following:
(bigger picture for:
main unit
fake0
select1 select2 select3
in the above picture)
main unit
|^^^^|fake_select_lex
|||||+--------------------------------------------+
......@@ -382,7 +411,7 @@ class st_select_lex_unit: public st_select_lex_node {
typedef class st_select_lex_unit SELECT_LEX_UNIT;
/*
SELECT_LEX - store information of parsed SELECT_LEX statment
SELECT_LEX - store information of parsed SELECT statment
*/
class st_select_lex: public st_select_lex_node
{
......
......@@ -246,7 +246,7 @@ bool log_in_use(const char* log_name)
if ((linfo = tmp->current_linfo))
{
pthread_mutex_lock(&linfo->lock);
result = !memcmp(log_name, linfo->log_file_name, log_name_len);
result = !bcmp(log_name, linfo->log_file_name, log_name_len);
pthread_mutex_unlock(&linfo->lock);
if (result)
break;
......
......@@ -7622,8 +7622,8 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
{
byte *key_buffer, *key_pos, *record=table->record[0];
int error;
handler *file=table->file;
ulong extra_length=ALIGN_SIZE(key_length)-key_length;
handler *file= table->file;
ulong extra_length= ALIGN_SIZE(key_length)-key_length;
uint *field_lengths,*field_length;
HASH hash;
DBUG_ENTER("remove_dup_with_hash_index");
......@@ -7637,22 +7637,34 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
NullS))
DBUG_RETURN(1);
{
Field **ptr;
ulong total_length= 0;
for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++)
{
uint length= (*ptr)->pack_length();
(*field_length++)= length;
total_length+= length;
}
DBUG_PRINT("info",("field_count: %u key_length: %lu total_length: %lu",
field_count, key_length, total_length));
DBUG_ASSERT(total_length <= key_length);
key_length= total_length;
extra_length= ALIGN_SIZE(key_length)-key_length;
}
if (hash_init(&hash, &my_charset_bin, (uint) file->records, 0,
key_length,(hash_get_key) 0, 0, 0))
key_length, (hash_get_key) 0, 0, 0))
{
my_free((char*) key_buffer,MYF(0));
DBUG_RETURN(1);
}
{
Field **ptr;
for (ptr= first_field, field_length=field_lengths ; *ptr ; ptr++)
(*field_length++)= (*ptr)->pack_length();
}
file->ha_rnd_init(1);
key_pos=key_buffer;
for (;;)
{
byte *org_key_pos;
if (thd->killed)
{
my_error(ER_SERVER_SHUTDOWN,MYF(0));
......@@ -7675,6 +7687,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
}
/* copy fields to key buffer */
org_key_pos= key_pos;
field_length=field_lengths;
for (Field **ptr= first_field ; *ptr ; ptr++)
{
......@@ -7682,14 +7695,14 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
key_pos+= *field_length++;
}
/* Check if it exists before */
if (hash_search(&hash,key_pos-key_length,key_length))
if (hash_search(&hash, org_key_pos, key_length))
{
/* Duplicated found ; Remove the row */
if ((error=file->delete_row(record)))
goto err;
}
else
(void) my_hash_insert(&hash, key_pos-key_length);
(void) my_hash_insert(&hash, org_key_pos);
key_pos+=extra_length;
}
my_free((char*) key_buffer,MYF(0));
......
......@@ -518,7 +518,6 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)),
register unsigned int cutlim;
register ulonglong i;
register const char *s, *e;
register unsigned char c;
const char *save;
int overflow;
......@@ -581,8 +580,9 @@ longlong my_strntoll_8bit(CHARSET_INFO *cs __attribute__((unused)),
overflow = 0;
i = 0;
for (c = *s; s != e; c = *++s)
for ( ; s != e; s++)
{
register unsigned char c= *s;
if (c>='0' && c<='9')
c -= '0';
else if (c>='A' && c<='Z')
......@@ -641,7 +641,6 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs,
register unsigned int cutlim;
register ulonglong i;
register const char *s, *e;
register unsigned char c;
const char *save;
int overflow;
......@@ -704,8 +703,10 @@ ulonglong my_strntoull_8bit(CHARSET_INFO *cs,
overflow = 0;
i = 0;
for (c = *s; s != e; c = *++s)
for ( ; s != e; s++)
{
register unsigned char c= *s;
if (c>='0' && c<='9')
c -= '0';
else if (c>='A' && c<='Z')
......
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