Skip to content

Commit

Permalink
MDEV-15763 - VARCHAR(1) COMPRESSED crashes the server
Browse files Browse the repository at this point in the history
Storing 1 byte long string in VARCHAR() COMPRESSED column may trigger
integer overflow when calculating available space for zlib output.
  • Loading branch information
Sergey Vojtovich committed Apr 20, 2018
1 parent 3dec6c4 commit 38c799c
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 1 deletion.
8 changes: 8 additions & 0 deletions mysql-test/main/column_compression.result
Original file line number Diff line number Diff line change
Expand Up @@ -1386,3 +1386,11 @@ SELECT LENGTH(a) FROM t1;
LENGTH(a)
0
DROP TABLE t1;
#
# MDEV-15763 - VARCHAR(1) COMPRESSED crashes the server
#
CREATE TABLE t1(a VARCHAR(1) COMPRESSED);
SET column_compression_threshold=0;
INSERT INTO t1 VALUES('a');
SET column_compression_threshold=DEFAULT;
DROP TABLE t1;
10 changes: 10 additions & 0 deletions mysql-test/main/column_compression.test
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,13 @@ INSERT INTO t1 VALUES('a');
INSERT INTO t1 VALUES(' ');
SELECT LENGTH(a) FROM t1;
DROP TABLE t1;


--echo #
--echo # MDEV-15763 - VARCHAR(1) COMPRESSED crashes the server
--echo #
CREATE TABLE t1(a VARCHAR(1) COMPRESSED);
SET column_compression_threshold=0;
INSERT INTO t1 VALUES('a');
SET column_compression_threshold=DEFAULT;
DROP TABLE t1;
22 changes: 21 additions & 1 deletion sql/field_comp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,30 @@
#include <zlib.h>


/**
Compresses string using zlib
@param[out] to destination buffer for compressed data
@param[in] from data to compress
@param[in] length from length
Requirement is such that string stored at `to' must not exceed `from' length.
Otherwise 0 is returned and caller stores string uncompressed.
`to' must be large enough to hold `length' bytes.
length == 1 is an edge case that may break stream.avail_out calculation: at
least 2 bytes required to store metadata.
*/

static uint compress_zlib(THD *thd, char *to, const char *from, uint length)
{
uint level= thd->variables.column_compression_zlib_level;

if (level > 0)
/* Caller takes care of empty strings. */
DBUG_ASSERT(length);

if (level > 0 && length > 1)
{
z_stream stream;
int wbits= thd->variables.column_compression_zlib_wrap ? MAX_WBITS :
Expand All @@ -40,6 +59,7 @@ static uint compress_zlib(THD *thd, char *to, const char *from, uint length)
stream.avail_in= length;
stream.next_in= (Bytef*) from;

DBUG_ASSERT(length >= original_pack_length + 1);
stream.avail_out= length - original_pack_length - 1;
stream.next_out= (Bytef*) to + original_pack_length + 1;

Expand Down

0 comments on commit 38c799c

Please sign in to comment.