fix #926
authorYann Collet <cyan@fb.com>
Sun, 8 Nov 2020 02:12:26 +0000 (18:12 -0800)
committerYann Collet <cyan@fb.com>
Sun, 8 Nov 2020 02:12:26 +0000 (18:12 -0800)
fix incorrect behavior of LZ4_saveDictHC()
when invoked right after initialization.

lib/lz4hc.c
tests/fuzzer.c

index ef7ded34a19823fd33e7e95aa6bc9b0d874136c4..a74144a9ab24f337957b1cdfc7064b8dec6f43fa 100644 (file)
@@ -1003,18 +1003,16 @@ int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)
 LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)
 {
     LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;
+    LZ4HC_CCtx_internal* const hcstate = &(LZ4_streamHCPtr->internal_donotuse);
+    /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */
+    LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= LZ4_STREAMHCSIZE);
+    DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", buffer, (unsigned)size);
+    /* check conditions */
     if (buffer == NULL) return NULL;
     if (size < sizeof(LZ4_streamHC_t)) return NULL;
     if (!LZ4_isAligned(buffer, LZ4_streamHC_t_alignment())) return NULL;
-    /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */
-    LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= LZ4_STREAMHCSIZE);
-    DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", LZ4_streamHCPtr, (unsigned)size);
-    /* end-base will trigger a clearTable on starting compression */
-    LZ4_streamHCPtr->internal_donotuse.end = (const BYTE *)(ptrdiff_t)-1;
-    LZ4_streamHCPtr->internal_donotuse.base = NULL;
-    LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL;
-    LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = 0;
-    LZ4_streamHCPtr->internal_donotuse.dirty = 0;
+    /* init */
+    MEM_INIT(hcstate, 0, sizeof(*hcstate));
     LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT);
     return LZ4_streamHCPtr;
 }
@@ -1100,10 +1098,11 @@ static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBl
     ctxPtr->dictCtx = NULL;
 }
 
-static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
-                                            const char* src, char* dst,
-                                            int* srcSizePtr, int dstCapacity,
-                                            limitedOutput_directive limit)
+static int
+LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
+                                 const char* src, char* dst,
+                                 int* srcSizePtr, int dstCapacity,
+                                 limitedOutput_directive limit)
 {
     LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
     DEBUGLOG(5, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",
@@ -1131,8 +1130,7 @@ static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
             if (sourceEnd > dictEnd) sourceEnd = dictEnd;
             ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase);
             if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit;
-        }
-    }
+    }   }
 
     return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);
 }
@@ -1152,13 +1150,17 @@ int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const ch
 
 
 
-/* dictionary saving */
-
+/* LZ4_saveDictHC :
+ * save history content
+ * into a user-provided buffer
+ * which is then used to continue compression
+ */
 int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
 {
     LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
     int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit));
-    DEBUGLOG(4, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);
+    DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);
+    assert(prefixSize >= 0);
     if (dictSize > 64 KB) dictSize = 64 KB;
     if (dictSize < 4) dictSize = 0;
     if (dictSize > prefixSize) dictSize = prefixSize;
index 29c6a8a0f49a579b3646f3841e117510ad7da86a..a411dd49446b9e731a0df280731a6a33390eb011 100644 (file)
@@ -1135,13 +1135,13 @@ static void FUZ_unitTests(int compressionLevel)
         shct* const shc = (shct*)malloc(sizeof(*shc));
         assert(shc != NULL);
         memset(shc, 0, sizeof(*shc));
-        DISPLAYLEVEL(3, "state1(%p) state2(%p) state3(%p) size(0x%x): ",
+        DISPLAYLEVEL(3, "state1(%p) state2(%p) state3(%p) LZ4_stream_t size(0x%x): ",
                     &(shc->state1), &(shc->state2), &(shc->state3), (unsigned)sizeof(LZ4_stream_t));
         FUZ_CHECKTEST( LZ4_initStream(&(shc->state1), sizeof(shc->state1)) == NULL, "state1 (%p) failed init", &(shc->state1) );
         FUZ_CHECKTEST( LZ4_initStream(&(shc->state2), sizeof(shc->state2)) == NULL, "state2 (%p) failed init", &(shc->state2)  );
         FUZ_CHECKTEST( LZ4_initStream(&(shc->state3), sizeof(shc->state3)) == NULL, "state3 (%p) failed init", &(shc->state3)  );
         FUZ_CHECKTEST( LZ4_initStream((char*)&(shc->state1) + 1, sizeof(shc->state1)) != NULL,
-                        "hc1+1 (%p) init must fail, due to bad alignment", (char*)&(shc->state1) + 1 );
+                       "hc1+1 (%p) init must fail, due to bad alignment", (char*)&(shc->state1) + 1 );
         free(shc);
     }
     DISPLAYLEVEL(3, "all inits OK \n");
@@ -1268,6 +1268,22 @@ static void FUZ_unitTests(int compressionLevel)
         }   }
         DISPLAYLEVEL(3, "OK \n");
 
+        /* saveDictHC test #926 */
+        DISPLAYLEVEL(3, "saveDictHC test #926 : ");
+        {   LZ4_streamHC_t* const ctx = LZ4_initStreamHC(&sHC, sizeof(sHC));
+            assert(ctx != NULL);  /* ensure init is successful */
+
+            /* Check access violation with asan */
+            FUZ_CHECKTEST( LZ4_saveDictHC(&sHC, NULL, 0) != 0,
+            "LZ4_saveDictHC() can't save anything into (NULL,0)");
+
+            /* Check access violation with asan */
+            {   char tmp_buffer[240] = { 0 };
+                FUZ_CHECKTEST( LZ4_saveDictHC(&sHC, tmp_buffer, sizeof(tmp_buffer)) != 0,
+                "LZ4_saveDictHC() can't save anything since compression hasn't started");
+        }   }
+
+
         /* long sequence test */
         DISPLAYLEVEL(3, "Long sequence HC_destSize test : ");
         {   size_t const blockSize = 1 MB;