summaryrefslogtreecommitdiff
path: root/mysys/hash.c
diff options
context:
space:
mode:
authorunknown <svoj@mysql.com/june.mysql.com>2007-07-05 11:45:14 +0500
committerunknown <svoj@mysql.com/june.mysql.com>2007-07-05 11:45:14 +0500
commitb7bf9725852640bf843a5bd5fc83d6a0556406de (patch)
tree5b26f141a181f4412db77a6f322eb129bd8f2a06 /mysys/hash.c
parentbe684dc0ee86be11af02f918bd9063baa637a753 (diff)
downloadmariadb-git-b7bf9725852640bf843a5bd5fc83d6a0556406de.tar.gz
BUG#27564 - Valgrind: UDF does not cleanup correctly
Dropping an user defined function may cause server crash in case this function is still in use by another thread. The problem was that our hash implementation didn't update hash link list properly when hash_update() was called. mysys/hash.c: The following requirement wasn't met by hash_update() function causing corruption of hash links list: After a record was unlinked from the old chain during update, it holds random position. By the chance this position is equal to position for the first element in the new chain. That means updated record is the only record in the new chain.
Diffstat (limited to 'mysys/hash.c')
-rw-r--r--mysys/hash.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/mysys/hash.c b/mysys/hash.c
index 75135a470c9..1ba80dc6fd3 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -572,6 +572,25 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length)
previous->next=pos->next; /* unlink pos */
/* Move data to correct position */
+ if (new_index == empty)
+ {
+ /*
+ At this point record is unlinked from the old chain, thus it holds
+ random position. By the chance this position is equal to position
+ for the first element in the new chain. That means updated record
+ is the only record in the new chain.
+ */
+ if (empty != idx)
+ {
+ /*
+ Record was moved while unlinking it from the old chain.
+ Copy data to a new position.
+ */
+ data[empty]= org_link;
+ }
+ data[empty].next= NO_RECORD;
+ DBUG_RETURN(0);
+ }
pos=data+new_index;
new_pos_index=hash_rec_mask(hash,pos,blength,records);
if (new_index != new_pos_index)