summaryrefslogtreecommitdiffstats
path: root/lib/lz4frame.c
diff options
context:
space:
mode:
authorYann Collet <cyan@fb.com>2020-08-13 00:27:33 (GMT)
committerYann Collet <cyan@fb.com>2020-08-13 00:27:33 (GMT)
commite9cfa49d0ddde238a7f3dbe6320f11e3d1fe58ea (patch)
treee1cf16ba087098aa80cc16572b6fc59e7e4b5065 /lib/lz4frame.c
parentf328e329b3cec38ec8316d454279b79d19c36fdd (diff)
downloadlz4-e9cfa49d0ddde238a7f3dbe6320f11e3d1fe58ea.zip
lz4-e9cfa49d0ddde238a7f3dbe6320f11e3d1fe58ea.tar.gz
lz4-e9cfa49d0ddde238a7f3dbe6320f11e3d1fe58ea.tar.bz2
Clarifies and fix EndMark
EndMark, the 4-bytes value indicating the end of frame, must be `0x00000000`. Previously, it was just mentioned as a `0-size` block. But such definition could encompass uncompressed blocks of size 0, with a header of value `0x80000000`. But the intention was to also support uncompressed empty blocks. They could be used as a keep-alive signal. Note that compressed empty blocks are already supported, it's just that they have a size 1 instead of 0 (for the `0` token). Unfortunately, the decoder implementation was also wrong, and would also interpret a `0x80000000` block header as an endMark. This issue evaded detection so far simply because this situation never happens, as LZ4Frame always issues a clean 0x00000000 value as a endMark. It also does not flush empty blocks. This is fixed in this PR. The decoder can now deal with empty uncompressed blocks, and do not confuse them with EndMark. The specification is also clarified. Finally, FrameTest is updated to randomly insert empty blocks during fuzzing.
Diffstat (limited to 'lib/lz4frame.c')
-rw-r--r--lib/lz4frame.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/lib/lz4frame.c b/lib/lz4frame.c
index 5d716ea..e11f1c8 100644
--- a/lib/lz4frame.c
+++ b/lib/lz4frame.c
@@ -1483,14 +1483,16 @@ size_t LZ4F_decompress(LZ4F_dctx* dctx,
} /* if (dctx->dStage == dstage_storeBlockHeader) */
/* decode block header */
- { size_t const nextCBlockSize = LZ4F_readLE32(selectedIn) & 0x7FFFFFFFU;
+ { U32 const blockHeader = LZ4F_readLE32(selectedIn);
+ size_t const nextCBlockSize = blockHeader & 0x7FFFFFFFU;
size_t const crcSize = dctx->frameInfo.blockChecksumFlag * BFSize;
- if (nextCBlockSize==0) { /* frameEnd signal, no more block */
+ if (blockHeader==0) { /* frameEnd signal, no more block */
dctx->dStage = dstage_getSuffix;
break;
}
- if (nextCBlockSize > dctx->maxBlockSize)
+ if (nextCBlockSize > dctx->maxBlockSize) {
return err0r(LZ4F_ERROR_maxBlockSize_invalid);
+ }
if (LZ4F_readLE32(selectedIn) & LZ4F_BLOCKUNCOMPRESSED_FLAG) {
/* next block is uncompressed */
dctx->tmpInTarget = nextCBlockSize;