FuzzCommon.cpp 11 KB

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