1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2020 Google, LLC 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 9cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 10cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 11cb93a386Sopenharmony_ci#include "include/effects/SkRuntimeEffect.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrShaderCaps.h" 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_ci#include "fuzz/Fuzz.h" 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_cistatic constexpr size_t kReservedBytes = 256; 17cb93a386Sopenharmony_ci/** 18cb93a386Sopenharmony_ci * The fuzzer will take in the bytes and divide into two parts. 19cb93a386Sopenharmony_ci * original bytes : [... code bytes ... | 256 bytes] 20cb93a386Sopenharmony_ci * The first part is codeBytes, the original bytes minus 256 bytes, which will be treated 21cb93a386Sopenharmony_ci * as sksl code, intending to create SkRuntimeEffect. 22cb93a386Sopenharmony_ci * For the second part, it will first reserve 256 bytes and then allocate bytes with same size 23cb93a386Sopenharmony_ci * as effect->inputSize() to uniformBytes. The uniformBytes is intended to create makeShader(). 24cb93a386Sopenharmony_ci * Note that if uniformBytes->size() != effect->inputSize() the shader won't be created. 25cb93a386Sopenharmony_ci * 26cb93a386Sopenharmony_ci * We fuzz twice, with two different settings for inlining in the SkSL compiler. By default, the 27cb93a386Sopenharmony_ci * compiler inlines most small to medium functions. This can hide bugs related to function-calling. 28cb93a386Sopenharmony_ci * So we run the fuzzer once with inlining disabled, and again with it enabled (aggressively). 29cb93a386Sopenharmony_ci * This gives us better coverage, and eases the burden on the fuzzer to inject useless noise into 30cb93a386Sopenharmony_ci * functions to suppress inlining. 31cb93a386Sopenharmony_ci */ 32cb93a386Sopenharmony_cistatic bool FuzzSkRuntimeEffect_Once(sk_sp<SkData> bytes, const SkRuntimeEffect::Options& options) { 33cb93a386Sopenharmony_ci if (bytes->size() < kReservedBytes) { 34cb93a386Sopenharmony_ci return false; 35cb93a386Sopenharmony_ci } 36cb93a386Sopenharmony_ci sk_sp<SkData> codeBytes = SkData::MakeSubset(bytes.get(), 0, bytes->size() - kReservedBytes); 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci SkString shaderText{static_cast<const char*>(codeBytes->data()), codeBytes->size()}; 39cb93a386Sopenharmony_ci SkRuntimeEffect::Result result = SkRuntimeEffect::MakeForShader(shaderText, options); 40cb93a386Sopenharmony_ci SkRuntimeEffect* effect = result.effect.get(); 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci if (!effect || effect->uniformSize() > kReservedBytes) { // if there is not enough uniform bytes 43cb93a386Sopenharmony_ci return false; 44cb93a386Sopenharmony_ci } 45cb93a386Sopenharmony_ci sk_sp<SkData> uniformBytes = 46cb93a386Sopenharmony_ci SkData::MakeSubset(bytes.get(), bytes->size() - kReservedBytes, effect->uniformSize()); 47cb93a386Sopenharmony_ci auto shader = effect->makeShader(uniformBytes, /*children=*/nullptr, /*childCount=*/0, 48cb93a386Sopenharmony_ci /*localMatrix=*/nullptr, /*isOpaque=*/false); 49cb93a386Sopenharmony_ci if (!shader) { 50cb93a386Sopenharmony_ci return false; 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci SkPaint paint; 53cb93a386Sopenharmony_ci paint.setShader(std::move(shader)); 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_ci sk_sp<SkSurface> s = SkSurface::MakeRasterN32Premul(128, 128); 56cb93a386Sopenharmony_ci if (!s) { 57cb93a386Sopenharmony_ci return false; 58cb93a386Sopenharmony_ci } 59cb93a386Sopenharmony_ci s->getCanvas()->drawPaint(paint); 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci return true; 62cb93a386Sopenharmony_ci} 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_cibool FuzzSkRuntimeEffect(sk_sp<SkData> bytes) { 65cb93a386Sopenharmony_ci // Test once with the inliner disabled... 66cb93a386Sopenharmony_ci SkRuntimeEffect::Options options; 67cb93a386Sopenharmony_ci options.forceNoInline = true; 68cb93a386Sopenharmony_ci bool result = FuzzSkRuntimeEffect_Once(bytes, options); 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci // ... and then with the inliner enabled. 71cb93a386Sopenharmony_ci options.forceNoInline = false; 72cb93a386Sopenharmony_ci result = FuzzSkRuntimeEffect_Once(bytes, options) || result; 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ci return result; 75cb93a386Sopenharmony_ci} 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_LIBFUZZER) 78cb93a386Sopenharmony_ciextern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 79cb93a386Sopenharmony_ci if (size > 3000) { 80cb93a386Sopenharmony_ci return 0; 81cb93a386Sopenharmony_ci } 82cb93a386Sopenharmony_ci auto bytes = SkData::MakeWithoutCopy(data, size); 83cb93a386Sopenharmony_ci FuzzSkRuntimeEffect(bytes); 84cb93a386Sopenharmony_ci return 0; 85cb93a386Sopenharmony_ci} 86cb93a386Sopenharmony_ci#endif 87