1 // This file is distributed under the University of Illinois Open Source
2 // License. See LICENSE.TXT for details.
3 
4 // Avoid ODR violations (LibFuzzer is built without ASan and this test is built
5 // with ASan) involving C++ standard library types when using libcxx.
6 #define _LIBCPP_HAS_NO_ASAN
7 
8 #include "FuzzerCorpus.h"
9 #include "FuzzerInternal.h"
10 #include "FuzzerDictionary.h"
11 #include "FuzzerMerge.h"
12 #include "FuzzerMutate.h"
13 #include "FuzzerRandom.h"
14 #include "gtest/gtest.h"
15 #include <memory>
16 #include <set>
17 
18 using namespace fuzzer;
19 
20 // For now, have LLVMFuzzerTestOneInput just to make it link.
21 // Later we may want to make unittests that actually call LLVMFuzzerTestOneInput.
LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)22 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
23   abort();
24 }
25 
TEST(Fuzzer, CrossOver)26 TEST(Fuzzer, CrossOver) {
27   std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
28   fuzzer::EF = t.get();
29   Random Rand(0);
30   MutationDispatcher MD(Rand, {});
31   Unit A({0, 1, 2}), B({5, 6, 7});
32   Unit C;
33   Unit Expected[] = {
34        { 0 },
35        { 0, 1 },
36        { 0, 5 },
37        { 0, 1, 2 },
38        { 0, 1, 5 },
39        { 0, 5, 1 },
40        { 0, 5, 6 },
41        { 0, 1, 2, 5 },
42        { 0, 1, 5, 2 },
43        { 0, 1, 5, 6 },
44        { 0, 5, 1, 2 },
45        { 0, 5, 1, 6 },
46        { 0, 5, 6, 1 },
47        { 0, 5, 6, 7 },
48        { 0, 1, 2, 5, 6 },
49        { 0, 1, 5, 2, 6 },
50        { 0, 1, 5, 6, 2 },
51        { 0, 1, 5, 6, 7 },
52        { 0, 5, 1, 2, 6 },
53        { 0, 5, 1, 6, 2 },
54        { 0, 5, 1, 6, 7 },
55        { 0, 5, 6, 1, 2 },
56        { 0, 5, 6, 1, 7 },
57        { 0, 5, 6, 7, 1 },
58        { 0, 1, 2, 5, 6, 7 },
59        { 0, 1, 5, 2, 6, 7 },
60        { 0, 1, 5, 6, 2, 7 },
61        { 0, 1, 5, 6, 7, 2 },
62        { 0, 5, 1, 2, 6, 7 },
63        { 0, 5, 1, 6, 2, 7 },
64        { 0, 5, 1, 6, 7, 2 },
65        { 0, 5, 6, 1, 2, 7 },
66        { 0, 5, 6, 1, 7, 2 },
67        { 0, 5, 6, 7, 1, 2 }
68   };
69   for (size_t Len = 1; Len < 8; Len++) {
70     std::set<Unit> FoundUnits, ExpectedUnitsWitThisLength;
71     for (int Iter = 0; Iter < 3000; Iter++) {
72       C.resize(Len);
73       size_t NewSize = MD.CrossOver(A.data(), A.size(), B.data(), B.size(),
74                                     C.data(), C.size());
75       C.resize(NewSize);
76       FoundUnits.insert(C);
77     }
78     for (const Unit &U : Expected)
79       if (U.size() <= Len)
80         ExpectedUnitsWitThisLength.insert(U);
81     EXPECT_EQ(ExpectedUnitsWitThisLength, FoundUnits);
82   }
83 }
84 
TEST(Fuzzer, Hash)85 TEST(Fuzzer, Hash) {
86   uint8_t A[] = {'a', 'b', 'c'};
87   fuzzer::Unit U(A, A + sizeof(A));
88   EXPECT_EQ("a9993e364706816aba3e25717850c26c9cd0d89d", fuzzer::Hash(U));
89   U.push_back('d');
90   EXPECT_EQ("81fe8bfe87576c3ecb22426f8e57847382917acf", fuzzer::Hash(U));
91 }
92 
93 typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size,
94                                               size_t MaxSize);
95 
TestEraseBytes(Mutator M, int NumIter)96 void TestEraseBytes(Mutator M, int NumIter) {
97   std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
98   fuzzer::EF = t.get();
99   uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
100   uint8_t REM1[8] = {0x00, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
101   uint8_t REM2[8] = {0x00, 0x11, 0x33, 0x44, 0x55, 0x66, 0x77};
102   uint8_t REM3[8] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x77};
103   uint8_t REM4[8] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x66, 0x77};
104   uint8_t REM5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x66, 0x77};
105   uint8_t REM6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x77};
106   uint8_t REM7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
107 
108   uint8_t REM8[6] = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
109   uint8_t REM9[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
110   uint8_t REM10[6] = {0x00, 0x11, 0x22, 0x55, 0x66, 0x77};
111 
112   uint8_t REM11[5] = {0x33, 0x44, 0x55, 0x66, 0x77};
113   uint8_t REM12[5] = {0x00, 0x11, 0x22, 0x33, 0x44};
114   uint8_t REM13[5] = {0x00, 0x44, 0x55, 0x66, 0x77};
115 
116 
117   Random Rand(0);
118   MutationDispatcher MD(Rand, {});
119   int FoundMask = 0;
120   for (int i = 0; i < NumIter; i++) {
121     uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
122     size_t NewSize = (MD.*M)(T, sizeof(T), sizeof(T));
123     if (NewSize == 7 && !memcmp(REM0, T, 7)) FoundMask |= 1 << 0;
124     if (NewSize == 7 && !memcmp(REM1, T, 7)) FoundMask |= 1 << 1;
125     if (NewSize == 7 && !memcmp(REM2, T, 7)) FoundMask |= 1 << 2;
126     if (NewSize == 7 && !memcmp(REM3, T, 7)) FoundMask |= 1 << 3;
127     if (NewSize == 7 && !memcmp(REM4, T, 7)) FoundMask |= 1 << 4;
128     if (NewSize == 7 && !memcmp(REM5, T, 7)) FoundMask |= 1 << 5;
129     if (NewSize == 7 && !memcmp(REM6, T, 7)) FoundMask |= 1 << 6;
130     if (NewSize == 7 && !memcmp(REM7, T, 7)) FoundMask |= 1 << 7;
131 
132     if (NewSize == 6 && !memcmp(REM8, T, 6)) FoundMask |= 1 << 8;
133     if (NewSize == 6 && !memcmp(REM9, T, 6)) FoundMask |= 1 << 9;
134     if (NewSize == 6 && !memcmp(REM10, T, 6)) FoundMask |= 1 << 10;
135 
136     if (NewSize == 5 && !memcmp(REM11, T, 5)) FoundMask |= 1 << 11;
137     if (NewSize == 5 && !memcmp(REM12, T, 5)) FoundMask |= 1 << 12;
138     if (NewSize == 5 && !memcmp(REM13, T, 5)) FoundMask |= 1 << 13;
139   }
140   EXPECT_EQ(FoundMask, (1 << 14) - 1);
141 }
142 
TEST(FuzzerMutate, EraseBytes1)143 TEST(FuzzerMutate, EraseBytes1) {
144   TestEraseBytes(&MutationDispatcher::Mutate_EraseBytes, 200);
145 }
TEST(FuzzerMutate, EraseBytes2)146 TEST(FuzzerMutate, EraseBytes2) {
147   TestEraseBytes(&MutationDispatcher::Mutate, 2000);
148 }
149 
TestInsertByte(Mutator M, int NumIter)150 void TestInsertByte(Mutator M, int NumIter) {
151   std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
152   fuzzer::EF = t.get();
153   Random Rand(0);
154   MutationDispatcher MD(Rand, {});
155   int FoundMask = 0;
156   uint8_t INS0[8] = {0xF1, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
157   uint8_t INS1[8] = {0x00, 0xF2, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
158   uint8_t INS2[8] = {0x00, 0x11, 0xF3, 0x22, 0x33, 0x44, 0x55, 0x66};
159   uint8_t INS3[8] = {0x00, 0x11, 0x22, 0xF4, 0x33, 0x44, 0x55, 0x66};
160   uint8_t INS4[8] = {0x00, 0x11, 0x22, 0x33, 0xF5, 0x44, 0x55, 0x66};
161   uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF6, 0x55, 0x66};
162   uint8_t INS6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF7, 0x66};
163   uint8_t INS7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF8};
164   for (int i = 0; i < NumIter; i++) {
165     uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
166     size_t NewSize = (MD.*M)(T, 7, 8);
167     if (NewSize == 8 && !memcmp(INS0, T, 8)) FoundMask |= 1 << 0;
168     if (NewSize == 8 && !memcmp(INS1, T, 8)) FoundMask |= 1 << 1;
169     if (NewSize == 8 && !memcmp(INS2, T, 8)) FoundMask |= 1 << 2;
170     if (NewSize == 8 && !memcmp(INS3, T, 8)) FoundMask |= 1 << 3;
171     if (NewSize == 8 && !memcmp(INS4, T, 8)) FoundMask |= 1 << 4;
172     if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5;
173     if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6;
174     if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7;
175   }
176   EXPECT_EQ(FoundMask, 255);
177 }
178 
TEST(FuzzerMutate, InsertByte1)179 TEST(FuzzerMutate, InsertByte1) {
180   TestInsertByte(&MutationDispatcher::Mutate_InsertByte, 1 << 15);
181 }
TEST(FuzzerMutate, InsertByte2)182 TEST(FuzzerMutate, InsertByte2) {
183   TestInsertByte(&MutationDispatcher::Mutate, 1 << 17);
184 }
185 
TestInsertRepeatedBytes(Mutator M, int NumIter)186 void TestInsertRepeatedBytes(Mutator M, int NumIter) {
187   std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
188   fuzzer::EF = t.get();
189   Random Rand(0);
190   MutationDispatcher MD(Rand, {});
191   int FoundMask = 0;
192   uint8_t INS0[7] = {0x00, 0x11, 0x22, 0x33, 'a', 'a', 'a'};
193   uint8_t INS1[7] = {0x00, 0x11, 0x22, 'a', 'a', 'a', 0x33};
194   uint8_t INS2[7] = {0x00, 0x11, 'a', 'a', 'a', 0x22, 0x33};
195   uint8_t INS3[7] = {0x00, 'a', 'a', 'a', 0x11, 0x22, 0x33};
196   uint8_t INS4[7] = {'a', 'a', 'a', 0x00, 0x11, 0x22, 0x33};
197 
198   uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 'b', 'b', 'b', 'b'};
199   uint8_t INS6[8] = {0x00, 0x11, 0x22, 'b', 'b', 'b', 'b', 0x33};
200   uint8_t INS7[8] = {0x00, 0x11, 'b', 'b', 'b', 'b', 0x22, 0x33};
201   uint8_t INS8[8] = {0x00, 'b', 'b', 'b', 'b', 0x11, 0x22, 0x33};
202   uint8_t INS9[8] = {'b', 'b', 'b', 'b', 0x00, 0x11, 0x22, 0x33};
203 
204   for (int i = 0; i < NumIter; i++) {
205     uint8_t T[8] = {0x00, 0x11, 0x22, 0x33};
206     size_t NewSize = (MD.*M)(T, 4, 8);
207     if (NewSize == 7 && !memcmp(INS0, T, 7)) FoundMask |= 1 << 0;
208     if (NewSize == 7 && !memcmp(INS1, T, 7)) FoundMask |= 1 << 1;
209     if (NewSize == 7 && !memcmp(INS2, T, 7)) FoundMask |= 1 << 2;
210     if (NewSize == 7 && !memcmp(INS3, T, 7)) FoundMask |= 1 << 3;
211     if (NewSize == 7 && !memcmp(INS4, T, 7)) FoundMask |= 1 << 4;
212 
213     if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5;
214     if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6;
215     if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7;
216     if (NewSize == 8 && !memcmp(INS8, T, 8)) FoundMask |= 1 << 8;
217     if (NewSize == 8 && !memcmp(INS9, T, 8)) FoundMask |= 1 << 9;
218 
219   }
220   EXPECT_EQ(FoundMask, (1 << 10) - 1);
221 }
222 
TEST(FuzzerMutate, InsertRepeatedBytes1)223 TEST(FuzzerMutate, InsertRepeatedBytes1) {
224   TestInsertRepeatedBytes(&MutationDispatcher::Mutate_InsertRepeatedBytes, 10000);
225 }
TEST(FuzzerMutate, InsertRepeatedBytes2)226 TEST(FuzzerMutate, InsertRepeatedBytes2) {
227   TestInsertRepeatedBytes(&MutationDispatcher::Mutate, 300000);
228 }
229 
TestChangeByte(Mutator M, int NumIter)230 void TestChangeByte(Mutator M, int NumIter) {
231   std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
232   fuzzer::EF = t.get();
233   Random Rand(0);
234   MutationDispatcher MD(Rand, {});
235   int FoundMask = 0;
236   uint8_t CH0[8] = {0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
237   uint8_t CH1[8] = {0x00, 0xF1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
238   uint8_t CH2[8] = {0x00, 0x11, 0xF2, 0x33, 0x44, 0x55, 0x66, 0x77};
239   uint8_t CH3[8] = {0x00, 0x11, 0x22, 0xF3, 0x44, 0x55, 0x66, 0x77};
240   uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0xF4, 0x55, 0x66, 0x77};
241   uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF5, 0x66, 0x77};
242   uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF5, 0x77};
243   uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7};
244   for (int i = 0; i < NumIter; i++) {
245     uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
246     size_t NewSize = (MD.*M)(T, 8, 9);
247     if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
248     if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
249     if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
250     if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
251     if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4;
252     if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
253     if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
254     if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
255   }
256   EXPECT_EQ(FoundMask, 255);
257 }
258 
TEST(FuzzerMutate, ChangeByte1)259 TEST(FuzzerMutate, ChangeByte1) {
260   TestChangeByte(&MutationDispatcher::Mutate_ChangeByte, 1 << 15);
261 }
TEST(FuzzerMutate, ChangeByte2)262 TEST(FuzzerMutate, ChangeByte2) {
263   TestChangeByte(&MutationDispatcher::Mutate, 1 << 17);
264 }
265 
TestChangeBit(Mutator M, int NumIter)266 void TestChangeBit(Mutator M, int NumIter) {
267   std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
268   fuzzer::EF = t.get();
269   Random Rand(0);
270   MutationDispatcher MD(Rand, {});
271   int FoundMask = 0;
272   uint8_t CH0[8] = {0x01, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
273   uint8_t CH1[8] = {0x00, 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
274   uint8_t CH2[8] = {0x00, 0x11, 0x02, 0x33, 0x44, 0x55, 0x66, 0x77};
275   uint8_t CH3[8] = {0x00, 0x11, 0x22, 0x37, 0x44, 0x55, 0x66, 0x77};
276   uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x54, 0x55, 0x66, 0x77};
277   uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x54, 0x66, 0x77};
278   uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x76, 0x77};
279   uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7};
280   for (int i = 0; i < NumIter; i++) {
281     uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
282     size_t NewSize = (MD.*M)(T, 8, 9);
283     if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
284     if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
285     if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
286     if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
287     if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4;
288     if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
289     if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
290     if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
291   }
292   EXPECT_EQ(FoundMask, 255);
293 }
294 
TEST(FuzzerMutate, ChangeBit1)295 TEST(FuzzerMutate, ChangeBit1) {
296   TestChangeBit(&MutationDispatcher::Mutate_ChangeBit, 1 << 16);
297 }
TEST(FuzzerMutate, ChangeBit2)298 TEST(FuzzerMutate, ChangeBit2) {
299   TestChangeBit(&MutationDispatcher::Mutate, 1 << 18);
300 }
301 
TestShuffleBytes(Mutator M, int NumIter)302 void TestShuffleBytes(Mutator M, int NumIter) {
303   std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
304   fuzzer::EF = t.get();
305   Random Rand(0);
306   MutationDispatcher MD(Rand, {});
307   int FoundMask = 0;
308   uint8_t CH0[7] = {0x00, 0x22, 0x11, 0x33, 0x44, 0x55, 0x66};
309   uint8_t CH1[7] = {0x11, 0x00, 0x33, 0x22, 0x44, 0x55, 0x66};
310   uint8_t CH2[7] = {0x00, 0x33, 0x11, 0x22, 0x44, 0x55, 0x66};
311   uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x33};
312   uint8_t CH4[7] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x44, 0x66};
313   for (int i = 0; i < NumIter; i++) {
314     uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
315     size_t NewSize = (MD.*M)(T, 7, 7);
316     if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0;
317     if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1;
318     if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2;
319     if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3;
320     if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4;
321   }
322   EXPECT_EQ(FoundMask, 31);
323 }
324 
TEST(FuzzerMutate, ShuffleBytes1)325 TEST(FuzzerMutate, ShuffleBytes1) {
326   TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 16);
327 }
TEST(FuzzerMutate, ShuffleBytes2)328 TEST(FuzzerMutate, ShuffleBytes2) {
329   TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 20);
330 }
331 
TestCopyPart(Mutator M, int NumIter)332 void TestCopyPart(Mutator M, int NumIter) {
333   std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
334   fuzzer::EF = t.get();
335   Random Rand(0);
336   MutationDispatcher MD(Rand, {});
337   int FoundMask = 0;
338   uint8_t CH0[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11};
339   uint8_t CH1[7] = {0x55, 0x66, 0x22, 0x33, 0x44, 0x55, 0x66};
340   uint8_t CH2[7] = {0x00, 0x55, 0x66, 0x33, 0x44, 0x55, 0x66};
341   uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x66};
342   uint8_t CH4[7] = {0x00, 0x11, 0x11, 0x22, 0x33, 0x55, 0x66};
343 
344   for (int i = 0; i < NumIter; i++) {
345     uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
346     size_t NewSize = (MD.*M)(T, 7, 7);
347     if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0;
348     if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1;
349     if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2;
350     if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3;
351     if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4;
352   }
353 
354   uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11, 0x22};
355   uint8_t CH6[8] = {0x22, 0x33, 0x44, 0x00, 0x11, 0x22, 0x33, 0x44};
356   uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x33, 0x44};
357   uint8_t CH8[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x22, 0x33, 0x44};
358   uint8_t CH9[8] = {0x00, 0x11, 0x22, 0x22, 0x33, 0x44, 0x33, 0x44};
359 
360   for (int i = 0; i < NumIter; i++) {
361     uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
362     size_t NewSize = (MD.*M)(T, 5, 8);
363     if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
364     if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
365     if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
366     if (NewSize == 8 && !memcmp(CH8, T, 8)) FoundMask |= 1 << 8;
367     if (NewSize == 8 && !memcmp(CH9, T, 8)) FoundMask |= 1 << 9;
368   }
369 
370   EXPECT_EQ(FoundMask, 1023);
371 }
372 
TEST(FuzzerMutate, CopyPart1)373 TEST(FuzzerMutate, CopyPart1) {
374   TestCopyPart(&MutationDispatcher::Mutate_CopyPart, 1 << 10);
375 }
TEST(FuzzerMutate, CopyPart2)376 TEST(FuzzerMutate, CopyPart2) {
377   TestCopyPart(&MutationDispatcher::Mutate, 1 << 13);
378 }
379 
TestAddWordFromDictionary(Mutator M, int NumIter)380 void TestAddWordFromDictionary(Mutator M, int NumIter) {
381   std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
382   fuzzer::EF = t.get();
383   Random Rand(0);
384   MutationDispatcher MD(Rand, {});
385   uint8_t Word1[4] = {0xAA, 0xBB, 0xCC, 0xDD};
386   uint8_t Word2[3] = {0xFF, 0xEE, 0xEF};
387   MD.AddWordToManualDictionary(Word(Word1, sizeof(Word1)));
388   MD.AddWordToManualDictionary(Word(Word2, sizeof(Word2)));
389   int FoundMask = 0;
390   uint8_t CH0[7] = {0x00, 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD};
391   uint8_t CH1[7] = {0x00, 0x11, 0xAA, 0xBB, 0xCC, 0xDD, 0x22};
392   uint8_t CH2[7] = {0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22};
393   uint8_t CH3[7] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x11, 0x22};
394   uint8_t CH4[6] = {0x00, 0x11, 0x22, 0xFF, 0xEE, 0xEF};
395   uint8_t CH5[6] = {0x00, 0x11, 0xFF, 0xEE, 0xEF, 0x22};
396   uint8_t CH6[6] = {0x00, 0xFF, 0xEE, 0xEF, 0x11, 0x22};
397   uint8_t CH7[6] = {0xFF, 0xEE, 0xEF, 0x00, 0x11, 0x22};
398   for (int i = 0; i < NumIter; i++) {
399     uint8_t T[7] = {0x00, 0x11, 0x22};
400     size_t NewSize = (MD.*M)(T, 3, 7);
401     if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0;
402     if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1;
403     if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2;
404     if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3;
405     if (NewSize == 6 && !memcmp(CH4, T, 6)) FoundMask |= 1 << 4;
406     if (NewSize == 6 && !memcmp(CH5, T, 6)) FoundMask |= 1 << 5;
407     if (NewSize == 6 && !memcmp(CH6, T, 6)) FoundMask |= 1 << 6;
408     if (NewSize == 6 && !memcmp(CH7, T, 6)) FoundMask |= 1 << 7;
409   }
410   EXPECT_EQ(FoundMask, 255);
411 }
412 
TEST(FuzzerMutate, AddWordFromDictionary1)413 TEST(FuzzerMutate, AddWordFromDictionary1) {
414   TestAddWordFromDictionary(
415       &MutationDispatcher::Mutate_AddWordFromManualDictionary, 1 << 15);
416 }
417 
TEST(FuzzerMutate, AddWordFromDictionary2)418 TEST(FuzzerMutate, AddWordFromDictionary2) {
419   TestAddWordFromDictionary(&MutationDispatcher::Mutate, 1 << 15);
420 }
421 
TestAddWordFromDictionaryWithHint(Mutator M, int NumIter)422 void TestAddWordFromDictionaryWithHint(Mutator M, int NumIter) {
423   std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
424   fuzzer::EF = t.get();
425   Random Rand(0);
426   MutationDispatcher MD(Rand, {});
427   uint8_t W[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xFF, 0xEE, 0xEF};
428   size_t PosHint = 7777;
429   MD.AddWordToAutoDictionary({Word(W, sizeof(W)), PosHint});
430   int FoundMask = 0;
431   for (int i = 0; i < NumIter; i++) {
432     uint8_t T[10000];
433     memset(T, 0, sizeof(T));
434     size_t NewSize = (MD.*M)(T, 9000, 10000);
435     if (NewSize >= PosHint + sizeof(W) &&
436         !memcmp(W, T + PosHint, sizeof(W)))
437       FoundMask = 1;
438   }
439   EXPECT_EQ(FoundMask, 1);
440 }
441 
TEST(FuzzerMutate, AddWordFromDictionaryWithHint1)442 TEST(FuzzerMutate, AddWordFromDictionaryWithHint1) {
443   TestAddWordFromDictionaryWithHint(
444       &MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary, 1 << 5);
445 }
446 
TEST(FuzzerMutate, AddWordFromDictionaryWithHint2)447 TEST(FuzzerMutate, AddWordFromDictionaryWithHint2) {
448   TestAddWordFromDictionaryWithHint(&MutationDispatcher::Mutate, 1 << 10);
449 }
450 
TestChangeASCIIInteger(Mutator M, int NumIter)451 void TestChangeASCIIInteger(Mutator M, int NumIter) {
452   std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
453   fuzzer::EF = t.get();
454   Random Rand(0);
455   MutationDispatcher MD(Rand, {});
456 
457   uint8_t CH0[8] = {'1', '2', '3', '4', '5', '6', '7', '7'};
458   uint8_t CH1[8] = {'1', '2', '3', '4', '5', '6', '7', '9'};
459   uint8_t CH2[8] = {'2', '4', '6', '9', '1', '3', '5', '6'};
460   uint8_t CH3[8] = {'0', '6', '1', '7', '2', '8', '3', '9'};
461   int FoundMask = 0;
462   for (int i = 0; i < NumIter; i++) {
463     uint8_t T[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
464     size_t NewSize = (MD.*M)(T, 8, 8);
465     /**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
466     else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
467     else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
468     else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
469     else if (NewSize == 8)                       FoundMask |= 1 << 4;
470   }
471   EXPECT_EQ(FoundMask, 31);
472 }
473 
TEST(FuzzerMutate, ChangeASCIIInteger1)474 TEST(FuzzerMutate, ChangeASCIIInteger1) {
475   TestChangeASCIIInteger(&MutationDispatcher::Mutate_ChangeASCIIInteger,
476                          1 << 15);
477 }
478 
TEST(FuzzerMutate, ChangeASCIIInteger2)479 TEST(FuzzerMutate, ChangeASCIIInteger2) {
480   TestChangeASCIIInteger(&MutationDispatcher::Mutate, 1 << 15);
481 }
482 
TestChangeBinaryInteger(Mutator M, int NumIter)483 void TestChangeBinaryInteger(Mutator M, int NumIter) {
484   std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
485   fuzzer::EF = t.get();
486   Random Rand(0);
487   MutationDispatcher MD(Rand, {});
488 
489   uint8_t CH0[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x79};
490   uint8_t CH1[8] = {0x00, 0x11, 0x22, 0x31, 0x44, 0x55, 0x66, 0x77};
491   uint8_t CH2[8] = {0xff, 0x10, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
492   uint8_t CH3[8] = {0x00, 0x11, 0x2a, 0x33, 0x44, 0x55, 0x66, 0x77};
493   uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x4f, 0x66, 0x77};
494   uint8_t CH5[8] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88};
495   uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x00, 0x00, 0x00, 0x08, 0x77}; // Size
496   uint8_t CH7[8] = {0x00, 0x08, 0x00, 0x33, 0x44, 0x55, 0x66, 0x77}; // Sw(Size)
497 
498   int FoundMask = 0;
499   for (int i = 0; i < NumIter; i++) {
500     uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
501     size_t NewSize = (MD.*M)(T, 8, 8);
502     /**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
503     else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
504     else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
505     else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
506     else if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4;
507     else if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
508     else if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
509     else if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
510   }
511   EXPECT_EQ(FoundMask, 255);
512 }
513 
TEST(FuzzerMutate, ChangeBinaryInteger1)514 TEST(FuzzerMutate, ChangeBinaryInteger1) {
515   TestChangeBinaryInteger(&MutationDispatcher::Mutate_ChangeBinaryInteger,
516                          1 << 12);
517 }
518 
TEST(FuzzerMutate, ChangeBinaryInteger2)519 TEST(FuzzerMutate, ChangeBinaryInteger2) {
520   TestChangeBinaryInteger(&MutationDispatcher::Mutate, 1 << 15);
521 }
522 
523 
TEST(FuzzerDictionary, ParseOneDictionaryEntry)524 TEST(FuzzerDictionary, ParseOneDictionaryEntry) {
525   Unit U;
526   EXPECT_FALSE(ParseOneDictionaryEntry("", &U));
527   EXPECT_FALSE(ParseOneDictionaryEntry(" ", &U));
528   EXPECT_FALSE(ParseOneDictionaryEntry("\t  ", &U));
529   EXPECT_FALSE(ParseOneDictionaryEntry("  \" ", &U));
530   EXPECT_FALSE(ParseOneDictionaryEntry("  zz\" ", &U));
531   EXPECT_FALSE(ParseOneDictionaryEntry("  \"zz ", &U));
532   EXPECT_FALSE(ParseOneDictionaryEntry("  \"\" ", &U));
533   EXPECT_TRUE(ParseOneDictionaryEntry("\"a\"", &U));
534   EXPECT_EQ(U, Unit({'a'}));
535   EXPECT_TRUE(ParseOneDictionaryEntry("\"abc\"", &U));
536   EXPECT_EQ(U, Unit({'a', 'b', 'c'}));
537   EXPECT_TRUE(ParseOneDictionaryEntry("abc=\"abc\"", &U));
538   EXPECT_EQ(U, Unit({'a', 'b', 'c'}));
539   EXPECT_FALSE(ParseOneDictionaryEntry("\"\\\"", &U));
540   EXPECT_TRUE(ParseOneDictionaryEntry("\"\\\\\"", &U));
541   EXPECT_EQ(U, Unit({'\\'}));
542   EXPECT_TRUE(ParseOneDictionaryEntry("\"\\xAB\"", &U));
543   EXPECT_EQ(U, Unit({0xAB}));
544   EXPECT_TRUE(ParseOneDictionaryEntry("\"\\xABz\\xDE\"", &U));
545   EXPECT_EQ(U, Unit({0xAB, 'z', 0xDE}));
546   EXPECT_TRUE(ParseOneDictionaryEntry("\"#\"", &U));
547   EXPECT_EQ(U, Unit({'#'}));
548   EXPECT_TRUE(ParseOneDictionaryEntry("\"\\\"\"", &U));
549   EXPECT_EQ(U, Unit({'"'}));
550 }
551 
TEST(FuzzerDictionary, ParseDictionaryFile)552 TEST(FuzzerDictionary, ParseDictionaryFile) {
553   std::vector<Unit> Units;
554   EXPECT_FALSE(ParseDictionaryFile("zzz\n", &Units));
555   EXPECT_FALSE(ParseDictionaryFile("", &Units));
556   EXPECT_TRUE(ParseDictionaryFile("\n", &Units));
557   EXPECT_EQ(Units.size(), 0U);
558   EXPECT_TRUE(ParseDictionaryFile("#zzzz a b c d\n", &Units));
559   EXPECT_EQ(Units.size(), 0U);
560   EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units));
561   EXPECT_EQ(Units.size(), 0U);
562   EXPECT_TRUE(ParseDictionaryFile("  #zzzz\n", &Units));
563   EXPECT_EQ(Units.size(), 0U);
564   EXPECT_TRUE(ParseDictionaryFile("  #zzzz\naaa=\"aa\"", &Units));
565   EXPECT_EQ(Units, std::vector<Unit>({Unit({'a', 'a'})}));
566   EXPECT_TRUE(
567       ParseDictionaryFile("  #zzzz\naaa=\"aa\"\n\nabc=\"abc\"", &Units));
568   EXPECT_EQ(Units,
569             std::vector<Unit>({Unit({'a', 'a'}), Unit({'a', 'b', 'c'})}));
570 }
571 
TEST(FuzzerUtil, Base64)572 TEST(FuzzerUtil, Base64) {
573   EXPECT_EQ("", Base64({}));
574   EXPECT_EQ("YQ==", Base64({'a'}));
575   EXPECT_EQ("eA==", Base64({'x'}));
576   EXPECT_EQ("YWI=", Base64({'a', 'b'}));
577   EXPECT_EQ("eHk=", Base64({'x', 'y'}));
578   EXPECT_EQ("YWJj", Base64({'a', 'b', 'c'}));
579   EXPECT_EQ("eHl6", Base64({'x', 'y', 'z'}));
580   EXPECT_EQ("YWJjeA==", Base64({'a', 'b', 'c', 'x'}));
581   EXPECT_EQ("YWJjeHk=", Base64({'a', 'b', 'c', 'x', 'y'}));
582   EXPECT_EQ("YWJjeHl6", Base64({'a', 'b', 'c', 'x', 'y', 'z'}));
583 }
584 
TEST(Corpus, Distribution)585 TEST(Corpus, Distribution) {
586   Random Rand(0);
587   InputCorpus C("");
588   size_t N = 10;
589   size_t TriesPerUnit = 1<<16;
590   for (size_t i = 0; i < N; i++)
591     C.AddToCorpus(Unit{ static_cast<uint8_t>(i) }, 0);
592 
593   std::vector<size_t> Hist(N);
594   for (size_t i = 0; i < N * TriesPerUnit; i++) {
595     Hist[C.ChooseUnitIdxToMutate(Rand)]++;
596   }
597   for (size_t i = 0; i < N; i++) {
598     // A weak sanity check that every unit gets invoked.
599     EXPECT_GT(Hist[i], TriesPerUnit / N / 3);
600   }
601 }
602 
TEST(Merge, Bad)603 TEST(Merge, Bad) {
604   const char *kInvalidInputs[] = {
605     "",
606     "x",
607     "3\nx",
608     "2\n3",
609     "2\n2",
610     "2\n2\nA\n",
611     "2\n2\nA\nB\nC\n",
612     "0\n0\n",
613     "1\n1\nA\nDONE 0",
614     "1\n1\nA\nSTARTED 1",
615   };
616   Merger M;
617   for (auto S : kInvalidInputs) {
618     // fprintf(stderr, "TESTING:\n%s\n", S);
619     EXPECT_FALSE(M.Parse(S, false));
620   }
621 }
622 
EQ(const std::vector<uint32_t> &A, const std::vector<uint32_t> &B)623 void EQ(const std::vector<uint32_t> &A, const std::vector<uint32_t> &B) {
624   EXPECT_EQ(A, B);
625 }
626 
EQ(const std::vector<std::string> &A, const std::vector<std::string> &B)627 void EQ(const std::vector<std::string> &A, const std::vector<std::string> &B) {
628   std::set<std::string> a(A.begin(), A.end());
629   std::set<std::string> b(B.begin(), B.end());
630   EXPECT_EQ(a, b);
631 }
632 
Merge(const std::string &Input, const std::vector<std::string> Result, size_t NumNewFeatures)633 static void Merge(const std::string &Input,
634                   const std::vector<std::string> Result,
635                   size_t NumNewFeatures) {
636   Merger M;
637   std::vector<std::string> NewFiles;
638   EXPECT_TRUE(M.Parse(Input, true));
639   EXPECT_EQ(NumNewFeatures, M.Merge(&NewFiles));
640   EQ(NewFiles, Result);
641 }
642 
TEST(Merge, Good)643 TEST(Merge, Good) {
644   Merger M;
645 
646   EXPECT_TRUE(M.Parse("1\n0\nAA\n", false));
647   EXPECT_EQ(M.Files.size(), 1U);
648   EXPECT_EQ(M.NumFilesInFirstCorpus, 0U);
649   EXPECT_EQ(M.Files[0].Name, "AA");
650   EXPECT_TRUE(M.LastFailure.empty());
651   EXPECT_EQ(M.FirstNotProcessedFile, 0U);
652 
653   EXPECT_TRUE(M.Parse("2\n1\nAA\nBB\nSTARTED 0 42\n", false));
654   EXPECT_EQ(M.Files.size(), 2U);
655   EXPECT_EQ(M.NumFilesInFirstCorpus, 1U);
656   EXPECT_EQ(M.Files[0].Name, "AA");
657   EXPECT_EQ(M.Files[1].Name, "BB");
658   EXPECT_EQ(M.LastFailure, "AA");
659   EXPECT_EQ(M.FirstNotProcessedFile, 1U);
660 
661   EXPECT_TRUE(M.Parse("3\n1\nAA\nBB\nC\n"
662                         "STARTED 0 1000\n"
663                         "DONE 0 1 2 3\n"
664                         "STARTED 1 1001\n"
665                         "DONE 1 4 5 6 \n"
666                         "STARTED 2 1002\n"
667                         "", true));
668   EXPECT_EQ(M.Files.size(), 3U);
669   EXPECT_EQ(M.NumFilesInFirstCorpus, 1U);
670   EXPECT_EQ(M.Files[0].Name, "AA");
671   EXPECT_EQ(M.Files[0].Size, 1000U);
672   EXPECT_EQ(M.Files[1].Name, "BB");
673   EXPECT_EQ(M.Files[1].Size, 1001U);
674   EXPECT_EQ(M.Files[2].Name, "C");
675   EXPECT_EQ(M.Files[2].Size, 1002U);
676   EXPECT_EQ(M.LastFailure, "C");
677   EXPECT_EQ(M.FirstNotProcessedFile, 3U);
678   EQ(M.Files[0].Features, {1, 2, 3});
679   EQ(M.Files[1].Features, {4, 5, 6});
680 
681 
682   std::vector<std::string> NewFiles;
683 
684   EXPECT_TRUE(M.Parse("3\n2\nAA\nBB\nC\n"
685                         "STARTED 0 1000\nDONE 0 1 2 3\n"
686                         "STARTED 1 1001\nDONE 1 4 5 6 \n"
687                         "STARTED 2 1002\nDONE 2 6 1 3 \n"
688                         "", true));
689   EXPECT_EQ(M.Files.size(), 3U);
690   EXPECT_EQ(M.NumFilesInFirstCorpus, 2U);
691   EXPECT_TRUE(M.LastFailure.empty());
692   EXPECT_EQ(M.FirstNotProcessedFile, 3U);
693   EQ(M.Files[0].Features, {1, 2, 3});
694   EQ(M.Files[1].Features, {4, 5, 6});
695   EQ(M.Files[2].Features, {1, 3, 6});
696   EXPECT_EQ(0U, M.Merge(&NewFiles));
697   EQ(NewFiles, {});
698 
699   EXPECT_TRUE(M.Parse("3\n1\nA\nB\nC\n"
700                         "STARTED 0 1000\nDONE 0 1 2 3\n"
701                         "STARTED 1 1001\nDONE 1 4 5 6 \n"
702                         "STARTED 2 1002\nDONE 2 6 1 3\n"
703                         "", true));
704   EQ(M.Files[0].Features, {1, 2, 3});
705   EQ(M.Files[1].Features, {4, 5, 6});
706   EQ(M.Files[2].Features, {1, 3, 6});
707   EXPECT_EQ(3U, M.Merge(&NewFiles));
708   EQ(NewFiles, {"B"});
709 }
710 
TEST(Merge, Merge)711 TEST(Merge, Merge) {
712 
713   Merge("3\n1\nA\nB\nC\n"
714         "STARTED 0 1000\nDONE 0 1 2 3\n"
715         "STARTED 1 1001\nDONE 1 4 5 6 \n"
716         "STARTED 2 1002\nDONE 2 6 1 3 \n",
717         {"B"}, 3);
718 
719   Merge("3\n0\nA\nB\nC\n"
720         "STARTED 0 2000\nDONE 0 1 2 3\n"
721         "STARTED 1 1001\nDONE 1 4 5 6 \n"
722         "STARTED 2 1002\nDONE 2 6 1 3 \n",
723         {"A", "B", "C"}, 6);
724 
725   Merge("4\n0\nA\nB\nC\nD\n"
726         "STARTED 0 2000\nDONE 0 1 2 3\n"
727         "STARTED 1 1101\nDONE 1 4 5 6 \n"
728         "STARTED 2 1102\nDONE 2 6 1 3 100 \n"
729         "STARTED 3 1000\nDONE 3 1  \n",
730         {"A", "B", "C", "D"}, 7);
731 
732   Merge("4\n1\nA\nB\nC\nD\n"
733         "STARTED 0 2000\nDONE 0 4 5 6 7 8\n"
734         "STARTED 1 1100\nDONE 1 1 2 3 \n"
735         "STARTED 2 1100\nDONE 2 2 3 \n"
736         "STARTED 3 1000\nDONE 3 1  \n",
737         {"B", "D"}, 3);
738 }
739