fuzzer.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*
  2. fuzzer.c - Fuzzer test tool for LZ4
  3. Copyright (C) Andrew Mahone - Yann Collet 2012
  4. Original code by Andrew Mahone / Modified by Yann Collet
  5. GPL v2 License
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License along
  15. with this program; if not, write to the Free Software Foundation, Inc.,
  16. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. You can contact the author at :
  18. - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
  19. - LZ4 source repository : http://code.google.com/p/lz4/
  20. */
  21. //**************************************
  22. // Remove Visual warning messages
  23. //**************************************
  24. #define _CRT_SECURE_NO_WARNINGS // fgets
  25. //**************************************
  26. // Includes
  27. //**************************************
  28. #include <stdlib.h>
  29. #include <stdio.h> // fgets, sscanf
  30. #include <sys/timeb.h> // timeb
  31. #include "lz4.h"
  32. //**************************************
  33. // Constants
  34. //**************************************
  35. #define NB_ATTEMPTS (1<<18)
  36. #define LEN ((1<<15))
  37. #define SEQ_POW 2
  38. #define NUM_SEQ (1 << SEQ_POW)
  39. #define SEQ_MSK ((NUM_SEQ) - 1)
  40. #define MOD_SEQ(x) ((((x) >> 8) & 255) == 0)
  41. #define NEW_SEQ(x) ((((x) >> 10) %10) == 0)
  42. #define PAGE_SIZE 4096
  43. #define ROUND_PAGE(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
  44. #define PRIME1 2654435761U
  45. #define PRIME2 2246822519U
  46. #define PRIME3 3266489917U
  47. //*********************************************************
  48. // Functions
  49. //*********************************************************
  50. static int FUZ_GetMilliStart()
  51. {
  52. struct timeb tb;
  53. int nCount;
  54. ftime( &tb );
  55. nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000);
  56. return nCount;
  57. }
  58. static int FUZ_GetMilliSpan( int nTimeStart )
  59. {
  60. int nSpan = FUZ_GetMilliStart() - nTimeStart;
  61. if ( nSpan < 0 )
  62. nSpan += 0x100000 * 1000;
  63. return nSpan;
  64. }
  65. unsigned int FUZ_rand(unsigned int* src)
  66. {
  67. *src = ((*src) * PRIME1) + PRIME2;
  68. return *src;
  69. }
  70. int test_canary(unsigned char *buf) {
  71. int i;
  72. for (i = 0; i < 2048; i++)
  73. if (buf[i] != buf[i + 2048])
  74. return 0;
  75. return 1;
  76. }
  77. int FUZ_SecurityTest()
  78. {
  79. char* output;
  80. char* input;
  81. int i, r;
  82. printf("Starting security tests...");
  83. input = (char*) malloc (20<<20);
  84. output = (char*) malloc (20<<20);
  85. input[0] = 0x0F;
  86. input[1] = 0x00;
  87. input[2] = 0x00;
  88. for(i = 3; i < 16840000; i++)
  89. input[i] = 0xff;
  90. r = LZ4_uncompress(input, output, 20<<20);
  91. free(input);
  92. free(output);
  93. printf(" Completed (r=%i)\n",r);
  94. return 0;
  95. }
  96. //int main(int argc, char *argv[]) {
  97. int main() {
  98. unsigned long long bytes = 0;
  99. unsigned long long cbytes = 0;
  100. unsigned char buf[LEN];
  101. unsigned char testOut[LEN+1];
  102. # define FUZ_max LZ4_COMPRESSBOUND(LEN)
  103. # define FUZ_avail ROUND_PAGE(FUZ_max)
  104. const int off_full = FUZ_avail - FUZ_max;
  105. unsigned char cbuf[FUZ_avail + PAGE_SIZE];
  106. unsigned int seed, cur_seq=PRIME3, seeds[NUM_SEQ], timestamp=FUZ_GetMilliStart();
  107. int i, j, k, ret, len;
  108. char userInput[30] = {0};
  109. printf("starting LZ4 fuzzer\n");
  110. printf("Select an Initialisation number (default : random) : ");
  111. fflush(stdout);
  112. if ( fgets(userInput, sizeof userInput, stdin) )
  113. {
  114. if ( sscanf(userInput, "%d", &seed) == 1 ) {}
  115. else seed = FUZ_GetMilliSpan(timestamp);
  116. }
  117. printf("Seed = %u\n", seed);
  118. FUZ_SecurityTest();
  119. for (i = 0; i < 2048; i++)
  120. cbuf[FUZ_avail + i] = cbuf[FUZ_avail + 2048 + i] = FUZ_rand(&seed) >> 16;
  121. for (i = 0; i < NB_ATTEMPTS; i++)
  122. {
  123. printf("\r%7i /%7i\r", i, NB_ATTEMPTS);
  124. FUZ_rand(&seed);
  125. for (j = 0; j < NUM_SEQ; j++) {
  126. seeds[j] = FUZ_rand(&seed) << 8;
  127. seeds[j] ^= (FUZ_rand(&seed) >> 8) & 65535;
  128. }
  129. for (j = 0; j < LEN; j++) {
  130. k = FUZ_rand(&seed);
  131. if (j == 0 || NEW_SEQ(k))
  132. cur_seq = seeds[(FUZ_rand(&seed) >> 16) & SEQ_MSK];
  133. if (MOD_SEQ(k)) {
  134. k = (FUZ_rand(&seed) >> 16) & SEQ_MSK;
  135. seeds[k] = FUZ_rand(&seed) << 8;
  136. seeds[k] ^= (FUZ_rand(&seed) >> 8) & 65535;
  137. }
  138. buf[j] = FUZ_rand(&cur_seq) >> 16;
  139. }
  140. // Test compression
  141. ret = LZ4_compress_limitedOutput((const char*)buf, (char*)&cbuf[off_full], LEN, FUZ_max);
  142. if (ret == 0) { printf("compression failed despite sufficient space: seed %u, len %d\n", seed, LEN); goto _output_error; }
  143. len = ret;
  144. // Test decoding with output size being exactly what's necessary => must work
  145. ret = LZ4_uncompress((char*)&cbuf[off_full], (char*)testOut, LEN);
  146. if (ret<0) { printf("decompression failed despite correct space: seed %u, len %d\n", seed, LEN); goto _output_error; }
  147. // Test decoding with one byte missing => must fail
  148. ret = LZ4_uncompress((char*)&cbuf[off_full], (char*)testOut, LEN-1);
  149. 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; }
  150. // Test decoding with one byte too much => must fail
  151. ret = LZ4_uncompress((char*)&cbuf[off_full], (char*)testOut, LEN+1);
  152. 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; }
  153. // Test decoding with enough output size => must work
  154. ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len, LEN+1);
  155. if (ret<0) { printf("decompression failed despite sufficient space: seed %u, len %d\n", seed, LEN); goto _output_error; }
  156. // Test decoding with output size being exactly what's necessary => must work
  157. ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len, LEN);
  158. if (ret<0) { printf("decompression failed despite sufficient space: seed %u, len %d\n", seed, LEN); goto _output_error; }
  159. // Test decoding with output size being one byte too short => must fail
  160. ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len, LEN-1);
  161. 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; }
  162. // Test decoding with input size being one byte too short => must fail
  163. ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len-1, LEN);
  164. 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; }
  165. // Test decoding with input size being one byte too large => must fail
  166. ret = LZ4_uncompress_unknownOutputSize((char*)&cbuf[off_full], (char*)testOut, len+1, LEN);
  167. 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; }
  168. // Test compression with output size being exactly what's necessary (should work)
  169. ret = LZ4_compress_limitedOutput((const char*)buf, (char*)&cbuf[FUZ_avail-len], LEN, len);
  170. if (!test_canary(&cbuf[FUZ_avail])) { printf("compression overran output buffer: seed %u, len %d, olen %d\n", seed, LEN, len); goto _output_error; }
  171. if (ret == 0) { printf("compression failed despite sufficient space: seed %u, len %d\n", seed, LEN); goto _output_error; }
  172. // Test compression with just one missing byte into output buffer => must fail
  173. ret = LZ4_compress_limitedOutput((const char*)buf, (char*)&cbuf[FUZ_avail-(len-1)], LEN, len-1);
  174. if (ret) { printf("compression overran output buffer: seed %u, len %d, olen %d => ret %d", seed, LEN, len-1, ret); goto _output_error; }
  175. if (!test_canary(&cbuf[FUZ_avail])) { printf("compression overran output buffer: seed %u, len %d, olen %d", seed, LEN, len-1); goto _output_error; }
  176. bytes += LEN;
  177. cbytes += len;
  178. }
  179. printf("all tests completed successfully \n");
  180. printf("compression ratio: %0.3f%%\n", (double)cbytes/bytes*100);
  181. getchar();
  182. return 0;
  183. _output_error:
  184. getchar();
  185. return 1;
  186. }