Bug in QuickLZ 1.30
qlz_compress() and qlz_decompress() of version 1.30 when not in streaming mode (streaming_mode flag not defined). All compression levels.
The bug does not apply to the demo project quick.exe.
The bug does not apply to any earlier versions.
qlz_compress() may generate errorneous compressed data and qlz_decompress() may decompress valid compressed data errorneously.
When qlz_compress() is called a local pointer size_t *b is set to point near the beginning of the user given scratch buffer (the exact position depends on alignment). The error occurs if the scratch buffer happens to be initialized with data such that
*b + size == 0
which can happen if the addition wraps over to become exactly 0. The size variable is the user given input size.
The same problem applies to qlz_decompress() and its scratch buffer.
Probability of occurence
If the first 16 bytes of the scratch buffers are initially zeroed out, the error cannot occur. They do not need to be zeroed out prior to successive calls. Otherwise following applies:
An upper limit of the risk of occurence is that one out of 232 = 4,294,967,296 calls to qlz_compress() or qlz_decompress() fail for 32-bit code and one out of 264 = 18,446,744,073,709,551,616 for 64-bit code. The risk is thus based on the number of calls and not the amount of data treated.
The bug has been discovered by code inspection and not by occurence/realization in any customer's software. In practise the risk may be reduced by the range and variation of the size argument and by the frequency at which the caller is allocating scratch buffers (most common is once per program initialization) which provides new values of *b.
Source code details
The bug is contained in line 857 of quicklz.c which is inside qlz_compress():
if (*buffersize + size > STREAMING_MODE_ROUNDED)
and line 930 which is inside qlz_decompress():if (*buffersize + qlz_size_decompressed((char *)source) > STREAMING_MODE_ROUNDED)
When not in streaming mode, STREAMING_MODE_ROUNDED is set to 0 and the if-condition was intended to be always true.
To fix the bug the lines must be edited into
if (*buffersize + size - 1 >= STREAMING_MODE_ROUNDED)
if (*buffersize + qlz_size_decompressed((char *)source) - 1 >= STREAMING_MODE_ROUNDED)
The bug has been fixed like described above in version 1.31, both in quicklz.c and the pre-compiled .dll files.