Commit 994674c0 authored by unknown's avatar unknown

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.

parent f63c8f53
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#define __GNU_LIBRARY__ /* Skip warnings in getopt.h */ #define __GNU_LIBRARY__ /* Skip warnings in getopt.h */
#endif #endif
#include <my_getopt.h> #include <my_getopt.h>
#include <assert.h>
#if INT_MAX > 32767 #if INT_MAX > 32767
#define BITS_SAVED 32 #define BITS_SAVED 32
...@@ -1975,7 +1976,9 @@ static void write_bits (register ulong value, register uint bits) ...@@ -1975,7 +1976,9 @@ static void write_bits (register ulong value, register uint bits)
{ {
reg3 uint byte_buff; reg3 uint byte_buff;
bits= (uint) -file_buffer.bits; 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 #if BITS_SAVED == 32
*file_buffer.pos++= (byte) (byte_buff >> 24) ; *file_buffer.pos++= (byte) (byte_buff >> 24) ;
*file_buffer.pos++= (byte) (byte_buff >> 16) ; *file_buffer.pos++= (byte) (byte_buff >> 16) ;
...@@ -1983,7 +1986,9 @@ static void write_bits (register ulong value, register uint bits) ...@@ -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 >> 8) ;
*file_buffer.pos++= (byte) byte_buff; *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_SAVED == 16
if (bits >= sizeof(uint)) if (bits >= sizeof(uint))
{ {
......
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