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/Fuzz.h" 9#include "fuzz/FuzzCommon.h" 10 11// We don't always want to test NaNs and infinities. 12static 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 19template <typename... Args> 20static void fuzz_nice_float(Fuzz* fuzz, float* f, Args... rest) { 21 fuzz_nice_float(fuzz, f); 22 fuzz_nice_float(fuzz, rest...); 23} 24 25static 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 31void 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)SkPathFillType::kInverseEvenOdd); 37 path->setFillType((SkPathFillType)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 SkPathDirection 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<SkPathDirection>(ui); 116 path->addRect(r, dir); 117 break; 118 case 14: 119 fuzz->nextRange(&ui, 0, 1); 120 dir = static_cast<SkPathDirection>(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<SkPathDirection>(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<SkPathDirection>(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<SkPathDirection>(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<SkPathDirection>(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<SkPathDirection>(ui); 160 path->addRRect(rr, dir); 161 break; 162 case 21: 163 fuzz->nextRange(&ui, 0, 1); 164 dir = static_cast<SkPathDirection>(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 216 default: 217 SkASSERT(false); 218 break; 219 } 220 SkASSERTF( path->isValid(), "path->isValid() failed at op %d, case %d", i, op); 221 } 222} 223 224// allows all float values for path points 225void FuzzEvilPath(Fuzz* fuzz, SkPath* path, int last_verb) { 226 while (!fuzz->exhausted()) { 227 // Use a uint8_t to conserve bytes. This makes our "fuzzed bytes footprint" 228 // smaller, which leads to more efficient fuzzing. 229 uint8_t operation; 230 fuzz->next(&operation); 231 SkScalar a,b,c,d,e,f; 232 233 switch (operation % (last_verb + 1)) { 234 case SkPath::Verb::kMove_Verb: 235 fuzz->next(&a, &b); 236 path->moveTo(a, b); 237 break; 238 239 case SkPath::Verb::kLine_Verb: 240 fuzz->next(&a, &b); 241 path->lineTo(a, b); 242 break; 243 244 case SkPath::Verb::kQuad_Verb: 245 fuzz->next(&a, &b, &c, &d); 246 path->quadTo(a, b, c, d); 247 break; 248 249 case SkPath::Verb::kConic_Verb: 250 fuzz->next(&a, &b, &c, &d, &e); 251 path->conicTo(a, b, c, d, e); 252 break; 253 254 case SkPath::Verb::kCubic_Verb: 255 fuzz->next(&a, &b, &c, &d, &e, &f); 256 path->cubicTo(a, b, c, d, e, f); 257 break; 258 259 case SkPath::Verb::kClose_Verb: 260 path->close(); 261 break; 262 263 case SkPath::Verb::kDone_Verb: 264 // In this case, simply exit. 265 return; 266 } 267 } 268} 269 270void FuzzNiceRRect(Fuzz* fuzz, SkRRect* rr) { 271 SkRect r; 272 fuzz_nice_rect(fuzz, &r); 273 274 SkVector radii[4]; 275 for (SkVector& vec : radii) { 276 fuzz->nextRange(&vec.fX, 0.0f, 1.0f); 277 vec.fX *= 0.5f * r.width(); 278 fuzz->nextRange(&vec.fY, 0.0f, 1.0f); 279 vec.fY *= 0.5f * r.height(); 280 } 281 rr->setRectRadii(r, radii); 282 SkASSERT(rr->isValid()); 283} 284 285void FuzzNiceMatrix(Fuzz* fuzz, SkMatrix* m) { 286 constexpr int kArrayLength = 9; 287 SkScalar buffer[kArrayLength]; 288 int matrixType; 289 fuzz->nextRange(&matrixType, 0, 4); 290 switch (matrixType) { 291 case 0: // identity 292 *m = SkMatrix::I(); 293 return; 294 case 1: // translate 295 fuzz->nextRange(&buffer[0], -4000.0f, 4000.0f); 296 fuzz->nextRange(&buffer[1], -4000.0f, 4000.0f); 297 *m = SkMatrix::Translate(buffer[0], buffer[1]); 298 return; 299 case 2: // translate + scale 300 fuzz->nextRange(&buffer[0], -400.0f, 400.0f); 301 fuzz->nextRange(&buffer[1], -400.0f, 400.0f); 302 fuzz->nextRange(&buffer[2], -4000.0f, 4000.0f); 303 fuzz->nextRange(&buffer[3], -4000.0f, 4000.0f); 304 *m = SkMatrix::Scale(buffer[0], buffer[1]); 305 m->postTranslate(buffer[2], buffer[3]); 306 return; 307 case 3: // affine 308 fuzz->nextN(buffer, 6); 309 m->setAffine(buffer); 310 return; 311 case 4: // perspective 312 fuzz->nextN(buffer, kArrayLength); 313 m->set9(buffer); 314 return; 315 default: 316 SkASSERT(false); 317 return; 318 } 319} 320 321void FuzzNiceRegion(Fuzz* fuzz, SkRegion* region, int maxN) { 322 uint8_t N; 323 fuzz->nextRange(&N, 0, maxN); 324 for (uint8_t i = 0; i < N; ++i) { 325 SkIRect r; 326 SkRegion::Op op; 327 // Avoid the sentinel value used by Region. 328 fuzz->nextRange(&r.fLeft, -2147483646, 2147483646); 329 fuzz->nextRange(&r.fTop, -2147483646, 2147483646); 330 fuzz->nextRange(&r.fRight, -2147483646, 2147483646); 331 fuzz->nextRange(&r.fBottom, -2147483646, 2147483646); 332 r.sort(); 333 fuzz->nextEnum(&op, SkRegion::kLastOp); 334 if (!region->op(r, op)) { 335 return; 336 } 337 } 338} 339