• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SkColorFilter.h"
10 #include "include/core/SkPaint.h"
11 #include "include/core/SkShader.h"
12 #include "include/core/SkSurface.h"
13 #include "include/effects/SkBlenders.h"
14 #include "include/effects/SkRuntimeEffect.h"
15 #include "src/gpu/GrShaderCaps.h"
16 
17 #include "fuzz/Fuzz.h"
18 
19 /**
20  * The fuzzer treats the input bytes as an SkSL program. The requested number of uniforms and
21  * children are automatically synthesized to match the program's needs.
22  *
23  * We fuzz twice, with two different settings for inlining in the SkSL compiler. By default, the
24  * compiler inlines most small to medium functions. This can hide bugs related to function-calling.
25  * So we run the fuzzer once with inlining disabled, and again with it enabled.
26  * This gives us better coverage, and eases the burden on the fuzzer to inject useless noise into
27  * functions to suppress inlining.
28  */
FuzzSkRuntimeEffect_Once(sk_sp<SkData> codeBytes,const SkRuntimeEffect::Options & options)29 static bool FuzzSkRuntimeEffect_Once(sk_sp<SkData> codeBytes,
30                                      const SkRuntimeEffect::Options& options) {
31     SkString shaderText{static_cast<const char*>(codeBytes->data()), codeBytes->size()};
32     SkRuntimeEffect::Result result = SkRuntimeEffect::MakeForShader(shaderText, options);
33     SkRuntimeEffect* effect = result.effect.get();
34     if (!effect) {
35         return false;
36     }
37 
38     // Create storage for our uniforms.
39     sk_sp<SkData> uniformBytes = SkData::MakeZeroInitialized(effect->uniformSize());
40     void* uniformData = uniformBytes->writable_data();
41 
42     for (const SkRuntimeEffect::Uniform& u : effect->uniforms()) {
43         // We treat scalars, vectors, matrices and arrays the same. We just figure out how many
44         // uniform slots need to be filled, and write consecutive numbers into those slots.
45         static_assert(sizeof(int) == 4 && sizeof(float) == 4);
46         size_t numFields = u.sizeInBytes() / 4;
47 
48         if (u.type == SkRuntimeEffect::Uniform::Type::kInt ||
49             u.type == SkRuntimeEffect::Uniform::Type::kInt2 ||
50             u.type == SkRuntimeEffect::Uniform::Type::kInt3 ||
51             u.type == SkRuntimeEffect::Uniform::Type::kInt4) {
52             int intVal = 0;
53             while (numFields--) {
54                 // Assign increasing integer values to each slot (0, 1, 2, ...).
55                 *static_cast<int*>(uniformData) = intVal++;
56                 uniformData = static_cast<int*>(uniformData) + 1;
57             }
58         } else {
59             float floatVal = 0.0f;
60             while (numFields--) {
61                 // Assign increasing float values to each slot (0.0, 1.0, 2.0, ...).
62                 *static_cast<float*>(uniformData) = floatVal++;
63                 uniformData = static_cast<float*>(uniformData) + 1;
64             }
65         }
66     }
67 
68     // Create valid children for any requested child effects.
69     std::vector<SkRuntimeEffect::ChildPtr> children;
70     children.reserve(effect->children().size());
71     for (const SkRuntimeEffect::Child& c : effect->children()) {
72         switch (c.type) {
73             case SkRuntimeEffect::ChildType::kShader:
74                 children.push_back(SkShaders::Color(SK_ColorRED));
75                 break;
76             case SkRuntimeEffect::ChildType::kColorFilter:
77                 children.push_back(SkColorFilters::Blend(SK_ColorBLUE, SkBlendMode::kModulate));
78                 break;
79             case SkRuntimeEffect::ChildType::kBlender:
80                 children.push_back(SkBlenders::Arithmetic(0.50f, 0.25f, 0.10f, 0.05f, false));
81                 break;
82         }
83     }
84 
85     sk_sp<SkShader> shader = effect->makeShader(uniformBytes, SkMakeSpan(children));
86     if (!shader) {
87         return false;
88     }
89     SkPaint paint;
90     paint.setShader(std::move(shader));
91 
92     sk_sp<SkSurface> s = SkSurface::MakeRasterN32Premul(128, 128);
93     if (!s) {
94         return false;
95     }
96     s->getCanvas()->drawPaint(paint);
97 
98     return true;
99 }
100 
FuzzSkRuntimeEffect(sk_sp<SkData> bytes)101 bool FuzzSkRuntimeEffect(sk_sp<SkData> bytes) {
102     // Test once with the inliner disabled...
103     SkRuntimeEffect::Options options;
104     options.forceNoInline = true;
105     bool result = FuzzSkRuntimeEffect_Once(bytes, options);
106 
107     // ... and then with the inliner enabled.
108     options.forceNoInline = false;
109     result = FuzzSkRuntimeEffect_Once(bytes, options) || result;
110 
111     return result;
112 }
113 
114 #if defined(SK_BUILD_FOR_LIBFUZZER)
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)115 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
116     if (size > 3000) {
117         return 0;
118     }
119     auto bytes = SkData::MakeWithoutCopy(data, size);
120     FuzzSkRuntimeEffect(bytes);
121     return 0;
122 }
123 #endif
124