Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
FuzzSkMeshSpecification.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2022 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
10
11#include "fuzz/Fuzz.h"
12
13using namespace skia_private;
14
15template <typename T>
17 T result = 0;
18 size_t bytesToCopy = std::min(sizeof(T), data.size());
19 if (bytesToCopy > 0) {
20 memcpy(&result, &data.front(), bytesToCopy);
21 data = data.subspan(bytesToCopy);
22 }
23 return result;
24}
25
26void FuzzSkMeshSpecification(const uint8_t *fuzzData, size_t fuzzSize) {
29
30 SkSpan<const uint8_t> data(fuzzData, fuzzSize);
33 size_t vertexStride;
34 SkString vs, fs;
35
36 auto fuzzByteToASCII = [&](uint8_t c, SkString* str) -> bool {
37 // Most control characters (including \0) and all high ASCII are treated as stop bytes.
38 if ((c >= 32 && c <= 127) || c == '\r' || c == '\n' || c == '\t') {
39 char ascii = c;
40 str->append(&ascii, 1);
41 return true;
42 }
43 return false;
44 };
45
46 auto fuzzByteToSkSL = [&](uint8_t c, SkString* str) -> bool {
47 // In the 0x00 - 0x80 range, treat characters as ASCII.
48 if (c < 128) {
49 return fuzzByteToASCII(c, str);
50 }
51 c -= 128;
52
53 // Dedicate a few bytes to injecting our attribute and varying names.
55 if (!attributes.empty()) {
56 str->append(attributes[c % attributes.size()].name);
57 }
58 return true;
59 }
61
63 if (!varyings.empty()) {
64 str->append(varyings[c % varyings.size()].name);
65 }
66 return true;
67 }
69
70 // Replace the remaining high-ASCII bytes with valid SkSL operators and keywords in order to
71 // improve our chances of generating a program. (We omit single-character operators since
72 // single-byte versions of those already exist in the low-ASCII space.)
73 static constexpr std::string_view kSkSLData[] = {
74 " true ",
75 " false ",
76 " if ",
77 " else ",
78 " for ",
79 " while ",
80 " do ",
81 " switch ",
82 " case ",
83 " default ",
84 " break ",
85 " continue ",
86 " discard ",
87 " return ",
88 " in ",
89 " out ",
90 " inout ",
91 " uniform ",
92 " const ",
93 " flat ",
94 " noperspective ",
95 " inline ",
96 " noinline ",
97 " $pure ",
98 " readonly ",
99 " writeonly ",
100 " buffer ",
101 " struct ",
102 " layout ",
103 " highp ",
104 " mediump ",
105 " lowp ",
106 " $es3 ",
107 " $export ",
108 " workgroup ",
109 " << ",
110 " >> ",
111 " && ",
112 " || ",
113 " ^^ ",
114 " == ",
115 " != ",
116 " <= ",
117 " >= ",
118 " += ",
119 " -= ",
120 " *= ",
121 " /= ",
122 " %= ",
123 " <<= ",
124 " >>= ",
125 " &= ",
126 " |= ",
127 " ^= ",
128 " ++ ",
129 " -- ",
130 " //",
131 " /*",
132 "*/ ",
133 " float",
134 " half",
135 " int",
136 " uint",
137 " short",
138 " ushort",
139 " bool",
140 " void",
141 " vec",
142 " ivec",
143 " bvec",
144 " mat",
145 " Attributes ",
146 " Varyings ",
147 };
148
149 c %= std::size(kSkSLData);
150 str->append(kSkSLData[c]);
151 return true;
152 };
153
154 // Pick a vertex stride; intentionally allow some bad values through.
155 vertexStride = extract<uint16_t>(data) % (SkMeshSpecification::kMaxStride + 2);
156
157 while (!data.empty()) {
158 uint8_t control = extract<uint8_t>(data) % 4;
159 // A control code with no payload can be ignored.
160 if (data.empty()) {
161 break;
162 }
163 switch (control) {
164 case 0: {
165 // Add an attribute.
166 Attribute& a = attributes.push_back();
167 a.type = (Attribute::Type)(extract<uint8_t>(data) %
169 a.offset = extract<uint16_t>(data) % (SkMeshSpecification::kMaxStride + 2);
170 while (uint8_t c = extract<char>(data)) {
171 if (!fuzzByteToASCII(c, &a.name)) {
172 break;
173 }
174 }
175 break;
176 }
177 case 1: {
178 // Add a varying.
179 Varying& v = varyings.push_back();
180 v.type = (Varying::Type)(extract<uint8_t>(data) % ((int)Varying::Type::kLast + 1));
181 while (uint8_t c = extract<char>(data)) {
182 if (!fuzzByteToASCII(c, &v.name)) {
183 break;
184 }
185 }
186 break;
187 }
188 case 2: {
189 // Convert the following data into SkSL and add it into the vertex program.
190 while (uint8_t c = extract<char>(data)) {
191 if (!fuzzByteToSkSL(c, &vs)) {
192 break;
193 }
194 }
195 break;
196 }
197 case 3: {
198 // Convert the following data into SkSL and add it into the fragment program.
199 while (uint8_t c = extract<char>(data)) {
200 if (!fuzzByteToSkSL(c, &fs)) {
201 break;
202 }
203 }
204 break;
205 }
206 }
207 }
208
209 auto result = SkMeshSpecification::Make(attributes, vertexStride, varyings, vs, fs);
210 if (result.error.isEmpty()) {
211 // TODO: synthesize a mesh with this specification and paint it.
212 printf("----\n%s\n----\n\n----\n%s\n----\n\n\n", vs.c_str(), fs.c_str());
213 }
214}
215
216#if defined(SK_BUILD_FOR_LIBFUZZER)
217extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
218 if (size > 8000) {
219 return 0;
220 }
221 FuzzSkMeshSpecification(data, size);
222 return 0;
223}
224#endif
T extract(SkSpan< const uint8_t > &data)
void FuzzSkMeshSpecification(const uint8_t *fuzzData, size_t fuzzSize)
Type::kYUV Type::kRGBA() int(0.7 *637)
static constexpr size_t kMaxVaryings
Definition SkMesh.h:72
static constexpr size_t kMaxAttributes
Definition SkMesh.h:69
static constexpr size_t kMaxStride
Definition SkMesh.h:68
static Result Make(SkSpan< const Attribute > attributes, size_t vertexStride, SkSpan< const Varying > varyings, const SkString &vs, const SkString &fs)
Definition SkMesh.cpp:389
void append(const char text[])
Definition SkString.h:203
const char * c_str() const
Definition SkString.h:133
bool empty() const
Definition SkTArray.h:194
int size() const
Definition SkTArray.h:416
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
struct MyStruct a[10]
GAsyncResult * result
#define T