From 416b248312efe7556f980d390254df8503bbbad7 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Thu, 10 Nov 2016 16:17:49 -0500 Subject: Avoid platform-dependent function params in Fuzzer We use this approach instead of T next() because different compilers evaluate function parameters in different orders. If fuzz->next() returned 5 and then 7, foo(fuzz->next(), fuzz->next()) would be foo(5, 7) when compiled on GCC and foo(7, 5) when compiled on Clang. By requiring params to be passed in, we avoid the temptation to call next() in a way that does not consume fuzzed bytes in a single platform-independent order. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4392 Change-Id: I35de849f82e8be45378f662a48100eb732fa8895 Reviewed-on: https://skia-review.googlesource.com/4392 Reviewed-by: Mike Klein Commit-Queue: Kevin Lubick --- fuzz/FilterFuzz.cpp | 637 +++++++++++++++++++++++++++------------------- fuzz/Fuzz.h | 88 ++++--- fuzz/FuzzGradients.cpp | 74 +++--- fuzz/FuzzParsePath.cpp | 42 ++- fuzz/FuzzPathop.cpp | 29 ++- fuzz/FuzzScaleToSides.cpp | 5 +- 6 files changed, 522 insertions(+), 353 deletions(-) diff --git a/fuzz/FilterFuzz.cpp b/fuzz/FilterFuzz.cpp index 81e9bf1f15..1953668d05 100644 --- a/fuzz/FilterFuzz.cpp +++ b/fuzz/FilterFuzz.cpp @@ -53,68 +53,37 @@ static Fuzz* fuzz; static const int kBitmapSize = 24; -static bool return_large = false; -static bool return_undef = false; -static int R(int x) { - return abs(fuzz->next()) % x; -} - -#if defined _WIN32 -#pragma warning ( push ) -// we are intentionally causing an overflow here -// (warning C4756: overflow in constant arithmetic) -#pragma warning ( disable : 4756 ) -#endif - -static float huge() { - double d = 1e100; - float f = (float)d; - return f; +// There should be no more than one make_* used as a function argument. +static bool make_bool() { + bool b; fuzz->next(&b); + return b; } -#if defined _WIN32 -#pragma warning ( pop ) -#endif - static float make_number(bool positiveOnly) { - float f = positiveOnly ? 1.0f : 0.0f; - float v = f; - int sel; - - if (return_large) sel = R(6); else sel = R(4); - if (!return_undef && sel == 0) sel = 1; - - if (R(2) == 1) v = (float)(R(100)+f); else - - switch (sel) { - case 0: break; - case 1: v = f; break; - case 2: v = 0.000001f; break; - case 3: v = 10000.0f; break; - case 4: v = 2000000000.0f; break; - case 5: v = huge(); break; + float f; + fuzz->next(&f); + if (positiveOnly) { + return std::abs(f); } - - if (!positiveOnly && (R(4) == 1)) v = -v; - return v; -} - -static SkScalar make_scalar(bool positiveOnly = false) { - return make_number(positiveOnly); + return f; } static SkString make_string() { - int length = R(1000); + int length; + fuzz->nextRange(&length, 0, 1000); SkString str(length); for (int i = 0; i < length; ++i) { - str[i] = static_cast(R(256)); + char c; + fuzz->nextRange(&c, 0, 255); + str[i] = c; } return str; } static SkString make_font_name() { - int sel = R(8); + int sel; + fuzz->nextRange(&sel, 0, 7); switch(sel) { case 0: return SkString("Courier New"); @@ -130,98 +99,127 @@ static SkString make_font_name() { } } -static bool make_bool() { - return fuzz->next(); -} - static SkRect make_rect() { - return SkRect::MakeWH(SkIntToScalar(R(static_cast(kBitmapSize))), - SkIntToScalar(R(static_cast(kBitmapSize)))); + SkScalar w, h; + fuzz->nextRange(&w, 0.0f, (float) kBitmapSize-1); + fuzz->nextRange(&h, 0.0f, (float) kBitmapSize-1); + return SkRect::MakeWH(w, h); } static SkRegion make_region() { - SkIRect iRegion = SkIRect::MakeXYWH(R(static_cast(kBitmapSize)), - R(static_cast(kBitmapSize)), - R(static_cast(kBitmapSize)), - R(static_cast(kBitmapSize))); + int32_t x, y, w, h; + fuzz->nextRange(&x, 0, kBitmapSize-1); + fuzz->nextRange(&y, 0, kBitmapSize-1); + fuzz->nextRange(&w, 0, kBitmapSize-1); + fuzz->nextRange(&h, 0, kBitmapSize-1); + SkIRect iRegion = SkIRect::MakeXYWH(x,y,w,h); return SkRegion(iRegion); } -static SkMatrix make_matrix() { - SkMatrix m; - for (int i = 0; i < 9; ++i) { - m[i] = make_scalar(); - } - return m; +static void init_matrix(SkMatrix* m) { + SkScalar mat[9]; + fuzz->nextN(mat, 9); + m->set9(mat); } static SkBlendMode make_blendmode() { - return static_cast(R((int)SkBlendMode::kLastMode+1)); + uint8_t i; + fuzz->nextRange(&i, 0, (uint8_t)SkBlendMode::kLastMode); + return static_cast(i); } static SkPaint::Align make_paint_align() { - return static_cast(R(SkPaint::kRight_Align+1)); + uint8_t i; + fuzz->nextRange(&i, 0, (uint8_t)SkPaint::kRight_Align); + return static_cast(i); } static SkPaint::Hinting make_paint_hinting() { - return static_cast(R(SkPaint::kFull_Hinting+1)); + uint8_t i; + fuzz->nextRange(&i, 0, (uint8_t)SkPaint::kFull_Hinting); + return static_cast(i); } static SkPaint::Style make_paint_style() { - return static_cast(R(SkPaint::kStrokeAndFill_Style+1)); + uint8_t i; + fuzz->nextRange(&i, 0, (uint8_t)SkPaint::kStrokeAndFill_Style); + return static_cast(i); } static SkPaint::Cap make_paint_cap() { - return static_cast(R(SkPaint::kDefault_Cap+1)); + uint8_t i; + fuzz->nextRange(&i, 0, (uint8_t)SkPaint::kDefault_Cap); + return static_cast(i); } static SkPaint::Join make_paint_join() { - return static_cast(R(SkPaint::kDefault_Join+1)); + uint8_t i; + fuzz->nextRange(&i, 0, (uint8_t)SkPaint::kDefault_Join); + return static_cast(i); } static SkPaint::TextEncoding make_paint_text_encoding() { - return static_cast(R(SkPaint::kGlyphID_TextEncoding+1)); + uint8_t i; + fuzz->nextRange(&i, 0, (uint8_t)SkPaint::kGlyphID_TextEncoding); + return static_cast(i); } static SkBlurStyle make_blur_style() { - return static_cast(R(kLastEnum_SkBlurStyle+1)); + uint8_t i; + fuzz->nextRange(&i, 0, (uint8_t)kLastEnum_SkBlurStyle); + return static_cast(i); } static SkBlurMaskFilter::BlurFlags make_blur_mask_filter_flag() { - return static_cast(R(SkBlurMaskFilter::kAll_BlurFlag+1)); + uint8_t i; + fuzz->nextRange(&i, 0, (uint8_t)SkBlurMaskFilter::kAll_BlurFlag); + return static_cast(i); } static SkFilterQuality make_filter_quality() { - return static_cast(R(kHigh_SkFilterQuality+1)); + uint8_t i; + fuzz->nextRange(&i, 0, (uint8_t)kHigh_SkFilterQuality); + return static_cast(i); } static SkFontStyle make_typeface_style() { - return SkFontStyle::FromOldStyle(R(SkTypeface::kBoldItalic+1)); + uint8_t i; + fuzz->nextRange(&i, 0, (uint8_t)SkTypeface::kBoldItalic); + return SkFontStyle::FromOldStyle(i); } static SkPath1DPathEffect::Style make_path_1d_path_effect_style() { - return static_cast(R((int)SkPath1DPathEffect::kLastEnum_Style + 1)); + uint8_t i; + fuzz->nextRange(&i, 0, (uint8_t)SkPath1DPathEffect::kLastEnum_Style); + return static_cast(i); } static SkColor make_color() { - return (R(2) == 1) ? 0xFFC0F0A0 : 0xFF000090; + return make_bool() ? 0xFFC0F0A0 : 0xFF000090; } static SkDropShadowImageFilter::ShadowMode make_shadow_mode() { - return (R(2) == 1) ? SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode : - SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode; + return make_bool() ? SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode : + SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode; } static SkPoint3 make_point() { - return SkPoint3::Make(make_scalar(), make_scalar(), make_scalar(true)); + SkScalar a, b, c; + fuzz->next(&a, &b, &c); + c = std::abs(c); + return SkPoint3::Make(a, b, c); } static SkDisplacementMapEffect::ChannelSelectorType make_channel_selector_type() { - return static_cast(R(4)+1); + uint8_t i; + fuzz->nextRange(&i, 1, (uint8_t)SkDisplacementMapEffect::kA_ChannelSelectorType); + return static_cast(i); } static SkColorType rand_colortype() { - return (SkColorType)R(kLastEnum_SkColorType + 1); + uint8_t i; + fuzz->nextRange(&i, 0, kLastEnum_SkColorType); + return (SkColorType) i; } static void rand_bitmap_for_canvas(SkBitmap* bitmap) { @@ -278,11 +276,15 @@ static const SkBitmap& make_bitmap() { make_checkerboard_bitmap(bitmap[1]); initialized = true; } - return bitmap[R(2)]; + uint8_t i; + fuzz->nextRange(&i, 0, 1); + return bitmap[i]; } static sk_sp make_3Dlut(int* cubeDimension, bool invR, bool invG, bool invB) { - int size = 4 << R(5); + uint8_t shift; + fuzz->nextRange(&shift, 0, 4); + int size = 4 << shift; auto data = SkData::MakeUninitialized(sizeof(SkColor) * size * size * size); SkColor* pixels = (SkColor*)(data->writable_data()); SkAutoTMalloc lutMemory(size); @@ -327,19 +329,13 @@ static void drawSomething(SkCanvas* canvas) { canvas->drawText("Picture", 7, SkIntToScalar(kBitmapSize/2), SkIntToScalar(kBitmapSize/4), paint); } -static void rand_color_table(uint8_t* table) { - for (int i = 0; i < 256; ++i) { - table[i] = R(256); - } -} - static sk_sp make_color_filter() { - switch (R(6)) { + uint8_t s; + fuzz->nextRange(&s, 0, 5); + switch (s) { case 0: { SkScalar array[20]; - for (int i = 0; i < 20; ++i) { - array[i] = make_scalar(); - } + fuzz->nextN(array, 20); return SkColorFilter::MakeMatrixFilterRowMajor255(array); } case 1: @@ -349,16 +345,22 @@ static sk_sp make_color_filter() { uint8_t tableR[256]; uint8_t tableG[256]; uint8_t tableB[256]; - rand_color_table(tableA); - rand_color_table(tableR); - rand_color_table(tableG); - rand_color_table(tableB); + fuzz->nextN(tableA, 256); + fuzz->nextN(tableR, 256); + fuzz->nextN(tableG, 256); + fuzz->nextN(tableB, 256); return SkTableColorFilter::MakeARGB(tableA, tableR, tableG, tableB); } - case 3: - return SkColorFilter::MakeModeFilter(make_color(), make_blendmode()); - case 4: - return SkColorMatrixFilter::MakeLightingFilter(make_color(), make_color()); + case 3: { + SkColor c = make_color(); + SkBlendMode mode = make_blendmode(); + return SkColorFilter::MakeModeFilter(c, mode); + } + case 4: { + SkColor a = make_color(); + SkColor b = make_color(); + return SkColorMatrixFilter::MakeLightingFilter(a, b); + } case 5: default: break; @@ -368,30 +370,38 @@ static sk_sp make_color_filter() { static SkPath make_path() { SkPath path; - int numOps = R(30); - for (int i = 0; i < numOps; ++i) { - switch (R(6)) { + uint8_t numOps; + fuzz->nextRange(&numOps, 0, 30); + for (uint8_t i = 0; i < numOps; ++i) { + uint8_t op; + fuzz->nextRange(&op, 0, 5); + SkScalar a, b, c, d, e, f; + switch (op) { case 0: - path.moveTo(make_scalar(), make_scalar()); + fuzz->next(&a, &b); + path.moveTo(a, b); break; case 1: - path.lineTo(make_scalar(), make_scalar()); + fuzz->next(&a, &b); + path.lineTo(a, b); break; case 2: - path.quadTo(make_scalar(), make_scalar(), make_scalar(), make_scalar()); + fuzz->next(&a, &b, &c, &d); + path.quadTo(a, b, c, d); break; case 3: - path.conicTo(make_scalar(), make_scalar(), make_scalar(), make_scalar(), make_scalar()); + fuzz->next(&a, &b, &c, &d, &e); + path.conicTo(a, b, c, d, e); break; case 4: - path.cubicTo(make_scalar(), make_scalar(), make_scalar(), - make_scalar(), make_scalar(), make_scalar()); + fuzz->next(&a, &b, &c, &d, &e, &f); + path.cubicTo(a, b, c, d, e, f); break; case 5: default: - path.arcTo(make_scalar(), make_scalar(), make_scalar(), make_scalar(), make_scalar()); + fuzz->next(&a, &b, &c, &d, &e); + path.arcTo(a, b, c, d, e); break; - } } path.close(); @@ -400,65 +410,98 @@ static SkPath make_path() { static sk_sp make_path_effect(bool canBeNull = true) { sk_sp pathEffect; - if (canBeNull && (R(3) == 0)) { return pathEffect; } + uint8_t s; + fuzz->nextRange(&s, 0, 2); + if (canBeNull && s == 0) { return pathEffect; } + + fuzz->nextRange(&s, 0, 8); - switch (R(9)) { - case 0: - pathEffect = SkArcToPathEffect::Make(make_scalar(true)); + switch (s) { + case 0: { + SkScalar a = make_number(true); + pathEffect = SkArcToPathEffect::Make(a); break; - case 1: - pathEffect = SkComposePathEffect::Make(make_path_effect(false), - make_path_effect(false)); + } + case 1: { + sk_sp a = make_path_effect(false); + sk_sp b = make_path_effect(false); + pathEffect = SkComposePathEffect::Make(a, b); break; - case 2: - pathEffect = SkCornerPathEffect::Make(make_scalar()); + } + case 2: { + SkScalar a = make_number(false); + pathEffect = SkCornerPathEffect::Make(a); break; + } case 3: { - int count = R(10); + uint8_t count; + fuzz->nextRange(&count, 0, 9); SkScalar intervals[10]; - for (int i = 0; i < count; ++i) { - intervals[i] = make_scalar(); - } - pathEffect = SkDashPathEffect::Make(intervals, count, make_scalar()); + fuzz->nextN(intervals, 10); + SkScalar a = make_number(false); + pathEffect = SkDashPathEffect::Make(intervals, count, a); break; } - case 4: - pathEffect = SkDiscretePathEffect::Make(make_scalar(), make_scalar()); + case 4: { + SkScalar a, b; + fuzz->next(&a, &b); + pathEffect = SkDiscretePathEffect::Make(a, b); break; - case 5: - pathEffect = SkPath1DPathEffect::Make(make_path(), make_scalar(), make_scalar(), - make_path_1d_path_effect_style()); + } + case 5: { + SkPath path = make_path(); + SkScalar a, b; + fuzz->next(&a, &b); + SkPath1DPathEffect::Style style = make_path_1d_path_effect_style(); + pathEffect = SkPath1DPathEffect::Make(path, a, b, style); break; - case 6: - pathEffect = SkLine2DPathEffect::Make(make_scalar(), make_matrix()); + } + case 6: { + SkScalar a = make_number(false); + SkMatrix m; + init_matrix(&m); + pathEffect = SkLine2DPathEffect::Make(a, m); break; - case 7: - pathEffect = SkPath2DPathEffect::Make(make_matrix(), make_path()); + } + case 7: { + SkPath path = make_path(); + SkMatrix m; + init_matrix(&m); + pathEffect = SkPath2DPathEffect::Make(m, path); break; + } case 8: - default: - pathEffect = SkSumPathEffect::Make(make_path_effect(false), - make_path_effect(false)); + default: { + sk_sp a = make_path_effect(false); + sk_sp b = make_path_effect(false); + pathEffect = SkSumPathEffect::Make(a, b); break; + } } return pathEffect; } static sk_sp make_mask_filter() { sk_sp maskFilter; - switch (R(3)) { - case 0: - maskFilter = SkBlurMaskFilter::Make(make_blur_style(), make_scalar(), - make_blur_mask_filter_flag()); + uint8_t s; + fuzz->nextRange(&s, 0, 2); + switch (s) { + case 0: { + SkBlurStyle blur = make_blur_style(); + SkScalar a = make_number(false); + SkBlurMaskFilter::BlurFlags flags = make_blur_mask_filter_flag(); + maskFilter = SkBlurMaskFilter::Make(blur, a, flags); + break; + } case 1: { + SkScalar a = make_number(false); SkEmbossMaskFilter::Light light; - for (int i = 0; i < 3; ++i) { - light.fDirection[i] = make_scalar(); - } - light.fPad = R(65536); - light.fAmbient = R(256); - light.fSpecular = R(256); - maskFilter = SkEmbossMaskFilter::Make(make_scalar(), light); + fuzz->nextN(light.fDirection, 3); + fuzz->nextRange(&light.fPad, 0, 65535); + fuzz->nextRange(&light.fAmbient, 0, 255); + fuzz->nextRange(&light.fSpecular, 0, 255); + maskFilter = SkEmbossMaskFilter::Make(a, light); + break; } case 2: default: @@ -490,8 +533,8 @@ static SkPaint make_paint() { paint.setFilterQuality(make_filter_quality()); paint.setStyle(make_paint_style()); paint.setColor(make_color()); - paint.setStrokeWidth(make_scalar()); - paint.setStrokeMiter(make_scalar()); + paint.setStrokeWidth(make_number(false)); + paint.setStrokeMiter(make_number(false)); paint.setStrokeCap(make_paint_cap()); paint.setStrokeJoin(make_paint_join()); paint.setColorFilter(make_color_filter()); @@ -506,17 +549,21 @@ static SkPaint make_paint() { SkLayerRasterizer::Builder rasterizerBuilder; SkPaint paintForRasterizer; - if (R(2) == 1) { + if (make_bool()) { paintForRasterizer = make_paint(); } rasterizerBuilder.addLayer(paintForRasterizer); paint.setRasterizer(rasterizerBuilder.detach()); paint.setImageFilter(make_image_filter()); - sk_sp data(make_3Dlut(nullptr, make_bool(), make_bool(), make_bool())); + bool a, b, c; + fuzz->next(&a, &b, &c); + sk_sp data(make_3Dlut(nullptr, a, b, c)); paint.setTextAlign(make_paint_align()); - paint.setTextSize(make_scalar()); - paint.setTextScaleX(make_scalar()); - paint.setTextSkewX(make_scalar()); + SkScalar d, e, f; + fuzz->next(&d, &e, &f); + paint.setTextSize(d); + paint.setTextScaleX(e); + paint.setTextSkewX(f); paint.setTextEncoding(make_paint_text_encoding()); return paint; } @@ -525,7 +572,9 @@ static sk_sp make_image_filter(bool canBeNull) { sk_sp filter; // Add a 1 in 3 chance to get a nullptr input - if (fuzz->exhausted() || (canBeNull && R(3) == 1)) { + uint8_t i; + fuzz->nextRange(&i, 0, 2); + if (fuzz->exhausted() || (canBeNull && i == 1)) { return filter; } @@ -534,18 +583,24 @@ static sk_sp make_image_filter(bool canBeNull) { DISTANT_LIGHT, POINT_LIGHT, SPOT_LIGHT, NOISE, DROP_SHADOW, MORPHOLOGY, BITMAP, DISPLACE, TILE, PICTURE, PAINT, NUM_FILTERS }; - switch (R(NUM_FILTERS)) { - case ALPHA_THRESHOLD: - filter = SkAlphaThresholdFilter::Make(make_region(), - make_scalar(), - make_scalar(), - make_image_filter()); + uint8_t s; + fuzz->nextRange(&s, 0, NUM_FILTERS - 1); + switch (s) { + case ALPHA_THRESHOLD: { + SkRegion reg = make_region(); + SkScalar innerMin, outerMax; + fuzz->next(&innerMin, &outerMax); + sk_sp fil = make_image_filter(); + filter = SkAlphaThresholdFilter::Make(reg, innerMin, outerMax, fil); break; - case MERGE: - filter = SkMergeImageFilter::Make(make_image_filter(), - make_image_filter(), - make_blendmode()); + } + case MERGE: { + sk_sp filA = make_image_filter(); + sk_sp filB = make_image_filter(); + SkBlendMode blend = make_blendmode(); + filter = SkMergeImageFilter::Make(filA, filB, blend); break; + } case COLOR: { sk_sp cf(make_color_filter()); filter = cf ? SkColorFilterImageFilter::Make(std::move(cf), make_image_filter()) @@ -554,102 +609,141 @@ static sk_sp make_image_filter(bool canBeNull) { } case LUT3D: { int cubeDimension; - sk_sp lut3D(make_3Dlut(&cubeDimension, (R(2) == 1), (R(2) == 1), (R(2) == 1))); + bool a, b, c; + fuzz->next(&a, &b, &c); + sk_sp lut3D(make_3Dlut(&cubeDimension, a, b, c)); sk_sp cf(SkColorCubeFilter::Make(std::move(lut3D), cubeDimension)); filter = cf ? SkColorFilterImageFilter::Make(std::move(cf), make_image_filter()) : nullptr; break; } - case BLUR: - filter = SkBlurImageFilter::Make(make_scalar(true), - make_scalar(true), - make_image_filter()); + case BLUR: { + SkScalar sX = make_number(true); + SkScalar sY = make_number(true); + sk_sp fil = make_image_filter(); + + filter = SkBlurImageFilter::Make(sX, sY, fil); break; - case MAGNIFIER: - filter = SkMagnifierImageFilter::Make(make_rect(), - make_scalar(true), - make_image_filter()); + } + case MAGNIFIER: { + SkRect rect = make_rect(); + SkScalar inset = make_number(true); + sk_sp fil = make_image_filter(); + filter = SkMagnifierImageFilter::Make(rect, inset, fil); break; - case BLENDMODE: - filter = SkXfermodeImageFilter::Make(make_blendmode(), - make_image_filter(), - make_image_filter(), - nullptr); + } + case BLENDMODE: { + SkBlendMode mode = make_blendmode(); + sk_sp filA = make_image_filter(); + sk_sp filB = make_image_filter(); + filter = SkXfermodeImageFilter::Make(mode, filA, filB, nullptr); break; - case OFFSET: - filter = SkOffsetImageFilter::Make(make_scalar(), make_scalar(), make_image_filter()); + } + case OFFSET: { + SkScalar dx, dy; + fuzz->next(&dx, &dy); + sk_sp fil = make_image_filter(); + filter = SkOffsetImageFilter::Make(dx, dy, fil); break; - case MATRIX: - filter = SkImageFilter::MakeMatrixFilter(make_matrix(), - (SkFilterQuality)R(4), - make_image_filter()); + } + case MATRIX: { + SkMatrix m; + init_matrix(&m); + int qual; + fuzz->nextRange(&qual, 0, SkFilterQuality::kLast_SkFilterQuality - 1); + sk_sp fil = make_image_filter(); + filter = SkImageFilter::MakeMatrixFilter(m, (SkFilterQuality)qual, fil); break; + } case MATRIX_CONVOLUTION: { SkImageFilter::CropRect cropR(SkRect::MakeWH(SkIntToScalar(kBitmapSize), SkIntToScalar(kBitmapSize))); - SkISize size = SkISize::Make(R(10)+1, R(10)+1); + int w, h; + fuzz->nextRange(&w, 1, 10); + fuzz->nextRange(&h, 1, 10); + SkISize size = SkISize::Make(w, h); int arraySize = size.width() * size.height(); SkTArray kernel(arraySize); for (int i = 0; i < arraySize; ++i) { - kernel.push_back() = make_scalar(); + kernel.push_back() = make_number(false); } - SkIPoint kernelOffset = SkIPoint::Make(R(SkIntToScalar(size.width())), - R(SkIntToScalar(size.height()))); - + fuzz->nextRange(&w, 0, size.width() - 1); + fuzz->nextRange(&h, 0, size.height() - 1); + SkIPoint kernelOffset = SkIPoint::Make(w, h); + int mode; + fuzz->nextRange(&mode, 0, SkMatrixConvolutionImageFilter::kMax_TileMode - 1); + bool convolveAlpha = make_bool(); + SkScalar gain, bias; + fuzz->next(&gain, &bias); + sk_sp fil = make_image_filter(); filter = SkMatrixConvolutionImageFilter::Make(size, kernel.begin(), - make_scalar(), - make_scalar(), + gain, + bias, kernelOffset, - (SkMatrixConvolutionImageFilter::TileMode)R(3), - R(2) == 1, - make_image_filter(), + (SkMatrixConvolutionImageFilter::TileMode)mode, + convolveAlpha, + fil, &cropR); break; } - case COMPOSE: - filter = SkComposeImageFilter::Make(make_image_filter(), make_image_filter()); + case COMPOSE: { + sk_sp filA = make_image_filter(); + sk_sp filB = make_image_filter(); + filter = SkComposeImageFilter::Make(filA, filB); break; - case DISTANT_LIGHT: - filter = (R(2) == 1) - ? SkLightingImageFilter::MakeDistantLitDiffuse(make_point(), make_color(), - make_scalar(), make_scalar(), - make_image_filter()) - : SkLightingImageFilter::MakeDistantLitSpecular(make_point(), make_color(), - make_scalar(), make_scalar(), - SkIntToScalar(R(10)), - make_image_filter()); + } + case DISTANT_LIGHT: { + SkPoint3 p = make_point(); + SkColor c = make_color(); + SkScalar ss, kd; + fuzz->next(&ss, &kd); + int shininess; + fuzz->nextRange(&shininess, 0, 9); + sk_sp fil = make_image_filter(); + filter = make_bool() + ? SkLightingImageFilter::MakeDistantLitDiffuse(p, c, ss, kd, fil) + : SkLightingImageFilter::MakeDistantLitSpecular(p, c, ss, kd, shininess, fil); break; - case POINT_LIGHT: - filter = (R(2) == 1) - ? SkLightingImageFilter::MakePointLitDiffuse(make_point(), make_color(), - make_scalar(), make_scalar(), - make_image_filter()) - : SkLightingImageFilter::MakePointLitSpecular(make_point(), make_color(), - make_scalar(), make_scalar(), - SkIntToScalar(R(10)), - make_image_filter()); + } + case POINT_LIGHT: { + SkPoint3 p = make_point(); + SkColor c = make_color(); + SkScalar ss, kd; + fuzz->next(&ss, &kd); + int shininess; + fuzz->nextRange(&shininess, 0, 9); + sk_sp fil = make_image_filter(); + filter = make_bool() + ? SkLightingImageFilter::MakePointLitDiffuse(p, c, ss, kd, fil) + : SkLightingImageFilter::MakePointLitSpecular(p, c, ss, kd, shininess, fil); break; - case SPOT_LIGHT: - filter = (R(2) == 1) + } + case SPOT_LIGHT: { + SkPoint3 p = make_point(); + SkColor c = make_color(); + SkScalar se, ca, ss, kd; + fuzz->next(&se, &ca, &ss, &kd); + int shininess; + fuzz->nextRange(&shininess, 0, 9); + sk_sp fil = make_image_filter(); + filter = make_bool() ? SkLightingImageFilter::MakeSpotLitDiffuse(SkPoint3::Make(0, 0, 0), - make_point(), make_scalar(), - make_scalar(), make_color(), - make_scalar(), make_scalar(), - make_image_filter()) + p, se, ca, c, ss, kd, fil) : SkLightingImageFilter::MakeSpotLitSpecular(SkPoint3::Make(0, 0, 0), - make_point(), make_scalar(), - make_scalar(), make_color(), - make_scalar(), make_scalar(), - SkIntToScalar(R(10)), - make_image_filter()); + p, se, ca, c, ss, kd, + shininess, fil); break; + } case NOISE: { - sk_sp shader((R(2) == 1) - ? SkPerlinNoiseShader::MakeFractalNoise(make_scalar(true), make_scalar(true), - R(10.0f), make_scalar()) - : SkPerlinNoiseShader::MakeTurbulence(make_scalar(true), make_scalar(true), - R(10.0f), make_scalar())); + SkScalar bfx = make_number(true); + SkScalar bfy = make_number(true); + SkScalar seed = make_number(false); + int octaves; + fuzz->nextRange(&octaves, 0, 9); + sk_sp shader(make_bool() + ? SkPerlinNoiseShader::MakeFractalNoise(bfx, bfy, octaves, seed) + : SkPerlinNoiseShader::MakeTurbulence(bfx, bfy, octaves, seed)); SkPaint paint; paint.setShader(shader); SkImageFilter::CropRect cropR(SkRect::MakeWH(SkIntToScalar(kBitmapSize), @@ -657,30 +751,32 @@ static sk_sp make_image_filter(bool canBeNull) { filter = SkPaintImageFilter::Make(paint, &cropR); break; } - case DROP_SHADOW: - filter = SkDropShadowImageFilter::Make(make_scalar(), - make_scalar(), - make_scalar(true), - make_scalar(true), - make_color(), - make_shadow_mode(), - make_image_filter(), - nullptr); + case DROP_SHADOW: { + SkScalar dx, dy, sx, sy; + fuzz->next(&dx, &dy); + sx = make_number(true); + sy = make_number(true); + SkColor c = make_color(); + SkDropShadowImageFilter::ShadowMode mode = make_shadow_mode(); + sk_sp fil = make_image_filter(); + filter = SkDropShadowImageFilter::Make(dx, dy, sx, sy, c, mode, fil, nullptr); break; - case MORPHOLOGY: - if (R(2) == 1) { - filter = SkDilateImageFilter::Make(R(static_cast(kBitmapSize)), - R(static_cast(kBitmapSize)), - make_image_filter()); + } + case MORPHOLOGY: { + int rx, ry; + fuzz->nextRange(&rx, 0, kBitmapSize); + fuzz->nextRange(&ry, 0, kBitmapSize); + sk_sp fil = make_image_filter(); + if (make_bool()) { + filter = SkDilateImageFilter::Make(rx, ry, fil); } else { - filter = SkErodeImageFilter::Make(R(static_cast(kBitmapSize)), - R(static_cast(kBitmapSize)), - make_image_filter()); + filter = SkErodeImageFilter::Make(rx, ry, fil); } break; + } case BITMAP: { sk_sp image(SkImage::MakeFromBitmap(make_bitmap())); - if (R(2) == 1) { + if (make_bool()) { filter = SkImageSource::Make(std::move(image), make_rect(), make_rect(), @@ -690,16 +786,23 @@ static sk_sp make_image_filter(bool canBeNull) { } break; } - case DISPLACE: - filter = SkDisplacementMapEffect::Make(make_channel_selector_type(), - make_channel_selector_type(), - make_scalar(), - make_image_filter(false), - make_image_filter()); + case DISPLACE: { + SkDisplacementMapEffect::ChannelSelectorType x = make_channel_selector_type(); + SkDisplacementMapEffect::ChannelSelectorType y = make_channel_selector_type(); + SkScalar scale = make_number(false); + sk_sp filA = make_image_filter(false); + sk_sp filB = make_image_filter(); + + filter = SkDisplacementMapEffect::Make(x, y, scale, filA, filB); break; - case TILE: - filter = SkTileImageFilter::Make(make_rect(), make_rect(), make_image_filter(false)); + } + case TILE: { + SkRect src = make_rect(); + SkRect dest = make_rect(); + sk_sp fil = make_image_filter(false); + filter = SkTileImageFilter::Make(src, dest, fil); break; + } case PICTURE: { SkRTreeFactory factory; SkPictureRecorder recorder; @@ -730,9 +833,15 @@ static sk_sp make_serialized_image_filter() { #ifdef SK_ADD_RANDOM_BIT_FLIPS unsigned char* p = const_cast(ptr); for (size_t i = 0; i < len; ++i, ++p) { - if (R(250) == 1) { // 0.4% of the time, flip a bit or byte - if (R(10) == 1) { // Then 10% of the time, change a whole byte - switch(R(3)) { + uint8_t j; + fuzz->nextRange(&j, 1, 250); + if (j == 1) { // 0.4% of the time, flip a bit or byte + uint8_t k; + fuzz->nextRange(&k, 1, 10); + if (k == 1) { // Then 10% of the time, change a whole byte + uint8_t s; + fuzz->nextRange(&s, 0, 2); + switch(s) { case 0: *p ^= 0xFF; // Flip entire byte break; @@ -744,7 +853,9 @@ static sk_sp make_serialized_image_filter() { break; } } else { - *p ^= (1 << R(8)); + uint8_t s; + fuzz->nextRange(&s, 0, 7); + *p ^= (1 << 7); } } } diff --git a/fuzz/Fuzz.h b/fuzz/Fuzz.h index 17d75f4d34..5cc8bd21d8 100644 --- a/fuzz/Fuzz.h +++ b/fuzz/Fuzz.h @@ -23,12 +23,28 @@ public: // Returns if there are no bytes remaining for fuzzing. bool exhausted(); + // next() loads fuzzed bytes into the variable passed in by pointer. + // We use this approach instead of T next() because different compilers + // evaluate function parameters in different orders. If fuzz->next() + // returned 5 and then 7, foo(fuzz->next(), fuzz->next()) would be + // foo(5, 7) when compiled on GCC and foo(7, 5) when compiled on Clang. + // By requiring params to be passed in, we avoid the temptation to call + // next() in a way that does not consume fuzzed bytes in a single + // uplatform-independent order. template - T next(); + void next(T* t); + + // This is a convenient way to initialize more than one argument at a time. + template + void next(Arg* first, Args... rest); // nextRange returns values only in [min, max]. + template + void nextRange(T*, Min, Max); + + // nextN loads n * sizeof(T) bytes into ptr template - T nextRange(T min, T max); + void nextN(T* ptr, int n); void signalBug(); // Tell afl-fuzz these inputs found a bug. @@ -42,58 +58,66 @@ private: // UBSAN reminds us that bool can only legally hold 0 or 1. template <> -inline bool Fuzz::next() { - return (this->next() & 1) == 1; +inline void Fuzz::next(bool* b) { + uint8_t n; + this->next(&n); + *b = (n & 1) == 1; } template -T Fuzz::next() { +inline void Fuzz::next(T* n) { if ((fNextByte + sizeof(T)) > fBytes->size()) { - T n = 0; - memcpy(&n, fBytes->bytes() + fNextByte, fBytes->size() - fNextByte); + *n = 0; + memcpy(n, fBytes->bytes() + fNextByte, fBytes->size() - fNextByte); fNextByte = fBytes->size(); - return n; + return; } - T n; - memcpy(&n, fBytes->bytes() + fNextByte, sizeof(T)); + memcpy(n, fBytes->bytes() + fNextByte, sizeof(T)); fNextByte += sizeof(T); - return n; +} + +template +inline void Fuzz::next(Arg* first, Args... rest) { + this->next(first); + this->next(rest...); } template <> -inline float Fuzz::nextRange(float min, float max) { - if (min > max) { - SkDebugf("Check mins and maxes (%f, %f)\n", min, max); - this->signalBug(); - } - float f = this->next(); - if (!std::isnormal(f) && f != 0.0f) { +inline void Fuzz::nextRange(float* f, float min, float max) { + this->next(f); + if (!std::isnormal(*f) && *f != 0.0f) { // Don't deal with infinity or other strange floats. - return max; + *f = max; } - return min + std::fmod(std::abs(f), (max - min + 1)); + *f = min + std::fmod(std::abs(*f), (max - min + 1)); } -template -T Fuzz::nextRange(T min, T max) { - if (min > max) { - SkDebugf("Check mins and maxes (%d, %d)\n", min, max); - this->signalBug(); - } - T n = this->next(); +template +inline void Fuzz::nextRange(T* n, Min min, Max max) { + this->next(n); T range = max - min + 1; if (0 == range) { - return n; + return; } else { - n = abs(n); - if (n < 0) { + if (*n < 0) { + *n = *n * -1; + } + if (*n < 0) { // abs(INT_MIN) = INT_MIN, so we check this to avoid accidental negatives. - return min; + *n = min; + return; } - return min + n % range; + *n = min + *n % range; } } +template +inline void Fuzz::nextN(T* ptr, int n) { + for (int i = 0; i < n; i++) { + this->next(ptr+i); + } +} + struct Fuzzable { const char* name; void (*fn)(Fuzz*); diff --git a/fuzz/FuzzGradients.cpp b/fuzz/FuzzGradients.cpp index df36c7ce8f..90d4066a80 100644 --- a/fuzz/FuzzGradients.cpp +++ b/fuzz/FuzzGradients.cpp @@ -17,22 +17,30 @@ const int MAX_COUNT = 400; void makeMatrix(Fuzz* fuzz, SkMatrix* m) { - m->setAll(fuzz->next(), fuzz->next(), fuzz->next(), - fuzz->next(), fuzz->next(), fuzz->next(), - fuzz->next(), fuzz->next(), fuzz->next()); + SkScalar mat[9]; + fuzz->nextN(mat, 9); + m->set9(mat); } void initGradientParams(Fuzz* fuzz, std::vector* colors, std::vector* pos, SkShader::TileMode* mode) { - int count = fuzz->nextRange(0, MAX_COUNT); + int count; + fuzz->nextRange(&count, 0, MAX_COUNT); - *mode = static_cast(fuzz->nextRange(0, 2)); + // Use a uint8_t to conserve bytes. This makes our "fuzzed bytes footprint" + // smaller, which leads to more efficient fuzzing. + uint8_t m; + fuzz->nextRange(&m, 0, 2); + *mode = static_cast(m); colors->clear(); pos ->clear(); for (int i = 0; i < count; i++) { - colors->push_back(fuzz->next()); - pos ->push_back(fuzz->next()); + SkColor c; + SkScalar s; + fuzz->next(&c, &s); + colors->push_back(c); + pos ->push_back(s); } if (count) { std::sort(pos->begin(), pos->end()); @@ -43,10 +51,10 @@ void initGradientParams(Fuzz* fuzz, std::vector* colors, } void fuzzLinearGradient(Fuzz* fuzz) { - SkPoint pts[2] = {SkPoint::Make(fuzz->next(), fuzz->next()), - SkPoint::Make(fuzz->next(), fuzz->next())}; - bool useLocalMatrix = fuzz->next(); - bool useGlobalMatrix = fuzz->next(); + SkPoint pts[2]; + fuzz->next(&pts[0].fX, &pts[0].fY, &pts[1].fX, &pts[1].fY); + bool useLocalMatrix, useGlobalMatrix; + fuzz->next(&useLocalMatrix, &useGlobalMatrix); std::vector colors; std::vector pos; @@ -54,7 +62,8 @@ void fuzzLinearGradient(Fuzz* fuzz) { initGradientParams(fuzz, &colors, &pos, &mode); SkPaint p; - uint32_t flags = fuzz->next(); + uint32_t flags; + fuzz->next(&flags); SkTLazy localMatrix; if (useLocalMatrix) { @@ -76,10 +85,11 @@ void fuzzLinearGradient(Fuzz* fuzz) { } void fuzzRadialGradient(Fuzz* fuzz) { - SkPoint center = SkPoint::Make(fuzz->next(), fuzz->next()); - SkScalar radius = fuzz->next(); - bool useLocalMatrix = fuzz->next(); - bool useGlobalMatrix = fuzz->next(); + SkPoint center; + fuzz->next(¢er.fX, ¢er.fY); + SkScalar radius; + bool useLocalMatrix, useGlobalMatrix; + fuzz->next(&radius, &useLocalMatrix, &useGlobalMatrix); std::vector colors; @@ -88,7 +98,8 @@ void fuzzRadialGradient(Fuzz* fuzz) { initGradientParams(fuzz, &colors, &pos, &mode); SkPaint p; - uint32_t flags = fuzz->next(); + uint32_t flags; + fuzz->next(&flags); SkTLazy localMatrix; if (useLocalMatrix) { @@ -111,12 +122,13 @@ void fuzzRadialGradient(Fuzz* fuzz) { } void fuzzTwoPointConicalGradient(Fuzz* fuzz) { - SkPoint start = SkPoint::Make(fuzz->next(), fuzz->next()); - SkPoint end = SkPoint::Make(fuzz->next(), fuzz->next()); - SkScalar startRadius = fuzz->next(); - SkScalar endRadius = fuzz->next(); - bool useLocalMatrix = fuzz->next(); - bool useGlobalMatrix = fuzz->next(); + SkPoint start; + fuzz->next(&start.fX, &start.fY); + SkPoint end; + fuzz->next(&end.fX, &end.fY); + SkScalar startRadius, endRadius; + bool useLocalMatrix, useGlobalMatrix; + fuzz->next(&startRadius, &endRadius, &useLocalMatrix, &useGlobalMatrix); std::vector colors; std::vector pos; @@ -124,7 +136,8 @@ void fuzzTwoPointConicalGradient(Fuzz* fuzz) { initGradientParams(fuzz, &colors, &pos, &mode); SkPaint p; - uint32_t flags = fuzz->next(); + uint32_t flags; + fuzz->next(&flags); SkTLazy localMatrix; if (useLocalMatrix) { @@ -147,10 +160,9 @@ void fuzzTwoPointConicalGradient(Fuzz* fuzz) { } void fuzzSweepGradient(Fuzz* fuzz) { - SkScalar cx = fuzz->next(); - SkScalar cy = fuzz->next(); - bool useLocalMatrix = fuzz->next(); - bool useGlobalMatrix = fuzz->next(); + SkScalar cx, cy; + bool useLocalMatrix, useGlobalMatrix; + fuzz->next(&cx, &cy, &useLocalMatrix, &useGlobalMatrix); std::vector colors; std::vector pos; @@ -161,7 +173,8 @@ void fuzzSweepGradient(Fuzz* fuzz) { if (useLocalMatrix) { SkMatrix m; makeMatrix(fuzz, &m); - uint32_t flags = fuzz->next(); + uint32_t flags; + fuzz->next(&flags); p.setShader(SkGradientShader::MakeSweep(cx, cy, colors.data(), pos.data(), colors.size(), flags, &m)); @@ -183,7 +196,8 @@ void fuzzSweepGradient(Fuzz* fuzz) { } DEF_FUZZ(Gradients, fuzz) { - uint8_t i = fuzz->next(); + uint8_t i; + fuzz->next(&i); switch(i) { case 0: diff --git a/fuzz/FuzzParsePath.cpp b/fuzz/FuzzParsePath.cpp index 1a597d87a0..90b99ca8e5 100644 --- a/fuzz/FuzzParsePath.cpp +++ b/fuzz/FuzzParsePath.cpp @@ -39,9 +39,13 @@ static void add_white(Fuzz* fuzz, SkString* atom) { atom->append(" "); return; } - int reps = fuzz->nextRange(0, 2); - for (int rep = 0; rep < reps; ++rep) { - int index = fuzz->nextRange(0, (int) SK_ARRAY_COUNT(gWhiteSpace) - 1); + // Use a uint8_t to conserve bytes. This makes our "fuzzed bytes footprint" + // smaller, which leads to more efficient fuzzing. + uint8_t reps; + fuzz->nextRange(&reps, 0, 2); + for (uint8_t rep = 0; rep < reps; ++rep) { + uint8_t index; + fuzz->nextRange(&index, 0, SK_ARRAY_COUNT(gWhiteSpace) - 1); if (gWhiteSpace[index]) { atom->append(&gWhiteSpace[index], 1); } @@ -60,7 +64,9 @@ static void add_comma(Fuzz* fuzz, SkString* atom) { return; } add_white(fuzz, atom); - if (fuzz->next()) { + bool b; + fuzz->next(&b); + if (b) { atom->append(","); } add_some_white(fuzz, atom); @@ -68,15 +74,20 @@ static void add_comma(Fuzz* fuzz, SkString* atom) { SkString MakeRandomParsePathPiece(Fuzz* fuzz) { SkString atom; - int index = fuzz->nextRange(0, (int) SK_ARRAY_COUNT(gLegal) - 1); + uint8_t index; + fuzz->nextRange(&index, 0, SK_ARRAY_COUNT(gLegal) - 1); const Legal& legal = gLegal[index]; gEasy ? atom.append("\n") : add_white(fuzz, &atom); - char symbol = legal.fSymbol | (fuzz->next() ? 0x20 : 0); + bool b; + fuzz->next(&b); + char symbol = legal.fSymbol | (b ? 0x20 : 0); atom.append(&symbol, 1); - int reps = fuzz->nextRange(1, 3); + uint8_t reps; + fuzz->nextRange(&reps, 1, 3); for (int rep = 0; rep < reps; ++rep) { for (int index = 0; index < legal.fScalars; ++index) { - SkScalar coord = fuzz->nextRange(0.0f, 100.0f); + SkScalar coord; + fuzz->nextRange(&coord, 0.0f, 100.0f); add_white(fuzz, &atom); atom.appendScalar(coord); if (rep < reps - 1 && index < legal.fScalars - 1) { @@ -85,11 +96,15 @@ SkString MakeRandomParsePathPiece(Fuzz* fuzz) { add_some_white(fuzz, &atom); } if ('A' == legal.fSymbol && 1 == index) { - atom.appendScalar(fuzz->nextRange(-720.0f, 720.0f)); + SkScalar s; + fuzz->nextRange(&s, -720.0f, 720.0f); + atom.appendScalar(s); add_comma(fuzz, &atom); - atom.appendU32(fuzz->nextRange(0, 1)); + fuzz->next(&b); + atom.appendU32(b); add_comma(fuzz, &atom); - atom.appendU32(fuzz->nextRange(0, 1)); + fuzz->next(&b); + atom.appendU32(b); add_comma(fuzz, &atom); } } @@ -100,8 +115,9 @@ SkString MakeRandomParsePathPiece(Fuzz* fuzz) { DEF_FUZZ(ParsePath, fuzz) { SkPath path; SkString spec; - uint32_t count = fuzz->nextRange(0, 40); - for (uint32_t i = 0; i < count; ++i) { + uint8_t count; + fuzz->nextRange(&count, 0, 40); + for (uint8_t i = 0; i < count; ++i) { spec.append(MakeRandomParsePathPiece(fuzz)); } SkDebugf("SkParsePath::FromSVGString(%s, &path);\n",spec.c_str()); diff --git a/fuzz/FuzzPathop.cpp b/fuzz/FuzzPathop.cpp index a555cd6344..f20352436c 100644 --- a/fuzz/FuzzPathop.cpp +++ b/fuzz/FuzzPathop.cpp @@ -15,32 +15,36 @@ void BuildPath(Fuzz* fuzz, SkPath* path, int last_verb) { while (!fuzz->exhausted()) { - uint8_t operation = fuzz->next(); + // Use a uint8_t to conserve bytes. This makes our "fuzzed bytes footprint" + // smaller, which leads to more efficient fuzzing. + uint8_t operation; + fuzz->next(&operation); + SkScalar a,b,c,d,e,f; switch (operation % (last_verb + 1)) { case SkPath::Verb::kMove_Verb: - path->moveTo(fuzz->next(), fuzz->next()); + fuzz->next(&a, &b); + path->moveTo(a, b); break; case SkPath::Verb::kLine_Verb: - path->lineTo(fuzz->next(), fuzz->next()); + fuzz->next(&a, &b); + path->lineTo(a, b); break; case SkPath::Verb::kQuad_Verb: - path->quadTo(fuzz->next(), fuzz->next(), - fuzz->next(), fuzz->next()); + fuzz->next(&a, &b, &c, &d); + path->quadTo(a, b, c, d); break; case SkPath::Verb::kConic_Verb: - path->conicTo(fuzz->next(), fuzz->next(), - fuzz->next(), fuzz->next(), - fuzz->next()); + fuzz->next(&a, &b, &c, &d, &e); + path->conicTo(a, b, c, d, e); break; case SkPath::Verb::kCubic_Verb: - path->cubicTo(fuzz->next(), fuzz->next(), - fuzz->next(), fuzz->next(), - fuzz->next(), fuzz->next()); + fuzz->next(&a, &b, &c, &d, &e, &f); + path->cubicTo(a, b, c, d, e, f); break; case SkPath::Verb::kClose_Verb: @@ -57,7 +61,8 @@ void BuildPath(Fuzz* fuzz, DEF_FUZZ(Pathop, fuzz) { SkOpBuilder builder; - uint8_t stragglerOp = fuzz->next(); + uint8_t stragglerOp; + fuzz->next(&stragglerOp); SkPath path; BuildPath(fuzz, &path, SkPath::Verb::kDone_Verb); diff --git a/fuzz/FuzzScaleToSides.cpp b/fuzz/FuzzScaleToSides.cpp index dd2ffcca88..943ce5c8e0 100644 --- a/fuzz/FuzzScaleToSides.cpp +++ b/fuzz/FuzzScaleToSides.cpp @@ -16,9 +16,8 @@ #include DEF_FUZZ(ScaleToSides, fuzz) { - float radius1 = fuzz->next(), - radius2 = fuzz->next(), - width = fuzz->next(); + float radius1, radius2, width; + fuzz->next(&radius1, &radius2, &width); if (!std::isfinite(radius1) || !std::isfinite(radius2) || -- cgit v1.2.3