contrib/fuzz/mpatch.cc
changeset 38246 46dcb9f14900
child 43809 51a99e09c54b
equal deleted inserted replaced
38245:f2e3196a34f9 38246:46dcb9f14900
       
     1 /*
       
     2  * mpatch.cc - fuzzer harness for mpatch.c
       
     3  *
       
     4  * Copyright 2018, Google Inc.
       
     5  *
       
     6  * This software may be used and distributed according to the terms of
       
     7  * the GNU General Public License, incorporated herein by reference.
       
     8  */
       
     9 #include <iostream>
       
    10 #include <memory>
       
    11 #include <stdint.h>
       
    12 #include <stdlib.h>
       
    13 #include <vector>
       
    14 
       
    15 #include "fuzzutil.h"
       
    16 
       
    17 // To avoid having too many OOMs from the fuzzer infrastructure, we'll
       
    18 // skip patch application if the resulting fulltext would be bigger
       
    19 // than 10MiB.
       
    20 #define MAX_OUTPUT_SIZE 10485760
       
    21 
       
    22 extern "C" {
       
    23 #include "bitmanipulation.h"
       
    24 #include "mpatch.h"
       
    25 
       
    26 struct mpatchbin {
       
    27 	std::unique_ptr<char[]> data;
       
    28 	size_t len;
       
    29 };
       
    30 
       
    31 static mpatch_flist *getitem(void *vbins, ssize_t pos)
       
    32 {
       
    33 	std::vector<mpatchbin> *bins = (std::vector<mpatchbin> *)vbins;
       
    34 	const mpatchbin &bin = bins->at(pos + 1);
       
    35 	struct mpatch_flist *res;
       
    36 	LOG(2) << "mpatch_decode " << bin.len << std::endl;
       
    37 	if (mpatch_decode(bin.data.get(), bin.len, &res) < 0)
       
    38 		return NULL;
       
    39 	return res;
       
    40 }
       
    41 
       
    42 // input format:
       
    43 // u8 number of inputs
       
    44 // one u16 for each input, its length
       
    45 // the inputs
       
    46 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
       
    47 {
       
    48 	if (!Size) {
       
    49 		return 0;
       
    50 	}
       
    51 	// First byte of data is how many texts we expect, first text
       
    52 	// being the base the rest being the deltas.
       
    53 	ssize_t numtexts = Data[0];
       
    54 	if (numtexts < 2) {
       
    55 		// No point if we don't have at least a base text and a delta...
       
    56 		return 0;
       
    57 	}
       
    58 	// Each text will be described by a byte for how long it
       
    59 	// should be, so give up if we don't have enough.
       
    60 	if ((Size - 1) < (numtexts * 2)) {
       
    61 		return 0;
       
    62 	}
       
    63 	size_t consumed = 1 + (numtexts * 2);
       
    64 	LOG(2) << "input contains " << Size << std::endl;
       
    65 	LOG(2) << numtexts << " texts, consuming " << consumed << std::endl;
       
    66 	std::vector<mpatchbin> bins;
       
    67 	bins.reserve(numtexts);
       
    68 	for (int i = 0; i < numtexts; ++i) {
       
    69 		mpatchbin bin;
       
    70 		size_t nthsize = getbeuint16((char *)Data + 1 + (2 * i));
       
    71 		LOG(2) << "text " << i << " is " << nthsize << std::endl;
       
    72 		char *start = (char *)Data + consumed;
       
    73 		consumed += nthsize;
       
    74 		if (consumed > Size) {
       
    75 			LOG(2) << "ran out of data, consumed " << consumed
       
    76 			       << " of " << Size << std::endl;
       
    77 			return 0;
       
    78 		}
       
    79 		bin.len = nthsize;
       
    80 		bin.data.reset(new char[nthsize]);
       
    81 		memcpy(bin.data.get(), start, nthsize);
       
    82 		bins.push_back(std::move(bin));
       
    83 	}
       
    84 	LOG(2) << "mpatch_flist" << std::endl;
       
    85 	struct mpatch_flist *patch =
       
    86 	    mpatch_fold(&bins, getitem, 0, numtexts - 1);
       
    87 	if (!patch) {
       
    88 		return 0;
       
    89 	}
       
    90 	LOG(2) << "mpatch_calcsize" << std::endl;
       
    91 	ssize_t outlen = mpatch_calcsize(bins[0].len, patch);
       
    92 	LOG(2) << "outlen " << outlen << std::endl;
       
    93 	if (outlen < 0 || outlen > MAX_OUTPUT_SIZE) {
       
    94 		goto cleanup;
       
    95 	}
       
    96 	{
       
    97 		char *dest = (char *)malloc(outlen);
       
    98 		LOG(2) << "expecting " << outlen << " total bytes at "
       
    99 		       << (void *)dest << std::endl;
       
   100 		mpatch_apply(dest, bins[0].data.get(), bins[0].len, patch);
       
   101 		free(dest);
       
   102 		LOG(1) << "applied a complete patch" << std::endl;
       
   103 	}
       
   104 cleanup:
       
   105 	mpatch_lfree(patch);
       
   106 	return 0;
       
   107 }
       
   108 
       
   109 #ifdef HG_FUZZER_INCLUDE_MAIN
       
   110 int main(int argc, char **argv)
       
   111 {
       
   112 	// One text, one patch.
       
   113 	const char data[] = "\x02\x00\0x1\x00\x0d"
       
   114 	                    // base text
       
   115 	                    "a"
       
   116 	                    // binary delta that will append a single b
       
   117 	                    "\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01b";
       
   118 	return LLVMFuzzerTestOneInput((const uint8_t *)data, 19);
       
   119 }
       
   120 #endif
       
   121 
       
   122 } // extern "C"