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