/src/mercurial/contrib/fuzz/mpatch.cc
Line | Count | Source (jump to first uncovered line) |
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 | | extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) |
18 | 16 | { |
19 | 16 | return 0; |
20 | 16 | } |
21 | | |
22 | | // To avoid having too many OOMs from the fuzzer infrastructure, we'll |
23 | | // skip patch application if the resulting fulltext would be bigger |
24 | | // than 10MiB. |
25 | 219 | #define MAX_OUTPUT_SIZE 10485760 |
26 | | |
27 | | extern "C" { |
28 | | #include "bitmanipulation.h" |
29 | | #include "mpatch.h" |
30 | | |
31 | | struct mpatchbin { |
32 | | std::unique_ptr<char[]> data; |
33 | | size_t len; |
34 | | }; |
35 | | |
36 | | static mpatch_flist *getitem(void *vbins, ssize_t pos) |
37 | 16.4k | { |
38 | 16.4k | std::vector<mpatchbin> *bins = (std::vector<mpatchbin> *)vbins; |
39 | 16.4k | const mpatchbin &bin = bins->at(pos + 1); |
40 | 16.4k | struct mpatch_flist *res; |
41 | 16.4k | LOG(2) << "mpatch_decode " << bin.len << std::endl; |
42 | 16.4k | if (mpatch_decode(bin.data.get(), bin.len, &res) < 0) |
43 | 1.72k | return NULL; |
44 | 14.7k | return res; |
45 | 16.4k | } |
46 | | |
47 | | // input format: |
48 | | // u8 number of inputs |
49 | | // one u16 for each input, its length |
50 | | // the inputs |
51 | | int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) |
52 | 1.97k | { |
53 | 1.97k | if (!Size) { |
54 | 0 | return 0; |
55 | 0 | } |
56 | | // First byte of data is how many texts we expect, first text |
57 | | // being the base the rest being the deltas. |
58 | 1.97k | ssize_t numtexts = Data[0]; |
59 | 1.97k | if (numtexts < 2) { |
60 | | // No point if we don't have at least a base text and a delta... |
61 | 2 | return 0; |
62 | 2 | } |
63 | | // Each text will be described by a byte for how long it |
64 | | // should be, so give up if we don't have enough. |
65 | 1.97k | if ((Size - 1) < (numtexts * 2)) { |
66 | 12 | return 0; |
67 | 12 | } |
68 | 1.96k | size_t consumed = 1 + (numtexts * 2); |
69 | 1.96k | LOG(2) << "input contains " << Size << std::endl; |
70 | 1.96k | LOG(2) << numtexts << " texts, consuming " << consumed << std::endl; |
71 | 1.96k | std::vector<mpatchbin> bins; |
72 | 1.96k | bins.reserve(numtexts); |
73 | 20.7k | for (int i = 0; i < numtexts; ++i) { |
74 | 18.8k | mpatchbin bin; |
75 | 18.8k | size_t nthsize = getbeuint16((char *)Data + 1 + (2 * i)); |
76 | 18.8k | LOG(2) << "text " << i << " is " << nthsize << std::endl; |
77 | 18.8k | char *start = (char *)Data + consumed; |
78 | 18.8k | consumed += nthsize; |
79 | 18.8k | if (consumed > Size) { |
80 | 53 | LOG(2) << "ran out of data, consumed " << consumed |
81 | 0 | << " of " << Size << std::endl; |
82 | 53 | return 0; |
83 | 53 | } |
84 | 18.7k | bin.len = nthsize; |
85 | 18.7k | bin.data.reset(new char[nthsize]); |
86 | 18.7k | memcpy(bin.data.get(), start, nthsize); |
87 | 18.7k | bins.push_back(std::move(bin)); |
88 | 18.7k | } |
89 | 1.91k | LOG(2) << "mpatch_flist" << std::endl; |
90 | 1.91k | struct mpatch_flist *patch = |
91 | 1.91k | mpatch_fold(&bins, getitem, 0, numtexts - 1); |
92 | 1.91k | if (!patch) { |
93 | 778 | return 0; |
94 | 778 | } |
95 | 1.13k | LOG(2) << "mpatch_calcsize" << std::endl; |
96 | 1.13k | ssize_t outlen = mpatch_calcsize(bins[0].len, patch); |
97 | 1.13k | LOG(2) << "outlen " << outlen << std::endl; |
98 | 1.13k | if (outlen < 0 || outlen > MAX_OUTPUT_SIZE) { |
99 | 913 | goto cleanup; |
100 | 913 | } |
101 | 219 | { |
102 | 219 | char *dest = (char *)malloc(outlen); |
103 | 219 | LOG(2) << "expecting " << outlen << " total bytes at " |
104 | 0 | << (void *)dest << std::endl; |
105 | 219 | mpatch_apply(dest, bins[0].data.get(), bins[0].len, patch); |
106 | 219 | free(dest); |
107 | 219 | LOG(1) << "applied a complete patch" << std::endl; |
108 | 219 | } |
109 | 1.13k | cleanup: |
110 | 1.13k | mpatch_lfree(patch); |
111 | 1.13k | return 0; |
112 | 219 | } |
113 | | |
114 | | } // extern "C" |