1 /* 2 * Copyright 2018 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "Fuzz.h" 9 #include "FuzzCommon.h" 10 11 // We don't always want to test NaNs and infinities. 12 static void fuzz_nice_float(Fuzz* fuzz, float* f) { 13 float v; 14 fuzz->next(&v); 15 constexpr float kLimit = 1.0e35f; // FLT_MAX? 16 *f = (v == v && v <= kLimit && v >= -kLimit) ? v : 0.0f; 17 } 18 19 template <typename... Args> 20 static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) { 21 fuzz_nice_float(fuzz, f); 22 fuzz_nice_float(fuzz, rest...); 23 } 24 25 static void fuzz_nice_rect(Fuzz* fuzz, SkRect* r) { 26 fuzz_nice_float(fuzz, &r->fLeft, &r->fTop, &r->fRight, &r->fBottom); 27 r->sort(); 28 } 29 30 // allows some float values for path points 31 void FuzzNicePath(Fuzz* fuzz, SkPath* path, int maxOps) { 32 if (maxOps <= 0 || fuzz->exhausted() || path->countPoints() > 100000) { 33 return; 34 } 35 uint8_t fillType; 36 fuzz->nextRange(&fillType, 0, (uint8_t)SkPath::kInverseEvenOdd_FillType); 37 path->setFillType((SkPath::FillType)fillType); 38 uint8_t numOps; 39 fuzz->nextRange(&numOps, 0, maxOps); 40 for (uint8_t i = 0; i < numOps; ++i) { 41 // When we start adding the path to itself, the fuzzer can make an 42 // exponentially long path, which causes timeouts. 43 if (path->countPoints() > 100000) { 44 return; 45 } 46 // How many items in the switch statement below. 47 constexpr uint8_t PATH_OPERATIONS = 32; 48 uint8_t op; 49 fuzz->nextRange(&op, 0, PATH_OPERATIONS); 50 bool test; 51 SkPath p; 52 SkMatrix m; 53 SkRRect rr; 54 SkRect r; 55 SkPath::Direction dir; 56 unsigned int ui; 57 SkScalar a, b, c, d, e, f; 58 switch (op) { 59 case 0: 60 fuzz_nice_float(fuzz, &a, &b); 61 path->moveTo(a, b); 62 break; 63 case 1: 64 fuzz_nice_float(fuzz, &a, &b); 65 path->rMoveTo(a, b); 66 break; 67 case 2: 68 fuzz_nice_float(fuzz, &a, &b); 69 path->lineTo(a, b); 70 break; 71 case 3: 72 fuzz_nice_float(fuzz, &a, &b); 73 path->rLineTo(a, b); 74 break; 75 case 4: 76 fuzz_nice_float(fuzz, &a, &b, &c, &d); 77 path->quadTo(a, b, c, d); 78 break; 79 case 5: 80 fuzz_nice_float(fuzz, &a, &b, &c, &d); 81 path->rQuadTo(a, b, c, d); 82 break; 83 case 6: 84 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e); 85 path->conicTo(a, b, c, d, e); 86 break; 87 case 7: 88 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e); 89 path->rConicTo(a, b, c, d, e); 90 break; 91 case 8: 92 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e, &f); 93 path->cubicTo(a, b, c, d, e, f); 94 break; 95 case 9: 96 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e, &f); 97 path->rCubicTo(a, b, c, d, e, f); 98 break; 99 case 10: 100 fuzz_nice_float(fuzz, &a, &b, &c, &d, &e); 101 path->arcTo(a, b, c, d, e); 102 break; 103 case 11: 104 fuzz_nice_float(fuzz, &a, &b); 105 fuzz_nice_rect(fuzz, &r); 106 fuzz->next(&test); 107 path->arcTo(r, a, b, test); 108 break; 109 case 12: 110 path->close(); 111 break; 112 case 13: 113 fuzz_nice_rect(fuzz, &r); 114 fuzz->nextRange(&ui, 0, 1); 115 dir = static_cast<SkPath::Direction>(ui); 116 path->addRect(r, dir); 117 break; 118 case 14: 119 fuzz->nextRange(&ui, 0, 1); 120 dir = static_cast<SkPath::Direction>(ui); 121 fuzz_nice_rect(fuzz, &r); 122 fuzz->next(&ui); 123 path->addRect(r, dir, ui); 124 break; 125 case 15: 126 fuzz->nextRange(&ui, 0, 1); 127 dir = static_cast<SkPath::Direction>(ui); 128 fuzz_nice_rect(fuzz, &r); 129 path->addOval(r, dir); 130 break; 131 case 16: 132 fuzz->nextRange(&ui, 0, 1); 133 dir = static_cast<SkPath::Direction>(ui); 134 fuzz_nice_rect(fuzz, &r); 135 fuzz->next(&ui); 136 path->addOval(r, dir, ui); 137 break; 138 case 17: 139 fuzz->nextRange(&ui, 0, 1); 140 dir = static_cast<SkPath::Direction>(ui); 141 fuzz_nice_float(fuzz, &a, &b, &c); 142 path->addCircle(a, b, c, dir); 143 break; 144 case 18: 145 fuzz_nice_rect(fuzz, &r); 146 fuzz_nice_float(fuzz, &a, &b); 147 path->addArc(r, a, b); 148 break; 149 case 19: 150 fuzz_nice_float(fuzz, &a, &b); 151 fuzz_nice_rect(fuzz, &r); 152 fuzz->nextRange(&ui, 0, 1); 153 dir = static_cast<SkPath::Direction>(ui); 154 path->addRoundRect(r, a, b, dir); 155 break; 156 case 20: 157 FuzzNiceRRect(fuzz, &rr); 158 fuzz->nextRange(&ui, 0, 1); 159 dir = static_cast<SkPath::Direction>(ui); 160 path->addRRect(rr, dir); 161 break; 162 case 21: 163 fuzz->nextRange(&ui, 0, 1); 164 dir = static_cast<SkPath::Direction>(ui); 165 FuzzNiceRRect(fuzz, &rr); 166 path->addRRect(rr, dir, ui); 167 break; 168 case 22: { 169 fuzz->nextRange(&ui, 0, 1); 170 SkPath::AddPathMode mode = static_cast<SkPath::AddPathMode>(ui); 171 FuzzNiceMatrix(fuzz, &m); 172 FuzzNicePath(fuzz, &p, maxOps-1); 173 path->addPath(p, m, mode); 174 break; 175 } 176 case 23: { 177 fuzz->nextRange(&ui, 0, 1); 178 SkPath::AddPathMode mode = static_cast<SkPath::AddPathMode>(ui); 179 FuzzNiceMatrix(fuzz, &m); 180 path->addPath(*path, m, mode); 181 break; 182 } 183 case 24: 184 FuzzNicePath(fuzz, &p, maxOps-1); 185 path->reverseAddPath(p); 186 break; 187 case 25: 188 path->addPath(*path); 189 break; 190 case 26: 191 path->reverseAddPath(*path); 192 break; 193 case 27: 194 fuzz_nice_float(fuzz, &a, &b); 195 path->offset(a, b, path); 196 break; 197 case 28: 198 FuzzNicePath(fuzz, &p, maxOps-1); 199 fuzz_nice_float(fuzz, &a, &b); 200 p.offset(a, b, path); 201 break; 202 case 29: 203 FuzzNiceMatrix(fuzz, &m); 204 path->transform(m, path); 205 break; 206 case 30: 207 FuzzNicePath(fuzz, &p, maxOps-1); 208 FuzzNiceMatrix(fuzz, &m); 209 p.transform(m, path); 210 break; 211 case 31: 212 fuzz_nice_float(fuzz, &a, &b); 213 path->setLastPt(a, b); 214 break; 215 case PATH_OPERATIONS: 216 path->shrinkToFit(); 217 break; 218 219 default: 220 SkASSERT(false); 221 break; 222 } 223 SkASSERTF( path->isValid(), "path->isValid() failed at op %d, case %d", i, op); 224 } 225 } 226 227 // allows all float values for path points 228 void FuzzEvilPath(Fuzz* fuzz, SkPath* path, int last_verb) { 229 while (!fuzz->exhausted()) { 230 // Use a uint8_t to conserve bytes. This makes our "fuzzed bytes footprint" 231 // smaller, which leads to more efficient fuzzing. 232 uint8_t operation; 233 fuzz->next(&operation); 234 SkScalar a,b,c,d,e,f; 235 236 switch (operation % (last_verb + 1)) { 237 case SkPath::Verb::kMove_Verb: 238 fuzz->next(&a, &b); 239 path->moveTo(a, b); 240 break; 241 242 case SkPath::Verb::kLine_Verb: 243 fuzz->next(&a, &b); 244 path->lineTo(a, b); 245 break; 246 247 case SkPath::Verb::kQuad_Verb: 248 fuzz->next(&a, &b, &c, &d); 249 path->quadTo(a, b, c, d); 250 break; 251 252 case SkPath::Verb::kConic_Verb: 253 fuzz->next(&a, &b, &c, &d, &e); 254 path->conicTo(a, b, c, d, e); 255 break; 256 257 case SkPath::Verb::kCubic_Verb: 258 fuzz->next(&a, &b, &c, &d, &e, &f); 259 path->cubicTo(a, b, c, d, e, f); 260 break; 261 262 case SkPath::Verb::kClose_Verb: 263 path->close(); 264 break; 265 266 case SkPath::Verb::kDone_Verb: 267 // In this case, simply exit. 268 return; 269 } 270 } 271 } 272 273 void FuzzNiceRRect(Fuzz* fuzz, SkRRect* rr) { 274 SkRect r; 275 fuzz_nice_rect(fuzz, &r); 276 277 SkVector radii[4]; 278 for (SkVector& vec : radii) { 279 fuzz->nextRange(&vec.fX, 0.0f, 1.0f); 280 vec.fX *= 0.5f * r.width(); 281 fuzz->nextRange(&vec.fY, 0.0f, 1.0f); 282 vec.fY *= 0.5f * r.height(); 283 } 284 rr->setRectRadii(r, radii); 285 SkASSERT(rr->isValid()); 286 } 287 288 void FuzzNiceMatrix(Fuzz* fuzz, SkMatrix* m) { 289 constexpr int kArrayLength = 9; 290 SkScalar buffer[kArrayLength]; 291 int matrixType; 292 fuzz->nextRange(&matrixType, 0, 4); 293 switch (matrixType) { 294 case 0: // identity 295 *m = SkMatrix::I(); 296 return; 297 case 1: // translate 298 fuzz->nextRange(&buffer[0], -4000.0f, 4000.0f); 299 fuzz->nextRange(&buffer[1], -4000.0f, 4000.0f); 300 *m = SkMatrix::MakeTrans(buffer[0], buffer[1]); 301 return; 302 case 2: // translate + scale 303 fuzz->nextRange(&buffer[0], -400.0f, 400.0f); 304 fuzz->nextRange(&buffer[1], -400.0f, 400.0f); 305 fuzz->nextRange(&buffer[2], -4000.0f, 4000.0f); 306 fuzz->nextRange(&buffer[3], -4000.0f, 4000.0f); 307 *m = SkMatrix::MakeScale(buffer[0], buffer[1]); 308 m->postTranslate(buffer[2], buffer[3]); 309 return; 310 case 3: // affine 311 fuzz->nextN(buffer, 6); 312 m->setAffine(buffer); 313 return; 314 case 4: // perspective 315 fuzz->nextN(buffer, kArrayLength); 316 m->set9(buffer); 317 return; 318 default: 319 SkASSERT(false); 320 return; 321 } 322 } 323 324 void FuzzNiceRegion(Fuzz* fuzz, SkRegion* region, int maxN) { 325 uint8_t N; 326 fuzz->nextRange(&N, 0, maxN); 327 for (uint8_t i = 0; i < N; ++i) { 328 SkIRect r; 329 SkRegion::Op op; 330 // Avoid the sentinal value used by Region. 331 fuzz->nextRange(&r.fLeft, -2147483646, 2147483646); 332 fuzz->nextRange(&r.fTop, -2147483646, 2147483646); 333 fuzz->nextRange(&r.fRight, -2147483646, 2147483646); 334 fuzz->nextRange(&r.fBottom, -2147483646, 2147483646); 335 r.sort(); 336 fuzz->nextRange(&op, 0, SkRegion::kLastOp); 337 if (!region->op(r, op)) { 338 return; 339 } 340 } 341 } 342