LZ4 HC : extended detection window. Thanks to Adrien Grand.
authoryann.collet.73@gmail.com <yann.collet.73@gmail.com@650e7d94-2a16-8b24-b05c-7c0b3f6821cd>
Fri, 30 Nov 2012 13:23:36 +0000 (13:23 +0000)
committeryann.collet.73@gmail.com <yann.collet.73@gmail.com@650e7d94-2a16-8b24-b05c-7c0b3f6821cd>
Fri, 30 Nov 2012 13:23:36 +0000 (13:23 +0000)
Fuzzer : more tests cases
lz4demo : detect write errors. Thanks to Dima Tisnek
bench.c : compatibility with Solaris 64. Thanks to Thorbjørn Willoch
LZ4_compressBound() : now both in inline function and macro format. Thanks to Jacob Gorm Hansen

git-svn-id: https://lz4.googlecode.com/svn/trunk@84 650e7d94-2a16-8b24-b05c-7c0b3f6821cd

bench.c
fuzzer.c
lz4.c
lz4.h
lz4demo.c
lz4hc.c

diff --git a/bench.c b/bench.c
index b0a0ecb..015c36e 100644 (file)
--- a/bench.c
+++ b/bench.c
@@ -33,7 +33,7 @@
 #if (defined(__sun__) && (!defined(__LP64__)))   // Sun Solaris 32-bits requires specific definitions\r
 #  define _LARGEFILE_SOURCE \r
 #  define FILE_OFFSET_BITS=64\r
-#else\r
+#elif ! defined(__LP64__)                        // No point defining Large file for 64 bit\r
 #  define _LARGEFILE64_SOURCE\r
 #endif\r
 \r
index 9fea8fd..9ba79d4 100644 (file)
--- a/fuzzer.c
+++ b/fuzzer.c
@@ -33,7 +33,7 @@
 // Includes\r
 //**************************************\r
 #include <stdlib.h>\r
-#include <stdio.h>      // fgets\r
+#include <stdio.h>      // fgets, sscanf\r
 #include <sys/timeb.h>  // timeb\r
 #include "lz4.h"\r
 \r
@@ -97,11 +97,12 @@ int main() {
         unsigned long long bytes = 0;\r
         unsigned long long cbytes = 0;\r
         unsigned char buf[LEN];\r
-#       define FUZ_max   LZ4_compressBound(LEN)\r
+        unsigned char testOut[LEN+1];\r
+#       define FUZ_max   LZ4_COMPRESSBOUND(LEN)\r
 #       define FUZ_avail ROUND_PAGE(FUZ_max)\r
         const int off_full = FUZ_avail - FUZ_max;\r
         unsigned char cbuf[FUZ_avail + PAGE_SIZE];\r
-               unsigned int seed, cur_seq, seeds[NUM_SEQ], timestamp=FUZ_GetMilliStart();\r
+               unsigned int seed, cur_seq=PRIME3, seeds[NUM_SEQ], timestamp=FUZ_GetMilliStart();\r
         int i, j, k, ret, len;\r
                char userInput[30] = {0};\r
 \r
@@ -120,6 +121,7 @@ int main() {
 \r
         for (i = 0; i < NB_ATTEMPTS; i++) {\r
                        printf("\r%7i /%7i\r", i, NB_ATTEMPTS);\r
+                       \r
                        FUZ_rand(&seed);\r
             for (j = 0; j < NUM_SEQ; j++) {\r
                     seeds[j] = FUZ_rand(&seed) << 8;\r
@@ -136,23 +138,64 @@ int main() {
                     }\r
                     buf[j] = FUZ_rand(&cur_seq) >> 16;\r
             }\r
+\r
+                       // Test compression\r
             ret = LZ4_compress_limitedOutput((const char*)buf, (char*)&cbuf[off_full], LEN, FUZ_max);\r
+                       if (ret == 0) { printf("compression failed despite sufficient space: seed %u, len %d\n", seed, LEN); goto _output_error; }\r
             len = ret;\r
 \r
-                       // Test compression with output size being exactly what's necessary\r
+                       // Test decoding with output size being exactly what's necessary => must work\r
+                       ret = LZ4_uncompress((char*)&cbuf[off_full], (char*)testOut, LEN);\r
+                       if (ret<0) { printf("decompression failed despite sufficient space: seed %u, len %d\n", seed, LEN); goto _output_error; }\r
+\r
+                       // Test decoding with one byte missing => must fail\r
+                       ret = LZ4_uncompress((char*)&cbuf[off_full], (char*)testOut, LEN-1);\r
+                       if (ret>=0) { printf("decompression should have failed, due to Output Size being too small : seed %u, len %d\n", seed, LEN); goto _output_error; }\r
+\r
+                       // Test decoding with one byte too much => must fail\r
+                       ret = LZ4_uncompress((char*)&cbuf[off_full], (char*)testOut, LEN+1);\r
+                       if (ret>=0) { printf("decompression should have failed, due to Output Size being too large : seed %u, len %d\n", seed, LEN); goto _output_error; }\r
+\r
+                       // Test decoding with enough output size => must work\r
+                       ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len, LEN+1);\r
+                       if (ret<0) { printf("decompression failed despite sufficient space: seed %u, len %d\n", seed, LEN); goto _output_error; }\r
+\r
+                       // Test decoding with output size being exactly what's necessary => should work\r
+                       ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len, LEN);\r
+                       if (ret<0) { printf("decompression failed despite sufficient space: seed %u, len %d\n", seed, LEN); goto _output_error; }\r
+\r
+                       // Test decoding with output size being one byte too short => must fail\r
+                       ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len, LEN-1);\r
+                       if (ret>=0) { printf("decompression should have failed, due to Output Size being too small : seed %u, len %d\n", seed, LEN); goto _output_error; }\r
+\r
+                       // Test decoding with input size being one byte too short => must fail\r
+                       ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len-1, LEN);\r
+                       if (ret>=0) { printf("decompression should have failed, due to input size being too small : seed %u, len %d\n", seed, LEN); goto _output_error; }\r
+\r
+                       // Test decoding with input size being one byte too large => must fail\r
+                       ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len+1, LEN);\r
+                       if (ret>=0) { printf("decompression should have failed, due to input size being too large : seed %u, len %d\n", seed, LEN); goto _output_error; }\r
+\r
+                       // Test compression with output size being exactly what's necessary (should work)\r
             ret = LZ4_compress_limitedOutput((const char*)buf, (char*)&cbuf[FUZ_avail-len], LEN, len);\r
-            if (!test_canary(&cbuf[FUZ_avail])) { printf("compression overran output buffer: seed %u, len %d, olen %d\n", seed, LEN, len); return 1; }\r
-            if (ret == 0) { printf("compression failed despite sufficient space: seed %u, len %d\n", seed, LEN); return 1; }\r
+            if (!test_canary(&cbuf[FUZ_avail])) { printf("compression overran output buffer: seed %u, len %d, olen %d\n", seed, LEN, len); goto _output_error; }\r
+            if (ret == 0) { printf("compression failed despite sufficient space: seed %u, len %d\n", seed, LEN); goto _output_error; }\r
 \r
                        // Test compression with just one missing byte into output buffer => must fail\r
             ret = LZ4_compress_limitedOutput((const char*)buf, (char*)&cbuf[FUZ_avail-(len-1)], LEN, len-1);\r
-            if (ret) { printf("compression overran output buffer: seed %u, len %d, olen %d => ret %d", seed, LEN, len-1, ret); return 1; }\r
-            if (!test_canary(&cbuf[FUZ_avail])) { printf("compression overran output buffer: seed %u, len %d, olen %d", seed, LEN, len-1); return 1; }\r
+            if (ret) { printf("compression overran output buffer: seed %u, len %d, olen %d => ret %d", seed, LEN, len-1, ret); goto _output_error; }\r
+            if (!test_canary(&cbuf[FUZ_avail])) { printf("compression overran output buffer: seed %u, len %d, olen %d", seed, LEN, len-1); goto _output_error; }\r
 \r
                        bytes += LEN;\r
             cbytes += len;\r
         }\r
+\r
                printf("all tests completed successfully \n");\r
         printf("compression ratio: %0.3f%%\n", (double)cbytes/bytes*100);\r
+               getchar();\r
         return 0;\r
+\r
+_output_error:\r
+               getchar();\r
+               return 1;\r
 }\r
diff --git a/lz4.c b/lz4.c
index 75dc64a..a651748 100644 (file)
--- a/lz4.c
+++ b/lz4.c
@@ -91,7 +91,7 @@
 //**************************************\r
 // Compiler Options\r
 //**************************************\r
-#if __STDC_VERSION__ >= 199901L // C99\r
+#if __STDC_VERSION__ >= 199901L   // C99\r
 /* "restrict" is a known keyword */\r
 #else\r
 #  define restrict // Disable restrict\r
 #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)\r
 \r
 #ifdef _MSC_VER  // Visual Studio\r
-#  define inline __forceinline           // Visual is not C99, but supports some kind of inline\r
 #  include <intrin.h>   // For Visual 2005\r
 #  if LZ4_ARCH64       // 64-bit\r
 #    pragma intrinsic(_BitScanForward64) // For Visual 2005\r
diff --git a/lz4.h b/lz4.h
index dee3984..3680121 100644 (file)
--- a/lz4.h
+++ b/lz4.h
@@ -38,6 +38,14 @@ extern "C" {
 #endif\r
 \r
 \r
+//**************************************\r
+// Compiler Options\r
+//**************************************\r
+#ifdef _MSC_VER   // Visual Studio\r
+#  define inline __inline           // Visual is not C99, but supports some kind of inline\r
+#endif\r
+\r
+\r
 //****************************\r
 // Simple Functions\r
 //****************************\r
@@ -50,7 +58,7 @@ LZ4_compress() :
     Compresses 'isize' bytes from 'source' into 'dest'.\r
     Destination buffer must be already allocated,\r
     and must be sized to handle worst cases situations (input data not compressible)\r
-    Worst case size evaluation is provided by macro LZ4_compressBound()\r
+    Worst case size evaluation is provided by function LZ4_compressBound()\r
 \r
     isize  : is the input size. Max supported value is ~1.9GB\r
     return : the number of bytes written in buffer dest\r
@@ -70,12 +78,15 @@ LZ4_uncompress() :
 // Advanced Functions\r
 //****************************\r
 \r
-#define LZ4_compressBound(isize)   (isize + (isize/255) + 16)\r
+static inline int LZ4_compressBound(int isize)   { return ((isize) + ((isize)/255) + 16); }\r
+#define           LZ4_COMPRESSBOUND(    isize)            ((isize) + ((isize)/255) + 16)\r
 \r
 /*\r
 LZ4_compressBound() :\r
     Provides the maximum size that LZ4 may output in a "worst case" scenario (input data not compressible)\r
     primarily useful for memory allocation of output buffer.\r
+       inline function is recommended for the general case,\r
+       but macro is also provided when results need to be evaluated at compile time (such as table size allocation).\r
 \r
     isize  : is the input size. Max supported value is ~1.9GB\r
     return : maximum output size in a "worst case" scenario\r
index 6367401..067ac2e 100644 (file)
--- a/lz4demo.c
+++ b/lz4demo.c
@@ -53,7 +53,7 @@
 \r
 \r
 //**************************************\r
-// Compiler functions\r
+// Compiler-specific functions\r
 //**************************************\r
 #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)\r
 \r
@@ -91,9 +91,9 @@ static inline unsigned int swap32(unsigned int x) {
 // Architecture Macros\r
 //**************************************\r
 static const int one = 1;\r
-#define CPU_LITTLE_ENDIAN (*(char*)(&one))\r
-#define CPU_BIG_ENDIAN (!CPU_LITTLE_ENDIAN)\r
-#define LITTLE_ENDIAN32(i)   if (CPU_BIG_ENDIAN) { i = swap32(i); }\r
+#define CPU_LITTLE_ENDIAN  (*(char*)(&one))\r
+#define CPU_BIG_ENDIAN     (!CPU_LITTLE_ENDIAN)\r
+#define LITTLE_ENDIAN32(i) if (CPU_BIG_ENDIAN) { i = swap32(i); }\r
 \r
 \r
 //**************************************\r
@@ -177,6 +177,7 @@ int compress_file(char* input_filename, char* output_filename, int compressionle
        int r;\r
        int displayLevel = (compressionlevel>0);\r
        clock_t start, end;\r
+       size_t sizeCheck;\r
 \r
 \r
        // Init\r
@@ -199,7 +200,8 @@ int compress_file(char* input_filename, char* output_filename, int compressionle
        u32var = ARCHIVE_MAGICNUMBER;\r
        LITTLE_ENDIAN32(u32var);\r
        *(unsigned int*)out_buff = u32var;\r
-       fwrite(out_buff, 1, ARCHIVE_MAGICNUMBER_SIZE, foutput);\r
+       sizeCheck = fwrite(out_buff, 1, ARCHIVE_MAGICNUMBER_SIZE, foutput);\r
+       if (sizeCheck!=ARCHIVE_MAGICNUMBER_SIZE) { DISPLAY("write error\n"); return 10; }\r
 \r
        // Main Loop\r
        while (1)\r
@@ -220,7 +222,8 @@ int compress_file(char* input_filename, char* output_filename, int compressionle
                LITTLE_ENDIAN32(outSize);\r
                * (unsigned int*) out_buff = outSize;\r
                LITTLE_ENDIAN32(outSize);\r
-               fwrite(out_buff, 1, outSize+4, foutput);\r
+               sizeCheck = fwrite(out_buff, 1, outSize+4, foutput);\r
+               if (sizeCheck!=(size_t)(outSize+4)) { DISPLAY("write error\n"); return 11; }\r
        }\r
 \r
        // Status\r
@@ -254,6 +257,7 @@ int decode_file(char* input_filename, char* output_filename)
        FILE* foutput;\r
        clock_t start, end;\r
        int r;\r
+       size_t sizeCheck;\r
 \r
 \r
        // Init\r
@@ -291,7 +295,8 @@ int decode_file(char* input_filename, char* output_filename)
                filesize += sinkint;\r
 \r
                // Write Block\r
-               fwrite(out_buff, 1, sinkint, foutput);\r
+               sizeCheck = fwrite(out_buff, 1, sinkint, foutput);\r
+               if (sizeCheck != (size_t)sinkint) { DISPLAY("write error\n"); return 12; }\r
        }\r
 \r
        // Status\r
diff --git a/lz4hc.c b/lz4hc.c
index 2ab507e..7cd8bb4 100644 (file)
--- a/lz4hc.c
+++ b/lz4hc.c
@@ -337,7 +337,7 @@ inline static int LZ4HC_InsertAndFindBestMatch (LZ4HC_Data_Structure* hc4, const
        // HC4 match finder\r
        LZ4HC_Insert(hc4, ip);\r
        ref = HASH_POINTER(ip);\r
-       while ((ref > (ip-MAX_DISTANCE)) && (nbAttempts))\r
+       while ((ref >= (ip-MAX_DISTANCE)) && (nbAttempts))\r
        {\r
                nbAttempts--;\r
                if (*(ref+ml) == *(ip+ml))\r
@@ -380,7 +380,7 @@ inline static int LZ4HC_InsertAndGetWiderMatch (LZ4HC_Data_Structure* hc4, const
        LZ4HC_Insert(hc4, ip);\r
        ref = HASH_POINTER(ip);\r
 \r
-       while ((ref > ip-MAX_DISTANCE) && (ref >= hc4->base) && (nbAttempts))\r
+       while ((ref >= ip-MAX_DISTANCE) && (ref >= hc4->base) && (nbAttempts))\r
        {\r
                nbAttempts--;\r
                if (*(startLimit + longest) == *(ref - delta + longest))\r