-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Closed
Description
In C adding an offset to a null pointer has undefined behavior (in C++ that would be valid only if the offset was 0).
zstd may perform such operations (with both zero and non-zero offsets), which breaks execution under UBSan.
Here are places that I could find by running some of our tests under UBSan (in 1.4.4):
diff --git a/google3/third_party/zstdlib/compress/zstd_compress.c b/google3/third_party/zstdlib/compress/zstd_compress.c
--- a/google3/third_party/zstdlib/compress/zstd_compress.c
+++ b/google3/third_party/zstdlib/compress/zstd_compress.c
@@ -1321,6 +1321,7 @@ ZSTD_reset_matchState(ZSTD_matchState_t*
DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset);
if (forceResetIndex == ZSTDirp_reset) {
memset(&ms->window, 0, sizeof(ms->window));
+ ms->window.base = "";
ms->window.dictLimit = 1; /* start from 1, so that 1st position is valid */
ms->window.lowLimit = 1; /* it ensures first and later CCtx usages compress the same */
ms->window.nextSrc = ms->window.base + 1; /* see issue #1241 */
@@ -3655,11 +3656,11 @@ static size_t ZSTD_compressStream_generi
ZSTD_EndDirective const flushMode)
{
const char* const istart = (const char*)input->src;
- const char* const iend = istart + input->size;
- const char* ip = istart + input->pos;
+ const char* const iend = input->size ? istart + input->size : istart;
+ const char* ip = input->pos ? istart + input->pos : istart;
char* const ostart = (char*)output->dst;
- char* const oend = ostart + output->size;
- char* op = ostart + output->pos;
+ char* const oend = output->size ? ostart + output->size : ostart;
+ char* op = output->pos ? ostart + output->pos : ostart;
U32 someMoreWork = 1;
/* check expectations */
@@ -3698,7 +3699,7 @@ static size_t ZSTD_compressStream_generi
zcs->inBuff + zcs->inBuffPos, toLoad,
ip, iend-ip);
zcs->inBuffPos += loaded;
- ip += loaded;
+ if (loaded) ip += loaded;
if ( (flushMode == ZSTD_e_continue)
&& (zcs->inBuffPos < zcs->inBuffTarget) ) {
/* not enough input to fill full block : stop here */
@@ -3758,7 +3759,7 @@ static size_t ZSTD_compressStream_generi
zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u",
(unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed);
- op += flushed;
+ if (flushed) op += flushed;
zcs->outBuffFlushedSize += flushed;
if (toFlush!=flushed) {
/* flush not fully completed, presumably because dst is too small */
diff --git a/google3/third_party/zstdlib/compress/zstd_double_fast.c b/google3/third_party/zstdlib/compress/zstd_double_fast.c
--- a/google3/third_party/zstdlib/compress/zstd_double_fast.c
+++ b/google3/third_party/zstdlib/compress/zstd_double_fast.c
@@ -96,7 +96,7 @@ size_t ZSTD_compressBlock_doubleFast_gen
dictCParams->hashLog : hBitsL;
const U32 dictHBitsS = dictMode == ZSTD_dictMatchState ?
dictCParams->chainLog : hBitsS;
- const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictStart);
+ const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictStart));
DEBUGLOG(5, "ZSTD_compressBlock_doubleFast_generic");
diff --git a/google3/third_party/zstdlib/compress/zstd_lazy.c b/google3/third_party/zstdlib/compress/zstd_lazy.c
--- a/google3/third_party/zstdlib/compress/zstd_lazy.c
+++ b/google3/third_party/zstdlib/compress/zstd_lazy.c
@@ -660,7 +660,7 @@ ZSTD_compressBlock_lazy_generic(
const U32 dictIndexDelta = dictMode == ZSTD_dictMatchState ?
prefixLowestIndex - (U32)(dictEnd - dictBase) :
0;
- const U32 dictAndPrefixLength = (U32)(ip - prefixLowest + dictEnd - dictLowest);
+ const U32 dictAndPrefixLength = (U32)((ip - prefixLowest) + (dictEnd - dictLowest));
/* init */
ip += (dictAndPrefixLength == 0);
Could you fix that please?
Cyan4973
Metadata
Metadata
Assignees
Labels
No labels