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