1*27162e4eSAndroid Build Coastguard Worker /*
2*27162e4eSAndroid Build Coastguard Worker * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
3*27162e4eSAndroid Build Coastguard Worker * All rights reserved.
4*27162e4eSAndroid Build Coastguard Worker *
5*27162e4eSAndroid Build Coastguard Worker * This source code is licensed under both the BSD-style license (found in the
6*27162e4eSAndroid Build Coastguard Worker * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*27162e4eSAndroid Build Coastguard Worker * in the COPYING file in the root directory of this source tree),
8*27162e4eSAndroid Build Coastguard Worker * meaning you may select, at your option, one of the above-listed licenses.
9*27162e4eSAndroid Build Coastguard Worker */
10*27162e4eSAndroid Build Coastguard Worker
11*27162e4eSAndroid Build Coastguard Worker /*
12*27162e4eSAndroid Build Coastguard Worker * This program takes a file in input,
13*27162e4eSAndroid Build Coastguard Worker * performs an LZ4 round-trip test (compress + decompress)
14*27162e4eSAndroid Build Coastguard Worker * compares the result with original
15*27162e4eSAndroid Build Coastguard Worker * and generates an abort() on corruption detection,
16*27162e4eSAndroid Build Coastguard Worker * in order for afl to register the event as a crash.
17*27162e4eSAndroid Build Coastguard Worker */
18*27162e4eSAndroid Build Coastguard Worker
19*27162e4eSAndroid Build Coastguard Worker
20*27162e4eSAndroid Build Coastguard Worker /*===========================================
21*27162e4eSAndroid Build Coastguard Worker * Tuning Constant
22*27162e4eSAndroid Build Coastguard Worker *==========================================*/
23*27162e4eSAndroid Build Coastguard Worker #ifndef MIN_CLEVEL
24*27162e4eSAndroid Build Coastguard Worker # define MIN_CLEVEL (int)(-5)
25*27162e4eSAndroid Build Coastguard Worker #endif
26*27162e4eSAndroid Build Coastguard Worker
27*27162e4eSAndroid Build Coastguard Worker
28*27162e4eSAndroid Build Coastguard Worker
29*27162e4eSAndroid Build Coastguard Worker /*===========================================
30*27162e4eSAndroid Build Coastguard Worker * Dependencies
31*27162e4eSAndroid Build Coastguard Worker *==========================================*/
32*27162e4eSAndroid Build Coastguard Worker #include <stddef.h> /* size_t */
33*27162e4eSAndroid Build Coastguard Worker #include <stdlib.h> /* malloc, free, exit */
34*27162e4eSAndroid Build Coastguard Worker #include <stdio.h> /* fprintf */
35*27162e4eSAndroid Build Coastguard Worker #include <string.h> /* strcmp */
36*27162e4eSAndroid Build Coastguard Worker #include <assert.h>
37*27162e4eSAndroid Build Coastguard Worker #include <sys/types.h> /* stat */
38*27162e4eSAndroid Build Coastguard Worker #include <sys/stat.h> /* stat */
39*27162e4eSAndroid Build Coastguard Worker #include "xxhash.h"
40*27162e4eSAndroid Build Coastguard Worker
41*27162e4eSAndroid Build Coastguard Worker #include "lz4.h"
42*27162e4eSAndroid Build Coastguard Worker #include "lz4hc.h"
43*27162e4eSAndroid Build Coastguard Worker
44*27162e4eSAndroid Build Coastguard Worker
45*27162e4eSAndroid Build Coastguard Worker /*===========================================
46*27162e4eSAndroid Build Coastguard Worker * Macros
47*27162e4eSAndroid Build Coastguard Worker *==========================================*/
48*27162e4eSAndroid Build Coastguard Worker #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
49*27162e4eSAndroid Build Coastguard Worker
50*27162e4eSAndroid Build Coastguard Worker #define MSG(...) fprintf(stderr, __VA_ARGS__)
51*27162e4eSAndroid Build Coastguard Worker
52*27162e4eSAndroid Build Coastguard Worker #define CONTROL_MSG(c, ...) { \
53*27162e4eSAndroid Build Coastguard Worker if ((c)) { \
54*27162e4eSAndroid Build Coastguard Worker MSG(__VA_ARGS__); \
55*27162e4eSAndroid Build Coastguard Worker MSG(" \n"); \
56*27162e4eSAndroid Build Coastguard Worker abort(); \
57*27162e4eSAndroid Build Coastguard Worker } \
58*27162e4eSAndroid Build Coastguard Worker }
59*27162e4eSAndroid Build Coastguard Worker
60*27162e4eSAndroid Build Coastguard Worker
checkBuffers(const void * buff1,const void * buff2,size_t buffSize)61*27162e4eSAndroid Build Coastguard Worker static size_t checkBuffers(const void* buff1, const void* buff2, size_t buffSize)
62*27162e4eSAndroid Build Coastguard Worker {
63*27162e4eSAndroid Build Coastguard Worker const char* const ip1 = (const char*)buff1;
64*27162e4eSAndroid Build Coastguard Worker const char* const ip2 = (const char*)buff2;
65*27162e4eSAndroid Build Coastguard Worker size_t pos;
66*27162e4eSAndroid Build Coastguard Worker
67*27162e4eSAndroid Build Coastguard Worker for (pos=0; pos<buffSize; pos++)
68*27162e4eSAndroid Build Coastguard Worker if (ip1[pos]!=ip2[pos])
69*27162e4eSAndroid Build Coastguard Worker break;
70*27162e4eSAndroid Build Coastguard Worker
71*27162e4eSAndroid Build Coastguard Worker return pos;
72*27162e4eSAndroid Build Coastguard Worker }
73*27162e4eSAndroid Build Coastguard Worker
74*27162e4eSAndroid Build Coastguard Worker
75*27162e4eSAndroid Build Coastguard Worker /* select a compression level
76*27162e4eSAndroid Build Coastguard Worker * based on first bytes present in a reference buffer */
select_clevel(const void * refBuff,size_t refBuffSize)77*27162e4eSAndroid Build Coastguard Worker static int select_clevel(const void* refBuff, size_t refBuffSize)
78*27162e4eSAndroid Build Coastguard Worker {
79*27162e4eSAndroid Build Coastguard Worker const int minCLevel = MIN_CLEVEL;
80*27162e4eSAndroid Build Coastguard Worker const int maxClevel = LZ4HC_CLEVEL_MAX;
81*27162e4eSAndroid Build Coastguard Worker const int cLevelSpan = maxClevel - minCLevel;
82*27162e4eSAndroid Build Coastguard Worker size_t const hashLength = MIN(16, refBuffSize);
83*27162e4eSAndroid Build Coastguard Worker unsigned const h32 = XXH32(refBuff, hashLength, 0);
84*27162e4eSAndroid Build Coastguard Worker int const randL = h32 % (cLevelSpan+1);
85*27162e4eSAndroid Build Coastguard Worker
86*27162e4eSAndroid Build Coastguard Worker return minCLevel + randL;
87*27162e4eSAndroid Build Coastguard Worker }
88*27162e4eSAndroid Build Coastguard Worker
89*27162e4eSAndroid Build Coastguard Worker
90*27162e4eSAndroid Build Coastguard Worker typedef int (*compressFn)(const char* src, char* dst, int srcSize, int dstSize, int cLevel);
91*27162e4eSAndroid Build Coastguard Worker
92*27162e4eSAndroid Build Coastguard Worker
93*27162e4eSAndroid Build Coastguard Worker /** roundTripTest() :
94*27162e4eSAndroid Build Coastguard Worker * Compresses `srcBuff` into `compressedBuff`,
95*27162e4eSAndroid Build Coastguard Worker * then decompresses `compressedBuff` into `resultBuff`.
96*27162e4eSAndroid Build Coastguard Worker * If clevel==0, compression level is derived from srcBuff's content head bytes.
97*27162e4eSAndroid Build Coastguard Worker * This function abort() if it detects any round-trip error.
98*27162e4eSAndroid Build Coastguard Worker * Therefore, if it returns, round trip is considered successfully validated.
99*27162e4eSAndroid Build Coastguard Worker * Note : `compressedBuffCapacity` should be `>= LZ4_compressBound(srcSize)`
100*27162e4eSAndroid Build Coastguard Worker * for compression to be guaranteed to work */
roundTripTest(void * resultBuff,size_t resultBuffCapacity,void * compressedBuff,size_t compressedBuffCapacity,const void * srcBuff,size_t srcSize,int clevel)101*27162e4eSAndroid Build Coastguard Worker static void roundTripTest(void* resultBuff, size_t resultBuffCapacity,
102*27162e4eSAndroid Build Coastguard Worker void* compressedBuff, size_t compressedBuffCapacity,
103*27162e4eSAndroid Build Coastguard Worker const void* srcBuff, size_t srcSize,
104*27162e4eSAndroid Build Coastguard Worker int clevel)
105*27162e4eSAndroid Build Coastguard Worker {
106*27162e4eSAndroid Build Coastguard Worker int const proposed_clevel = clevel ? clevel : select_clevel(srcBuff, srcSize);
107*27162e4eSAndroid Build Coastguard Worker int const selected_clevel = proposed_clevel < 0 ? -proposed_clevel : proposed_clevel; /* if level < 0, it becomes an acceleration value */
108*27162e4eSAndroid Build Coastguard Worker compressFn compress = selected_clevel >= LZ4HC_CLEVEL_MIN ? LZ4_compress_HC : LZ4_compress_fast;
109*27162e4eSAndroid Build Coastguard Worker int const cSize = compress((const char*)srcBuff, (char*)compressedBuff, (int)srcSize, (int)compressedBuffCapacity, selected_clevel);
110*27162e4eSAndroid Build Coastguard Worker CONTROL_MSG(cSize == 0, "Compression error !");
111*27162e4eSAndroid Build Coastguard Worker
112*27162e4eSAndroid Build Coastguard Worker { int const dSize = LZ4_decompress_safe((const char*)compressedBuff, (char*)resultBuff, cSize, (int)resultBuffCapacity);
113*27162e4eSAndroid Build Coastguard Worker CONTROL_MSG(dSize < 0, "Decompression detected an error !");
114*27162e4eSAndroid Build Coastguard Worker CONTROL_MSG(dSize != (int)srcSize, "Decompression corruption error : wrong decompressed size !");
115*27162e4eSAndroid Build Coastguard Worker }
116*27162e4eSAndroid Build Coastguard Worker
117*27162e4eSAndroid Build Coastguard Worker /* check potential content corruption error */
118*27162e4eSAndroid Build Coastguard Worker assert(resultBuffCapacity >= srcSize);
119*27162e4eSAndroid Build Coastguard Worker { size_t const errorPos = checkBuffers(srcBuff, resultBuff, srcSize);
120*27162e4eSAndroid Build Coastguard Worker CONTROL_MSG(errorPos != srcSize,
121*27162e4eSAndroid Build Coastguard Worker "Silent decoding corruption, at pos %u !!!",
122*27162e4eSAndroid Build Coastguard Worker (unsigned)errorPos);
123*27162e4eSAndroid Build Coastguard Worker }
124*27162e4eSAndroid Build Coastguard Worker
125*27162e4eSAndroid Build Coastguard Worker }
126*27162e4eSAndroid Build Coastguard Worker
roundTripCheck(const void * srcBuff,size_t srcSize,int clevel)127*27162e4eSAndroid Build Coastguard Worker static void roundTripCheck(const void* srcBuff, size_t srcSize, int clevel)
128*27162e4eSAndroid Build Coastguard Worker {
129*27162e4eSAndroid Build Coastguard Worker size_t const cBuffSize = LZ4_COMPRESSBOUND(srcSize);
130*27162e4eSAndroid Build Coastguard Worker void* const cBuff = malloc(cBuffSize);
131*27162e4eSAndroid Build Coastguard Worker void* const rBuff = malloc(cBuffSize);
132*27162e4eSAndroid Build Coastguard Worker
133*27162e4eSAndroid Build Coastguard Worker if (!cBuff || !rBuff) {
134*27162e4eSAndroid Build Coastguard Worker fprintf(stderr, "not enough memory ! \n");
135*27162e4eSAndroid Build Coastguard Worker exit(1);
136*27162e4eSAndroid Build Coastguard Worker }
137*27162e4eSAndroid Build Coastguard Worker
138*27162e4eSAndroid Build Coastguard Worker roundTripTest(rBuff, cBuffSize,
139*27162e4eSAndroid Build Coastguard Worker cBuff, cBuffSize,
140*27162e4eSAndroid Build Coastguard Worker srcBuff, srcSize,
141*27162e4eSAndroid Build Coastguard Worker clevel);
142*27162e4eSAndroid Build Coastguard Worker
143*27162e4eSAndroid Build Coastguard Worker free(rBuff);
144*27162e4eSAndroid Build Coastguard Worker free(cBuff);
145*27162e4eSAndroid Build Coastguard Worker }
146*27162e4eSAndroid Build Coastguard Worker
147*27162e4eSAndroid Build Coastguard Worker
getFileSize(const char * infilename)148*27162e4eSAndroid Build Coastguard Worker static size_t getFileSize(const char* infilename)
149*27162e4eSAndroid Build Coastguard Worker {
150*27162e4eSAndroid Build Coastguard Worker int r;
151*27162e4eSAndroid Build Coastguard Worker #if defined(_MSC_VER)
152*27162e4eSAndroid Build Coastguard Worker struct _stat64 statbuf;
153*27162e4eSAndroid Build Coastguard Worker r = _stat64(infilename, &statbuf);
154*27162e4eSAndroid Build Coastguard Worker if (r || !(statbuf.st_mode & S_IFREG)) return 0; /* No good... */
155*27162e4eSAndroid Build Coastguard Worker #else
156*27162e4eSAndroid Build Coastguard Worker struct stat statbuf;
157*27162e4eSAndroid Build Coastguard Worker r = stat(infilename, &statbuf);
158*27162e4eSAndroid Build Coastguard Worker if (r || !S_ISREG(statbuf.st_mode)) return 0; /* No good... */
159*27162e4eSAndroid Build Coastguard Worker #endif
160*27162e4eSAndroid Build Coastguard Worker return (size_t)statbuf.st_size;
161*27162e4eSAndroid Build Coastguard Worker }
162*27162e4eSAndroid Build Coastguard Worker
163*27162e4eSAndroid Build Coastguard Worker
isDirectory(const char * infilename)164*27162e4eSAndroid Build Coastguard Worker static int isDirectory(const char* infilename)
165*27162e4eSAndroid Build Coastguard Worker {
166*27162e4eSAndroid Build Coastguard Worker int r;
167*27162e4eSAndroid Build Coastguard Worker #if defined(_MSC_VER)
168*27162e4eSAndroid Build Coastguard Worker struct _stat64 statbuf;
169*27162e4eSAndroid Build Coastguard Worker r = _stat64(infilename, &statbuf);
170*27162e4eSAndroid Build Coastguard Worker if (!r && (statbuf.st_mode & _S_IFDIR)) return 1;
171*27162e4eSAndroid Build Coastguard Worker #else
172*27162e4eSAndroid Build Coastguard Worker struct stat statbuf;
173*27162e4eSAndroid Build Coastguard Worker r = stat(infilename, &statbuf);
174*27162e4eSAndroid Build Coastguard Worker if (!r && S_ISDIR(statbuf.st_mode)) return 1;
175*27162e4eSAndroid Build Coastguard Worker #endif
176*27162e4eSAndroid Build Coastguard Worker return 0;
177*27162e4eSAndroid Build Coastguard Worker }
178*27162e4eSAndroid Build Coastguard Worker
179*27162e4eSAndroid Build Coastguard Worker
180*27162e4eSAndroid Build Coastguard Worker /** loadFile() :
181*27162e4eSAndroid Build Coastguard Worker * requirement : `buffer` size >= `fileSize` */
loadFile(void * buffer,const char * fileName,size_t fileSize)182*27162e4eSAndroid Build Coastguard Worker static void loadFile(void* buffer, const char* fileName, size_t fileSize)
183*27162e4eSAndroid Build Coastguard Worker {
184*27162e4eSAndroid Build Coastguard Worker FILE* const f = fopen(fileName, "rb");
185*27162e4eSAndroid Build Coastguard Worker if (isDirectory(fileName)) {
186*27162e4eSAndroid Build Coastguard Worker MSG("Ignoring %s directory \n", fileName);
187*27162e4eSAndroid Build Coastguard Worker exit(2);
188*27162e4eSAndroid Build Coastguard Worker }
189*27162e4eSAndroid Build Coastguard Worker if (f==NULL) {
190*27162e4eSAndroid Build Coastguard Worker MSG("Impossible to open %s \n", fileName);
191*27162e4eSAndroid Build Coastguard Worker exit(3);
192*27162e4eSAndroid Build Coastguard Worker }
193*27162e4eSAndroid Build Coastguard Worker { size_t const readSize = fread(buffer, 1, fileSize, f);
194*27162e4eSAndroid Build Coastguard Worker if (readSize != fileSize) {
195*27162e4eSAndroid Build Coastguard Worker MSG("Error reading %s \n", fileName);
196*27162e4eSAndroid Build Coastguard Worker exit(5);
197*27162e4eSAndroid Build Coastguard Worker } }
198*27162e4eSAndroid Build Coastguard Worker fclose(f);
199*27162e4eSAndroid Build Coastguard Worker }
200*27162e4eSAndroid Build Coastguard Worker
201*27162e4eSAndroid Build Coastguard Worker
fileCheck(const char * fileName,int clevel)202*27162e4eSAndroid Build Coastguard Worker static void fileCheck(const char* fileName, int clevel)
203*27162e4eSAndroid Build Coastguard Worker {
204*27162e4eSAndroid Build Coastguard Worker size_t const fileSize = getFileSize(fileName);
205*27162e4eSAndroid Build Coastguard Worker void* const buffer = malloc(fileSize + !fileSize /* avoid 0 */);
206*27162e4eSAndroid Build Coastguard Worker if (!buffer) {
207*27162e4eSAndroid Build Coastguard Worker MSG("not enough memory \n");
208*27162e4eSAndroid Build Coastguard Worker exit(4);
209*27162e4eSAndroid Build Coastguard Worker }
210*27162e4eSAndroid Build Coastguard Worker loadFile(buffer, fileName, fileSize);
211*27162e4eSAndroid Build Coastguard Worker roundTripCheck(buffer, fileSize, clevel);
212*27162e4eSAndroid Build Coastguard Worker free (buffer);
213*27162e4eSAndroid Build Coastguard Worker }
214*27162e4eSAndroid Build Coastguard Worker
215*27162e4eSAndroid Build Coastguard Worker
bad_usage(const char * exeName)216*27162e4eSAndroid Build Coastguard Worker int bad_usage(const char* exeName)
217*27162e4eSAndroid Build Coastguard Worker {
218*27162e4eSAndroid Build Coastguard Worker MSG(" \n");
219*27162e4eSAndroid Build Coastguard Worker MSG("bad usage: \n");
220*27162e4eSAndroid Build Coastguard Worker MSG(" \n");
221*27162e4eSAndroid Build Coastguard Worker MSG("%s [Options] fileName \n", exeName);
222*27162e4eSAndroid Build Coastguard Worker MSG(" \n");
223*27162e4eSAndroid Build Coastguard Worker MSG("Options: \n");
224*27162e4eSAndroid Build Coastguard Worker MSG("-# : use #=[0-9] compression level (default:0 == random) \n");
225*27162e4eSAndroid Build Coastguard Worker return 1;
226*27162e4eSAndroid Build Coastguard Worker }
227*27162e4eSAndroid Build Coastguard Worker
228*27162e4eSAndroid Build Coastguard Worker
main(int argCount,const char ** argv)229*27162e4eSAndroid Build Coastguard Worker int main(int argCount, const char** argv)
230*27162e4eSAndroid Build Coastguard Worker {
231*27162e4eSAndroid Build Coastguard Worker const char* const exeName = argv[0];
232*27162e4eSAndroid Build Coastguard Worker int argNb = 1;
233*27162e4eSAndroid Build Coastguard Worker int clevel = 0;
234*27162e4eSAndroid Build Coastguard Worker
235*27162e4eSAndroid Build Coastguard Worker assert(argCount >= 1);
236*27162e4eSAndroid Build Coastguard Worker if (argCount < 2) return bad_usage(exeName);
237*27162e4eSAndroid Build Coastguard Worker
238*27162e4eSAndroid Build Coastguard Worker if (argv[1][0] == '-') {
239*27162e4eSAndroid Build Coastguard Worker clevel = argv[1][1] - '0';
240*27162e4eSAndroid Build Coastguard Worker argNb = 2;
241*27162e4eSAndroid Build Coastguard Worker }
242*27162e4eSAndroid Build Coastguard Worker
243*27162e4eSAndroid Build Coastguard Worker if (argNb >= argCount) return bad_usage(exeName);
244*27162e4eSAndroid Build Coastguard Worker
245*27162e4eSAndroid Build Coastguard Worker fileCheck(argv[argNb], clevel);
246*27162e4eSAndroid Build Coastguard Worker MSG("no pb detected \n");
247*27162e4eSAndroid Build Coastguard Worker return 0;
248*27162e4eSAndroid Build Coastguard Worker }
249