Fix buffer sizing for LZ4.

Fix exit condition checks in LZ4 decompression wrapper.
This commit is contained in:
Moinak Ghosh 2012-08-04 17:55:20 +05:30
parent f9215b53fb
commit 2cbcb0c9e4
3 changed files with 50 additions and 10 deletions

View file

@ -32,6 +32,8 @@
#include <lz4hc.h> #include <lz4hc.h>
#include <allocator.h> #include <allocator.h>
#define LZ4_MAX_CHUNK 2147450621L
struct lz4_params { struct lz4_params {
int level; int level;
}; };
@ -41,14 +43,23 @@ lz4_stats(int show)
{ {
} }
int
lz4_buf_extra(ssize_t buflen)
{
if (buflen > LZ4_MAX_CHUNK)
buflen = LZ4_MAX_CHUNK;
return (LZ4_compressBound(buflen) - buflen + sizeof(int));
}
int int
lz4_init(void **data, int *level, ssize_t chunksize) lz4_init(void **data, int *level, ssize_t chunksize)
{ {
struct lz4_params *lzdat; struct lz4_params *lzdat;
int lev; int lev;
if (chunksize > INT_MAX) { if (chunksize > LZ4_MAX_CHUNK) {
fprintf(stderr, "Chunk size too big for LZ4.\n"); fprintf(stderr, "Max allowed chunk size for LZ4 is: %d \n",
LZ4_MAX_CHUNK);
return (1); return (1);
} }
lzdat = slab_alloc(NULL, sizeof (struct lz4_params)); lzdat = slab_alloc(NULL, sizeof (struct lz4_params));
@ -85,12 +96,13 @@ lz4_compress(void *src, size_t srclen, void *dst, size_t *dstlen,
if (lzdat->level == 1) { if (lzdat->level == 1) {
rv = LZ4_compress(src, dst, _srclen); rv = LZ4_compress(src, dst, _srclen);
} else if (lzdat->level == 2) { } else if (lzdat->level == 2) {
rv = LZ4_compress(src, dst, _srclen); rv = LZ4_compress(src, dst, _srclen);
if (rv == 0) { if (rv == 0 || rv > *dstlen) {
return (-1); return (-1);
} }
dst2 = slab_alloc(NULL, rv + sizeof (int)); dst2 = slab_alloc(NULL, rv + sizeof (int) + LZ4_compressBound(rv));
*((int *)dst2) = htonl(rv); *((int *)dst2) = htonl(rv);
rv = LZ4_compressHC(dst, dst2 + sizeof (int), rv); rv = LZ4_compressHC(dst, dst2 + sizeof (int), rv);
if (rv != 0) { if (rv != 0) {
@ -120,20 +132,23 @@ lz4_decompress(void *src, size_t srclen, void *dst, size_t *dstlen,
if (lzdat->level == 1 || lzdat->level == 3) { if (lzdat->level == 1 || lzdat->level == 3) {
rv = LZ4_uncompress(src, dst, _dstlen); rv = LZ4_uncompress(src, dst, _dstlen);
if (rv != srclen) {
return (-1);
}
} else if (lzdat->level == 2) { } else if (lzdat->level == 2) {
int sz1; int sz1;
sz1 = ntohl(*((int *)src)); sz1 = ntohl(*((int *)src));
rv = LZ4_uncompress(src + sizeof (int), dst, sz1); rv = LZ4_uncompress(src + sizeof (int), dst, sz1);
if (rv != sz1) { if (rv != srclen - sizeof (int)) {
return (-1); return (-1);
} }
memcpy(src, dst, sz1); memcpy(src, dst, sz1);
rv = LZ4_uncompress(src, dst, _dstlen); rv = LZ4_uncompress(src, dst, _dstlen);
} if (rv != sz1) {
if (rv != srclen) {
return (-1); return (-1);
} }
}
return (0); return (0);
} }

28
main.c
View file

@ -398,8 +398,20 @@ start_decompress(const char *filename, const char *to_filename)
goto uncomp_done; goto uncomp_done;
} }
compressed_chunksize = chunksize + (chunksize >> 6) + sizeof (uint64_t) compressed_chunksize = chunksize + sizeof (chunksize) +
+ sizeof (chunksize); sizeof (uint64_t) + sizeof (chunksize) + zlib_buf_extra(chunksize);
/*
* Adjust for LZ4 overflow size if LZ4 was selected.
* TODO: A more generic way to handle this for various algos. I'm too
* lazy to do this at present.
*/
if (strncmp(algo, "lz4", 3) == 0) {
if (chunksize + lz4_buf_extra(chunksize) > compressed_chunksize) {
compressed_chunksize += (chunksize + lz4_buf_extra(chunksize) -
compressed_chunksize);
}
}
if (flags & FLAG_DEDUP) { if (flags & FLAG_DEDUP) {
enable_rabin_scan = 1; enable_rabin_scan = 1;
@ -804,6 +816,18 @@ start_compress(const char *filename, uint64_t chunksize, int level)
compressed_chunksize = chunksize + sizeof (chunksize) + compressed_chunksize = chunksize + sizeof (chunksize) +
sizeof (uint64_t) + sizeof (chunksize) + zlib_buf_extra(chunksize); sizeof (uint64_t) + sizeof (chunksize) + zlib_buf_extra(chunksize);
/*
* Adjust for LZ4 overflow size if LZ4 was selected.
* TODO: A more generic way to handle this for various algos. I'm too
* lazy to do this at present.
*/
if (strncmp(algo, "lz4", 3) == 0) {
if (chunksize + lz4_buf_extra(chunksize) > compressed_chunksize) {
compressed_chunksize += (chunksize + lz4_buf_extra(chunksize) -
compressed_chunksize);
}
}
flags = 0; flags = 0;
if (enable_rabin_scan) { if (enable_rabin_scan) {
flags |= FLAG_DEDUP; flags |= FLAG_DEDUP;

View file

@ -56,6 +56,7 @@ extern uint64_t lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc);
extern uint64_t lzma_crc64_8bchk(const uint8_t *buf, size_t size, extern uint64_t lzma_crc64_8bchk(const uint8_t *buf, size_t size,
uint64_t crc, uint64_t *cnt); uint64_t crc, uint64_t *cnt);
extern uint32_t zlib_buf_extra(ssize_t buflen); extern uint32_t zlib_buf_extra(ssize_t buflen);
extern int lz4_buf_extra(ssize_t buflen);
extern int zlib_compress(void *src, size_t srclen, void *dst, extern int zlib_compress(void *src, size_t srclen, void *dst,
size_t *destlen, int level, uchar_t chdr, void *data); size_t *destlen, int level, uchar_t chdr, void *data);