summaryrefslogtreecommitdiff
path: root/myisam
diff options
context:
space:
mode:
authorunknown <ingo@mysql.com>2005-04-28 15:27:42 +0200
committerunknown <ingo@mysql.com>2005-04-28 15:27:42 +0200
commit994674c09b112745fd03355a0972fbf3f4b0295c (patch)
treeacdc21ec81893c0fcc23262fdc1e7e2bf2592e0c /myisam
parentf63c8f53b050016c6be6a152ea01b4e17e9ee071 (diff)
downloadmariadb-git-994674c09b112745fd03355a0972fbf3f4b0295c.tar.gz
Bug#8321 - myisampack bug in compression algorithm
This is the second of three changesets. It contains the pure bug fix. It also contains the second after-review fixes. The problem was that with gcc on x86, shifts are done modulo word size. 'value' is 32 bits wide and shifting it by 32 bits is a no-op. This was triggered by an evil distribution of character incidences. A distribution of 2917027827 characters made of 202 distinct values led to 34 occurrences of 32-bit Huffman codes. This might have been the first time ever that write_bits() had to write 32-bit values. Since it can be expected that one day even 32 bits might be insufficient, the third changeset suggests to enlarge some variables to 64 bits.
Diffstat (limited to 'myisam')
-rw-r--r--myisam/myisampack.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/myisam/myisampack.c b/myisam/myisampack.c
index 9f4e3bde65a..90689b08476 100644
--- a/myisam/myisampack.c
+++ b/myisam/myisampack.c
@@ -31,6 +31,7 @@
#define __GNU_LIBRARY__ /* Skip warnings in getopt.h */
#endif
#include <my_getopt.h>
+#include <assert.h>
#if INT_MAX > 32767
#define BITS_SAVED 32
@@ -1975,7 +1976,9 @@ static void write_bits (register ulong value, register uint bits)
{
reg3 uint byte_buff;
bits= (uint) -file_buffer.bits;
- byte_buff=file_buffer.byte | (uint) (value >> bits);
+ DBUG_ASSERT(bits <= 8 * sizeof(value));
+ byte_buff= (file_buffer.byte |
+ ((bits != 8 * sizeof(value)) ? (uint) (value >> bits) : 0));
#if BITS_SAVED == 32
*file_buffer.pos++= (byte) (byte_buff >> 24) ;
*file_buffer.pos++= (byte) (byte_buff >> 16) ;
@@ -1983,7 +1986,9 @@ static void write_bits (register ulong value, register uint bits)
*file_buffer.pos++= (byte) (byte_buff >> 8) ;
*file_buffer.pos++= (byte) byte_buff;
- value&=(1 << bits)-1;
+ DBUG_ASSERT(bits <= 8 * sizeof(ulong));
+ if (bits != 8 * sizeof(value))
+ value&= (((ulong) 1) << bits) - 1;
#if BITS_SAVED == 16
if (bits >= sizeof(uint))
{