OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "Fuzz.h" | 8 #include "Fuzz.h" |
9 #include "SkCanvas.h" | 9 #include "SkCanvas.h" |
10 #include "SkCodec.h" | 10 #include "SkCodec.h" |
11 #include "SkCommandLineFlags.h" | 11 #include "SkCommandLineFlags.h" |
12 #include "SkData.h" | 12 #include "SkData.h" |
13 #include "SkForceLinking.h" | 13 #include "SkForceLinking.h" |
14 #include "SkImage.h" | 14 #include "SkImage.h" |
15 #include "SkImageEncoder.h" | 15 #include "SkImageEncoder.h" |
16 #include "SkMallocPixelRef.h" | 16 #include "SkMallocPixelRef.h" |
17 #include "SkPicture.h" | 17 #include "SkPicture.h" |
18 #include "SkStream.h" | 18 #include "SkStream.h" |
19 | 19 |
20 #include <signal.h> | 20 #include <signal.h> |
21 #include <stdlib.h> | 21 #include <stdlib.h> |
22 | 22 |
23 __SK_FORCE_IMAGE_DECODER_LINKING; | 23 __SK_FORCE_IMAGE_DECODER_LINKING; |
scroggo
2016/02/16 19:17:38
Note to self: We can remove this once we switch SK
kjlubick
2016/02/16 19:55:13
I added a TODO
| |
24 | 24 |
25 DEFINE_string2(bytes, b, "", "A path to a file. This can be the fuzz bytes or a binary to parse."); | 25 DEFINE_string2(bytes, b, "", "A path to a file. This can be the fuzz bytes or a binary to parse."); |
26 DEFINE_string2(name, n, "", "If --type is 'api', fuzz the API with this name."); | 26 DEFINE_string2(name, n, "", "If --type is 'api', fuzz the API with this name."); |
27 | 27 |
28 DEFINE_string2(type, t, "api", "How to interpret --bytes, either 'image', 'skp', or 'api'."); | 28 DEFINE_string2(type, t, "api", "How to interpret --bytes, either 'image_scale', 'image_mode', 'skp', or 'api'."); |
29 DEFINE_string2(dump, d, "", "If not empty, dump 'image' or 'skp' types as a PNG with this name."); | 29 DEFINE_string2(dump, d, "", "If not empty, dump 'image*' or 'skp' types as a PNG with this name."); |
30 | 30 |
31 static int printUsage(const char* name) { | 31 static int printUsage(const char* name) { |
32 SkDebugf("Usage: %s -t <type> -b <path/to/file> [-n api-to-fuzz]\n", name); | 32 SkDebugf("Usage: %s -t <type> -b <path/to/file> [-n api-to-fuzz]\n", name); |
33 return 1; | 33 return 1; |
34 } | 34 } |
35 static uint8_t calculateMulti(SkData*); | |
scroggo
2016/02/16 19:17:38
nit: Typically we name static functions as
calcul
kjlubick
2016/02/16 19:55:13
Done. option seems a bit better.
| |
35 | 36 |
36 static int fuzz_api(SkData*); | 37 static int fuzz_api(SkData*); |
37 static int fuzz_img(SkData*); | 38 static int fuzz_img(SkData*, uint8_t, uint8_t); |
38 static int fuzz_skp(SkData*); | 39 static int fuzz_skp(SkData*); |
39 | 40 |
40 int main(int argc, char** argv) { | 41 int main(int argc, char** argv) { |
41 SkCommandLineFlags::Parse(argc, argv); | 42 SkCommandLineFlags::Parse(argc, argv); |
42 | 43 |
43 const char* path = FLAGS_bytes.isEmpty() ? argv[0] : FLAGS_bytes[0]; | 44 const char* path = FLAGS_bytes.isEmpty() ? argv[0] : FLAGS_bytes[0]; |
44 SkAutoTUnref<SkData> bytes(SkData::NewFromFileName(path)); | 45 SkAutoTUnref<SkData> bytes(SkData::NewFromFileName(path)); |
45 if (!bytes) { | 46 if (!bytes) { |
46 SkDebugf("Could not read %s\n", path); | 47 SkDebugf("Could not read %s\n", path); |
47 return 2; | 48 return 2; |
48 } | 49 } |
49 | 50 |
51 uint8_t multi = calculateMulti(bytes); | |
52 | |
50 if (!FLAGS_type.isEmpty()) { | 53 if (!FLAGS_type.isEmpty()) { |
51 switch (FLAGS_type[0][0]) { | 54 switch (FLAGS_type[0][0]) { |
52 case 'a': return fuzz_api(bytes); | 55 case 'a': return fuzz_api(bytes); |
53 case 'i': return fuzz_img(bytes); | 56 // We only allow one degree of freedom to avoid a search space explo sion for afl-fuzz. |
57 case 'i': return fuzz_img(bytes, strcmp(FLAGS_type[0], "image_scale" ) != 0 ? 0: multi, strcmp(FLAGS_type[0], "image_mode") != 0 ? 0: multi); | |
scroggo
2016/02/16 19:17:38
Split this up over multiple lines?
kjlubick
2016/02/16 19:55:13
Done.
| |
54 case 's': return fuzz_skp(bytes); | 58 case 's': return fuzz_skp(bytes); |
55 } | 59 } |
56 } | 60 } |
57 return printUsage(argv[0]); | 61 return printUsage(argv[0]); |
58 } | 62 } |
59 | 63 |
64 // This adds up the first 1024 bytes and returns it as an 8 bit integer. This a llows afl-fuzz to | |
65 // deterministically excercise different paths (such as different scaling sizes or different | |
66 // image modes) without needing to introduce a parameter. This way we don't nee d a image_scale1, | |
67 // image_scale2, image_scale4, image_scale8, etc fuzzer, we can just have a imag e_scale fuzzer. | |
68 // Clients are expected to transform this number into a different range, e.g. wi th modulo (%). | |
69 static uint8_t calculateMulti(SkData* bytes) { | |
70 uint8_t total = 0; | |
71 const uint8_t* data = bytes->bytes(); | |
72 for (size_t i = 0; i < 1024 && i < bytes->size(); i++) { | |
73 total += data[i]; | |
74 } | |
75 return total; | |
76 } | |
77 | |
60 int fuzz_api(SkData* bytes) { | 78 int fuzz_api(SkData* bytes) { |
61 const char* name = FLAGS_name.isEmpty() ? "" : FLAGS_name[0]; | 79 const char* name = FLAGS_name.isEmpty() ? "" : FLAGS_name[0]; |
62 | 80 |
63 for (auto r = SkTRegistry<Fuzzable>::Head(); r; r = r->next()) { | 81 for (auto r = SkTRegistry<Fuzzable>::Head(); r; r = r->next()) { |
64 auto fuzzable = r->factory(); | 82 auto fuzzable = r->factory(); |
65 if (0 == strcmp(name, fuzzable.name)) { | 83 if (0 == strcmp(name, fuzzable.name)) { |
66 SkDebugf("Fuzzing %s...\n", fuzzable.name); | 84 SkDebugf("Fuzzing %s...\n", fuzzable.name); |
67 Fuzz fuzz(bytes); | 85 Fuzz fuzz(bytes); |
68 fuzzable.fn(&fuzz); | 86 fuzzable.fn(&fuzz); |
69 SkDebugf("[terminated] Success!\n"); | 87 SkDebugf("[terminated] Success!\n"); |
70 return 0; | 88 return 0; |
71 } | 89 } |
72 } | 90 } |
73 | 91 |
74 SkDebugf("When using --type api, please choose an API to fuzz with --name/-n :\n"); | 92 SkDebugf("When using --type api, please choose an API to fuzz with --name/-n :\n"); |
75 for (auto r = SkTRegistry<Fuzzable>::Head(); r; r = r->next()) { | 93 for (auto r = SkTRegistry<Fuzzable>::Head(); r; r = r->next()) { |
76 auto fuzzable = r->factory(); | 94 auto fuzzable = r->factory(); |
77 SkDebugf("\t%s\n", fuzzable.name); | 95 SkDebugf("\t%s\n", fuzzable.name); |
78 } | 96 } |
79 return 1; | 97 return 1; |
80 } | 98 } |
81 | 99 |
82 static void dump_png(SkBitmap bitmap) { | 100 static void dump_png(SkBitmap bitmap) { |
83 if (!FLAGS_dump.isEmpty()) { | 101 if (!FLAGS_dump.isEmpty()) { |
84 SkImageEncoder::EncodeFile(FLAGS_dump[0], bitmap, SkImageEncoder::kPNG_T ype, 100); | 102 SkImageEncoder::EncodeFile(FLAGS_dump[0], bitmap, SkImageEncoder::kPNG_T ype, 100); |
85 SkDebugf("Dumped to %s\n", FLAGS_dump[0]); | 103 SkDebugf("Dumped to %s\n", FLAGS_dump[0]); |
86 } | 104 } |
87 } | 105 } |
88 | 106 |
89 int fuzz_img(SkData* bytes) { | 107 int fuzz_img(SkData* bytes, uint8_t scale, uint8_t mode) { |
108 // We can scale 1x, 2x, 4x, 8x, 16x | |
109 scale = scale % 5; | |
110 scale = pow(2, scale); | |
111 SkDebugf("Scaling factor: %d\n", scale); | |
112 | |
113 // We have 4 different modes of decoding, just like DM. | |
114 mode = mode % 4; | |
115 SkDebugf("Mode: %d\n", mode); | |
116 | |
117 // This is mostly copied from DMSrcSink's CodecSrc::draw method. | |
90 SkDebugf("Decoding\n"); | 118 SkDebugf("Decoding\n"); |
91 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(bytes)); | 119 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(bytes)); |
92 if (nullptr == codec.get()) { | 120 if (nullptr == codec.get()) { |
93 SkDebugf("[terminated] Couldn't create codec.\n"); | 121 SkDebugf("[terminated] Couldn't create codec.\n"); |
94 return 3; | 122 return 3; |
95 } | 123 } |
96 | 124 |
97 SkImageInfo decodeInfo = codec->getInfo(); | 125 SkImageInfo decodeInfo = codec->getInfo(); |
126 | |
127 SkISize size = codec->getScaledDimensions(scale); | |
128 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); | |
129 | |
98 // Construct a color table for the decode if necessary | 130 // Construct a color table for the decode if necessary |
99 SkAutoTUnref<SkColorTable> colorTable(nullptr); | 131 SkAutoTUnref<SkColorTable> colorTable(nullptr); |
100 SkPMColor* colorPtr = nullptr; | 132 SkPMColor* colorPtr = nullptr; |
101 int* colorCountPtr = nullptr; | 133 int* colorCountPtr = nullptr; |
102 int maxColors = 256; | 134 int maxColors = 256; |
103 if (kIndex_8_SkColorType == decodeInfo.colorType()) { | 135 if (kIndex_8_SkColorType == decodeInfo.colorType()) { |
104 SkPMColor colors[256]; | 136 SkPMColor colors[256]; |
105 colorTable.reset(new SkColorTable(colors, maxColors)); | 137 colorTable.reset(new SkColorTable(colors, maxColors)); |
106 colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); | 138 colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); |
107 colorCountPtr = &maxColors; | 139 colorCountPtr = &maxColors; |
108 } | 140 } |
109 | 141 |
110 SkBitmap bitmap; | 142 SkBitmap bitmap; |
111 SkMallocPixelRef::ZeroedPRFactory zeroFactory; | 143 SkMallocPixelRef::ZeroedPRFactory zeroFactory; |
112 SkCodec::Options options; | 144 SkCodec::Options options; |
113 options.fZeroInitialized = SkCodec::kYes_ZeroInitialized; | 145 options.fZeroInitialized = SkCodec::kYes_ZeroInitialized; |
114 | 146 |
115 if (!bitmap.tryAllocPixels(decodeInfo, &zeroFactory, nullptr)) { | 147 if (!bitmap.tryAllocPixels(decodeInfo, &zeroFactory, colorTable.get())) { |
116 SkDebugf("[terminated] Could not allocate memory. Image might be too la rge (%d x %d)", | 148 SkDebugf("[terminated] Could not allocate memory. Image might be too la rge (%d x %d)", |
117 decodeInfo.width(), decodeInfo.height()); | 149 decodeInfo.width(), decodeInfo.height()); |
118 return 4; | 150 return 4; |
119 } | 151 } |
120 | 152 |
121 switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), &options, | 153 switch (mode) { |
122 colorPtr, colorCountPtr)) { | 154 case 0: {//kCodecZeroInit_Mode, kCodec_Mode |
123 case SkCodec::kSuccess: | 155 switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowB ytes(), &options, |
156 colorPtr, colorCountPtr)) { | |
scroggo
2016/02/16 19:17:38
nit: This should align with decodeInfo, above (or
kjlubick
2016/02/16 19:55:13
Done.
| |
157 case SkCodec::kSuccess: | |
scroggo
2016/02/16 19:17:38
nit: This should be indented four more spaces.
kjlubick
2016/02/16 19:55:13
Done.
| |
158 SkDebugf("[terminated] Success!\n"); | |
159 break; | |
160 case SkCodec::kIncompleteInput: | |
161 SkDebugf("[terminated] Partial Success\n"); | |
162 break; | |
163 case SkCodec::kInvalidConversion: | |
scroggo
2016/02/16 19:17:38
Is this happening? If so, this is a bug.
msarett
2016/02/16 19:54:01
Testing if we can remove this from DM. I can't re
kjlubick
2016/02/16 19:55:13
It's not, AFAIK, but I can add signalBug so we kno
| |
164 SkDebugf("[terminated] Incompatible colortype conversion\n"); | |
165 return 5; | |
166 default: | |
167 SkDebugf("[terminated] Couldn't getPixels.\n"); | |
168 return 6; | |
169 } | |
170 break; | |
171 } | |
172 case 1: {//kScanline_Mode | |
173 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL , colorPtr, | |
174 colorCountPt r)) { | |
scroggo
2016/02/16 19:17:38
nit: Normally we would line this up with "decodeIn
kjlubick
2016/02/16 19:55:13
Done.
| |
175 SkDebugf("[terminated] Could not start scanline decoder\n"); | |
176 return 7; | |
177 } | |
178 | |
179 void* dst = bitmap.getAddr(0, 0); | |
180 size_t rowBytes = bitmap.rowBytes(); | |
181 uint32_t height = decodeInfo.height(); | |
182 switch (codec->getScanlineOrder()) { | |
183 case SkCodec::kTopDown_SkScanlineOrder: | |
184 case SkCodec::kBottomUp_SkScanlineOrder: | |
185 case SkCodec::kNone_SkScanlineOrder: | |
186 // We do not need to check the return value. On an incomple te | |
187 // image, memory will be filled with a default value. | |
188 codec->getScanlines(dst, height, rowBytes); | |
189 break; | |
190 case SkCodec::kOutOfOrder_SkScanlineOrder: { | |
191 for (int y = 0; y < decodeInfo.height(); y++) { | |
192 int dstY = codec->outputScanline(y); | |
193 void* dstPtr = bitmap.getAddr(0, dstY); | |
194 // We complete the loop, even if this call begins to fai l | |
195 // due to an incomplete image. This ensures any uniniti alized | |
196 // memory will be filled with the proper value. | |
197 codec->getScanlines(dstPtr, 1, bitmap.rowBytes()); | |
198 } | |
199 break; | |
200 } | |
201 } | |
124 SkDebugf("[terminated] Success!\n"); | 202 SkDebugf("[terminated] Success!\n"); |
125 break; | 203 break; |
126 case SkCodec::kIncompleteInput: | 204 } |
127 SkDebugf("[terminated] Partial Success\n"); | 205 case 2: { //kStripe_Mode |
128 break; | 206 const int height = decodeInfo.height(); |
129 case SkCodec::kInvalidConversion: | 207 // This value is chosen arbitrarily. We exercise more cases by choo sing a value that |
130 SkDebugf("[terminated] Incompatible colortype conversion\n"); | 208 // does not align with image blocks. |
131 return 5; | 209 const int stripeHeight = 37; |
210 const int numStripes = (height + stripeHeight - 1) / stripeHeight; | |
211 | |
212 // Decode odd stripes | |
213 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL , colorPtr, | |
214 colorCountPtr) | |
215 || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOr der()) { | |
216 // This mode was designed to test the new skip scanlines API in libjpeg-turbo. | |
217 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting | |
218 // to run this test for image types that do not have this scanli ne ordering. | |
219 SkDebugf("[terminated] Could not start top-down scanline decoder \n"); | |
220 return 8; | |
221 } | |
222 | |
223 for (int i = 0; i < numStripes; i += 2) { | |
224 // Skip a stripe | |
225 const int linesToSkip = SkTMin(stripeHeight, height - i * stripe Height); | |
226 codec->skipScanlines(linesToSkip); | |
227 | |
228 // Read a stripe | |
229 const int startY = (i + 1) * stripeHeight; | |
230 const int linesToRead = SkTMin(stripeHeight, height - startY); | |
231 if (linesToRead > 0) { | |
232 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes()); | |
233 } | |
234 } | |
235 | |
236 // Decode even stripes | |
237 const SkCodec::Result startResult = codec->startScanlineDecode(decod eInfo, nullptr, | |
238 colorPtr, colorCountPtr); | |
239 if (SkCodec::kSuccess != startResult) { | |
240 SkDebugf("[terminated] Failed to restart scanline decoder with s ame parameters.\n"); | |
241 return 9; | |
242 } | |
243 for (int i = 0; i < numStripes; i += 2) { | |
244 // Read a stripe | |
245 const int startY = i * stripeHeight; | |
246 const int linesToRead = SkTMin(stripeHeight, height - startY); | |
247 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitm ap.rowBytes()); | |
248 | |
249 // Skip a stripe | |
250 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight); | |
251 if (linesToSkip > 0) { | |
252 codec->skipScanlines(linesToSkip); | |
253 } | |
254 } | |
255 SkDebugf("[terminated] Success!\n"); | |
256 break; | |
257 } | |
258 case 3: { //kSubset_Mode | |
259 // Arbitrarily choose a divisor. | |
260 int divisor = 2; | |
261 // Total width/height of the image. | |
262 const int W = codec->getInfo().width(); | |
263 const int H = codec->getInfo().height(); | |
264 if (divisor > W || divisor > H) { | |
265 SkDebugf("[terminated] Cannot codec subset: divisor %d is too bi g " | |
266 "with dimensions (%d x %d) \n", divisor, | |
267 W, H); | |
268 return 10; | |
269 } | |
270 // subset dimensions | |
271 // SkWebpCodec, the only one that supports subsets, requires even to p/left boundaries. | |
272 const int w = SkAlign2(W / divisor); | |
273 const int h = SkAlign2(H / divisor); | |
274 SkIRect subset; | |
275 SkCodec::Options opts; | |
276 opts.fSubset = ⊂ | |
277 SkBitmap subsetBm; | |
278 // We will reuse pixel memory from bitmap. | |
279 void* pixels = bitmap.getPixels(); | |
280 // Keep track of left and top (for drawing subsetBm into canvas). We could use | |
281 // scale * x and scale * y, but we want integers such that the next subset will start | |
282 // where the last one ended. So we'll add decodeInfo.width() and hei ght(). | |
283 int left = 0; | |
284 for (int x = 0; x < W; x += w) { | |
285 int top = 0; | |
286 for (int y = 0; y < H; y+= h) { | |
287 // Do not make the subset go off the edge of the image. | |
288 const int preScaleW = SkTMin(w, W - x); | |
289 const int preScaleH = SkTMin(h, H - y); | |
290 subset.setXYWH(x, y, preScaleW, preScaleH); | |
291 // And scale | |
292 // FIXME: Should we have a version of getScaledDimensions th at takes a subset | |
293 // into account? | |
294 decodeInfo = decodeInfo.makeWH( | |
295 SkTMax(1, SkScalarRoundToInt(preScaleW * scale)), | |
296 SkTMax(1, SkScalarRoundToInt(preScaleH * scale))); | |
297 size_t rowBytes = decodeInfo.minRowBytes(); | |
298 if (!subsetBm.installPixels(decodeInfo, pixels, rowBytes, co lorTable.get(), | |
299 nullptr, nullptr)) { | |
300 SkDebugf("[terminated] Could not install pixels.\n"); | |
301 return 11; | |
302 } | |
303 const SkCodec::Result result = codec->getPixels(decodeInfo, pixels, rowBytes, | |
304 &opts, colorPtr, colorCountPtr); | |
305 switch (result) { | |
306 case SkCodec::kSuccess: | |
307 case SkCodec::kIncompleteInput: | |
308 SkDebugf("okay\n"); | |
309 break; | |
310 case SkCodec::kInvalidConversion: | |
311 if (0 == (x|y)) { | |
312 // First subset is okay to return unimplemented. | |
313 SkDebugf("[terminated] Incompatible colortype co nversion\n"); | |
314 return 12; | |
315 } | |
316 // If the first subset succeeded, a later one should not fail. | |
317 // fall through to failure | |
318 case SkCodec::kUnimplemented: | |
319 if (0 == (x|y)) { | |
320 // First subset is okay to return unimplemented. | |
321 SkDebugf("[terminated] subset codec not supporte d\n"); | |
322 return 13; | |
323 } | |
324 // If the first subset succeeded, why would a later one fail? | |
325 // fall through to failure | |
326 default: | |
327 SkDebugf("[terminated] subset codec failed to decode (%d, %d, %d, %d) " | |
328 "with dimensions (%d x %d)\t e rror %d\n", | |
329 x, y, decodeInfo.width(), deco deInfo.height(), | |
330 W, H, result); | |
331 return 14; | |
332 } | |
333 // translate by the scaled height. | |
334 top += decodeInfo.height(); | |
335 } | |
336 // translate by the scaled width. | |
337 left += decodeInfo.width(); | |
338 } | |
339 SkDebugf("[terminated] Success!\n"); | |
340 break; | |
341 } | |
132 default: | 342 default: |
133 // Everything else is considered a failure. | 343 SkDebugf("[terminated] Mode not implemented yet\n"); |
134 SkDebugf("[terminated] Couldn't getPixels.\n"); | |
135 return 6; | |
136 } | 344 } |
137 | 345 |
138 dump_png(bitmap); | 346 dump_png(bitmap); |
139 return 0; | 347 return 0; |
140 } | 348 } |
141 | 349 |
142 int fuzz_skp(SkData* bytes) { | 350 int fuzz_skp(SkData* bytes) { |
143 SkMemoryStream stream(bytes); | 351 SkMemoryStream stream(bytes); |
144 SkDebugf("Decoding\n"); | 352 SkDebugf("Decoding\n"); |
145 SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(&stream)); | 353 SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(&stream)); |
(...skipping 28 matching lines...) Expand all Loading... | |
174 T val; | 382 T val; |
175 memcpy(&val, fBytes->bytes() + fNextByte, sizeof(T)); | 383 memcpy(&val, fBytes->bytes() + fNextByte, sizeof(T)); |
176 fNextByte += sizeof(T); | 384 fNextByte += sizeof(T); |
177 return val; | 385 return val; |
178 } | 386 } |
179 | 387 |
180 uint8_t Fuzz::nextB() { return this->nextT<uint8_t >(); } | 388 uint8_t Fuzz::nextB() { return this->nextT<uint8_t >(); } |
181 uint32_t Fuzz::nextU() { return this->nextT<uint32_t>(); } | 389 uint32_t Fuzz::nextU() { return this->nextT<uint32_t>(); } |
182 float Fuzz::nextF() { return this->nextT<float >(); } | 390 float Fuzz::nextF() { return this->nextT<float >(); } |
183 | 391 |
OLD | NEW |