--- /dev/null
+/*\r
+ fuzzer.c - Fuzzer test tool for LZ4\r
+ Copyright (C) Yann Collet - Andrew Mahone 2012-2013\r
+ Code started by Andrew Mahone, modified by Yann Collet\r
+ GPL v2 License\r
+\r
+ This program is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License along\r
+ with this program; if not, write to the Free Software Foundation, Inc.,\r
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+\r
+ You can contact the author at :\r
+ - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html\r
+ - LZ4 source repository : http://code.google.com/p/lz4/\r
+*/\r
+\r
+//**************************************\r
+// Remove Visual warning messages\r
+//**************************************\r
+#define _CRT_SECURE_NO_WARNINGS // fgets\r
+\r
+\r
+//**************************************\r
+// Includes\r
+//**************************************\r
+#include <stdlib.h>\r
+#include <stdio.h> // fgets, sscanf\r
+#include <sys/timeb.h> // timeb\r
+#include "lz4.h"\r
+#include "lz4hc.h"\r
+\r
+\r
+//**************************************\r
+// Constants\r
+//**************************************\r
+#define NB_ATTEMPTS (1<<17)\r
+#define LEN ((1<<15))\r
+#define SEQ_POW 2\r
+#define NUM_SEQ (1 << SEQ_POW)\r
+#define SEQ_MSK ((NUM_SEQ) - 1)\r
+#define MOD_SEQ(x) ((((x) >> 8) & 255) == 0)\r
+#define NEW_SEQ(x) ((((x) >> 10) %10) == 0)\r
+#define PAGE_SIZE 4096\r
+#define ROUND_PAGE(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))\r
+#define PRIME1 2654435761U\r
+#define PRIME2 2246822519U\r
+#define PRIME3 3266489917U\r
+\r
+\r
+//*********************************************************\r
+// Functions\r
+//*********************************************************\r
+static int FUZ_GetMilliStart()\r
+{\r
+ struct timeb tb;\r
+ int nCount;\r
+ ftime( &tb );\r
+ nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000);\r
+ return nCount;\r
+}\r
+\r
+\r
+static int FUZ_GetMilliSpan( int nTimeStart )\r
+{\r
+ int nSpan = FUZ_GetMilliStart() - nTimeStart;\r
+ if ( nSpan < 0 )\r
+ nSpan += 0x100000 * 1000;\r
+ return nSpan;\r
+}\r
+\r
+\r
+unsigned int FUZ_rand(unsigned int* src)\r
+{\r
+ *src = ((*src) * PRIME1) + PRIME2;\r
+ return *src;\r
+}\r
+\r
+\r
+int test_canary(unsigned char *buf)\r
+{\r
+ int i;\r
+ for (i = 0; i < 2048; i++)\r
+ if (buf[i] != buf[i + 2048])\r
+ return 0;\r
+ return 1;\r
+}\r
+\r
+\r
+int FUZ_SecurityTest()\r
+{\r
+ char* output;\r
+ char* input;\r
+ int i, r;\r
+\r
+ printf("Overflow test (issue 52)...");\r
+ input = (char*) malloc (20<<20);\r
+ output = (char*) malloc (20<<20);\r
+ input[0] = 0x0F;\r
+ input[1] = 0x00;\r
+ input[2] = 0x00;\r
+ for(i = 3; i < 16840000; i++)\r
+ input[i] = 0xff;\r
+ r = LZ4_decompress_fast(input, output, 20<<20);\r
+\r
+ free(input);\r
+ free(output);\r
+ printf(" Passed (return = %i < 0)\n",r);\r
+ return 0;\r
+}\r
+\r
+\r
+//int main(int argc, char *argv[]) {\r
+int main() {\r
+ unsigned long long bytes = 0;\r
+ unsigned long long cbytes = 0;\r
+ unsigned long long hcbytes = 0;\r
+ unsigned char buf[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, randState, cur_seq=PRIME3, seeds[NUM_SEQ], timestamp=FUZ_GetMilliStart();\r
+ int i, j, k, ret, len, lenHC, attemptNb;\r
+ char userInput[30] = {0};\r
+# define FUZ_CHECKTEST(cond, message) testNb++; if (cond) { printf("Test %i : %s : seed %u, cycle %u \n", testNb, message, seed, attemptNb); goto _output_error; }\r
+\r
+ printf("starting LZ4 fuzzer\n");\r
+ printf("Select an Initialisation number (default : random) : ");\r
+ fflush(stdout);\r
+ if ( fgets(userInput, sizeof userInput, stdin) )\r
+ {\r
+ if ( sscanf(userInput, "%d", &seed) == 1 ) {}\r
+ else seed = FUZ_GetMilliSpan(timestamp);\r
+ }\r
+ printf("Seed = %u\n", seed);\r
+ randState = seed;\r
+\r
+ FUZ_SecurityTest();\r
+\r
+ for (i = 0; i < 2048; i++)\r
+ cbuf[FUZ_avail + i] = cbuf[FUZ_avail + 2048 + i] = FUZ_rand(&randState) >> 16;\r
+\r
+ for (attemptNb = 0; attemptNb < NB_ATTEMPTS; attemptNb++) \r
+ {\r
+ int testNb = 0;\r
+\r
+ printf("\r%7i /%7i\r", attemptNb, NB_ATTEMPTS);\r
+ \r
+ for (j = 0; j < NUM_SEQ; j++) {\r
+ seeds[j] = FUZ_rand(&randState) << 8;\r
+ seeds[j] ^= (FUZ_rand(&randState) >> 8) & 65535;\r
+ }\r
+ for (j = 0; j < LEN; j++) {\r
+ k = FUZ_rand(&randState);\r
+ if (j == 0 || NEW_SEQ(k))\r
+ cur_seq = seeds[(FUZ_rand(&randState) >> 16) & SEQ_MSK];\r
+ if (MOD_SEQ(k)) {\r
+ k = (FUZ_rand(&randState) >> 16) & SEQ_MSK;\r
+ seeds[k] = FUZ_rand(&randState) << 8;\r
+ seeds[k] ^= (FUZ_rand(&randState) >> 8) & 65535;\r
+ }\r
+ buf[j] = FUZ_rand(&cur_seq) >> 16;\r
+ }\r
+\r
+ // Test compression HC\r
+ ret = LZ4_compressHC_limitedOutput((const char*)buf, (char*)&cbuf[off_full], LEN, FUZ_max);\r
+ FUZ_CHECKTEST(ret==0, "HC compression failed despite sufficient space");\r
+ lenHC = ret;\r
+\r
+ // Test compression\r
+ ret = LZ4_compress_limitedOutput((const char*)buf, (char*)&cbuf[off_full], LEN, FUZ_max);\r
+ FUZ_CHECKTEST(ret==0, "compression failed despite sufficient space");\r
+ len = ret;\r
+\r
+ // Test decoding with output size being exactly what's necessary => must work\r
+ ret = LZ4_decompress_fast((char*)&cbuf[off_full], (char*)testOut, LEN);\r
+ FUZ_CHECKTEST(ret<0, "decompression failed despite correct space");\r
+\r
+ // Test decoding with one byte missing => must fail\r
+ ret = LZ4_decompress_fast((char*)&cbuf[off_full], (char*)testOut, LEN-1);\r
+ FUZ_CHECKTEST(ret>=0, "decompression should have failed, due to Output Size being too small");\r
+\r
+ // Test decoding with one byte too much => must fail\r
+ ret = LZ4_decompress_fast((char*)&cbuf[off_full], (char*)testOut, LEN+1);\r
+ FUZ_CHECKTEST(ret>=0, "decompression should have failed, due to Output Size being too large");\r
+\r
+ // Test decoding with enough output size => must work\r
+ ret = LZ4_decompress_safe((char*)&cbuf[off_full], (char*)testOut, len, LEN+1);\r
+ FUZ_CHECKTEST(ret<0, "decompression failed despite sufficient space");\r
+\r
+ // Test decoding with output size being exactly what's necessary => must work\r
+ ret = LZ4_decompress_safe((char*)&cbuf[off_full], (char*)testOut, len, LEN);\r
+ FUZ_CHECKTEST(ret<0, "decompression failed despite sufficient space");\r
+\r
+ // Test decoding with output size being one byte too short => must fail\r
+ ret = LZ4_decompress_safe((char*)&cbuf[off_full], (char*)testOut, len, LEN-1);\r
+ FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe should have failed, due to Output Size being one byte too short");\r
+\r
+ // Test decoding with input size being one byte too short => must fail\r
+ ret = LZ4_decompress_safe((char*)&cbuf[off_full], (char*)testOut, len-1, LEN);\r
+ FUZ_CHECKTEST(ret>=0, "LZ4_decompress_safe should have failed, due to input size being one byte too short");\r
+\r
+ // Test decoding with input size being one byte too large => must fail\r
+ ret = LZ4_decompress_safe((char*)&cbuf[off_full], (char*)testOut, len+1, LEN);\r
+ FUZ_CHECKTEST(ret>=0, "decompression should have failed, due to input size being too large");\r
+ //if (ret>=0) { printf("Test 10 : decompression should have failed, due to input size being too large : seed %u, len %d\n", seed, LEN); goto _output_error; }\r
+\r
+ // Test partial decoding with target output size being max/2 => must work\r
+ ret = LZ4_decompress_safe_partial((char*)&cbuf[off_full], (char*)testOut, len, LEN/2, LEN);\r
+ FUZ_CHECKTEST(ret<0, "partial decompression failed despite sufficient space");\r
+\r
+ // Test partial decoding with target output size being just below max => must work\r
+ ret = LZ4_decompress_safe_partial((char*)&cbuf[off_full], (char*)testOut, len, LEN-3, LEN);\r
+ FUZ_CHECKTEST(ret<0, "partial decompression failed despite sufficient space");\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
+ FUZ_CHECKTEST(!test_canary(&cbuf[FUZ_avail]), "compression overran output buffer");\r
+ FUZ_CHECKTEST(ret==0, "compression failed despite sufficient space");\r
+\r
+ // Test HC compression with output size being exactly what's necessary (should work)\r
+ ret = LZ4_compressHC_limitedOutput((const char*)buf, (char*)&cbuf[FUZ_avail-len], LEN, lenHC);\r
+ FUZ_CHECKTEST(ret==0, "HC compression failed despite sufficient space");\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
+ FUZ_CHECKTEST(ret, "compression overran output buffer");\r
+ FUZ_CHECKTEST(!test_canary(&cbuf[FUZ_avail]), "compression overran output buffer");\r
+\r
+ // Test HC compression with just one missing byte into output buffer => must fail\r
+ ret = LZ4_compressHC_limitedOutput((const char*)buf, (char*)&cbuf[FUZ_avail-(len-1)], LEN, lenHC-1);\r
+ FUZ_CHECKTEST(ret, "HC compression overran output buffer");\r
+\r
+ bytes += LEN;\r
+ cbytes += len;\r
+ hcbytes += lenHC;\r
+ FUZ_rand(&randState);\r
+ }\r
+\r
+ printf("all tests completed successfully \n");\r
+ printf("compression ratio: %0.3f%%\n", (double)cbytes/bytes*100);\r
+ printf("HC compression ratio: %0.3f%%\n", (double)hcbytes/bytes*100);\r
+ getchar();\r
+ return 0;\r
+\r
+_output_error:\r
+ getchar();\r
+ return 1;\r
+}\r