Add SkRuntimeEffect Fuzzer
The major improvement is that now the fuzzer is able to execute
the sksl code (before it just compiled it). The fuzzer will
reserve 256 bytes for providing uniforms to the shader;
meanwhile, the fuzzer will read the remaining bytes as sksl code
to create SkRuntimeEffect. It then creates a shader and executes
it by painting the shader on a canvas.
The code was tested locally with afl-fuzz, and the execution
speed was around 700/sec.
An alternative implementation would have been using Fuzz.h to
read bytes; I decided to go with sk_sp<SkData> since it has a
comparable format to other binary fuzzer and meets all the
functionality in this fuzzer.
For future changes, there are 2 important improvements to the
implementation:
1) Current shader does not have children shaders; thus,
makeShader() will fail if the SkSL ever tries to use an 'in shader'.
As pointed out in patchset 11, after creating the runtime effect,
effect->children().count() will tell you how many children it's
expecting (how many 'in shader' variables were declared). When you
call makeShader(), the second and third arguments are a
(C-style) array of shader pointers, and
a count (which must match children().count()).
Some helpful examples can be SkRTShader::CreateProc in
SkRuntimeEffect.cpp, make_fuzz_shader in FuzzCanvas.cpp.
2)
In this fuzzer, after creating the paint from a shader, the paint
can be drawn on either GPU canvas or CPU, so a possible way is to
use SkSurface::MakeRenderTarget to create GPU canvas and use a byte
to determine which canvas it will be drawn on.
Change-Id: Ib0385edd0f5ec2f23744aa517135a6955c53ba38
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300618
Commit-Queue: Zepeng Hu <zepenghu@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
2020-07-10 13:36:20 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2020 Google, LLC
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "include/core/SkCanvas.h"
|
2022-02-12 01:07:54 +00:00
|
|
|
#include "include/core/SkColorFilter.h"
|
Add SkRuntimeEffect Fuzzer
The major improvement is that now the fuzzer is able to execute
the sksl code (before it just compiled it). The fuzzer will
reserve 256 bytes for providing uniforms to the shader;
meanwhile, the fuzzer will read the remaining bytes as sksl code
to create SkRuntimeEffect. It then creates a shader and executes
it by painting the shader on a canvas.
The code was tested locally with afl-fuzz, and the execution
speed was around 700/sec.
An alternative implementation would have been using Fuzz.h to
read bytes; I decided to go with sk_sp<SkData> since it has a
comparable format to other binary fuzzer and meets all the
functionality in this fuzzer.
For future changes, there are 2 important improvements to the
implementation:
1) Current shader does not have children shaders; thus,
makeShader() will fail if the SkSL ever tries to use an 'in shader'.
As pointed out in patchset 11, after creating the runtime effect,
effect->children().count() will tell you how many children it's
expecting (how many 'in shader' variables were declared). When you
call makeShader(), the second and third arguments are a
(C-style) array of shader pointers, and
a count (which must match children().count()).
Some helpful examples can be SkRTShader::CreateProc in
SkRuntimeEffect.cpp, make_fuzz_shader in FuzzCanvas.cpp.
2)
In this fuzzer, after creating the paint from a shader, the paint
can be drawn on either GPU canvas or CPU, so a possible way is to
use SkSurface::MakeRenderTarget to create GPU canvas and use a byte
to determine which canvas it will be drawn on.
Change-Id: Ib0385edd0f5ec2f23744aa517135a6955c53ba38
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300618
Commit-Queue: Zepeng Hu <zepenghu@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
2020-07-10 13:36:20 +00:00
|
|
|
#include "include/core/SkPaint.h"
|
2022-02-12 01:07:54 +00:00
|
|
|
#include "include/core/SkShader.h"
|
Add SkRuntimeEffect Fuzzer
The major improvement is that now the fuzzer is able to execute
the sksl code (before it just compiled it). The fuzzer will
reserve 256 bytes for providing uniforms to the shader;
meanwhile, the fuzzer will read the remaining bytes as sksl code
to create SkRuntimeEffect. It then creates a shader and executes
it by painting the shader on a canvas.
The code was tested locally with afl-fuzz, and the execution
speed was around 700/sec.
An alternative implementation would have been using Fuzz.h to
read bytes; I decided to go with sk_sp<SkData> since it has a
comparable format to other binary fuzzer and meets all the
functionality in this fuzzer.
For future changes, there are 2 important improvements to the
implementation:
1) Current shader does not have children shaders; thus,
makeShader() will fail if the SkSL ever tries to use an 'in shader'.
As pointed out in patchset 11, after creating the runtime effect,
effect->children().count() will tell you how many children it's
expecting (how many 'in shader' variables were declared). When you
call makeShader(), the second and third arguments are a
(C-style) array of shader pointers, and
a count (which must match children().count()).
Some helpful examples can be SkRTShader::CreateProc in
SkRuntimeEffect.cpp, make_fuzz_shader in FuzzCanvas.cpp.
2)
In this fuzzer, after creating the paint from a shader, the paint
can be drawn on either GPU canvas or CPU, so a possible way is to
use SkSurface::MakeRenderTarget to create GPU canvas and use a byte
to determine which canvas it will be drawn on.
Change-Id: Ib0385edd0f5ec2f23744aa517135a6955c53ba38
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300618
Commit-Queue: Zepeng Hu <zepenghu@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
2020-07-10 13:36:20 +00:00
|
|
|
#include "include/core/SkSurface.h"
|
2022-02-12 01:07:54 +00:00
|
|
|
#include "include/effects/SkBlenders.h"
|
Add SkRuntimeEffect Fuzzer
The major improvement is that now the fuzzer is able to execute
the sksl code (before it just compiled it). The fuzzer will
reserve 256 bytes for providing uniforms to the shader;
meanwhile, the fuzzer will read the remaining bytes as sksl code
to create SkRuntimeEffect. It then creates a shader and executes
it by painting the shader on a canvas.
The code was tested locally with afl-fuzz, and the execution
speed was around 700/sec.
An alternative implementation would have been using Fuzz.h to
read bytes; I decided to go with sk_sp<SkData> since it has a
comparable format to other binary fuzzer and meets all the
functionality in this fuzzer.
For future changes, there are 2 important improvements to the
implementation:
1) Current shader does not have children shaders; thus,
makeShader() will fail if the SkSL ever tries to use an 'in shader'.
As pointed out in patchset 11, after creating the runtime effect,
effect->children().count() will tell you how many children it's
expecting (how many 'in shader' variables were declared). When you
call makeShader(), the second and third arguments are a
(C-style) array of shader pointers, and
a count (which must match children().count()).
Some helpful examples can be SkRTShader::CreateProc in
SkRuntimeEffect.cpp, make_fuzz_shader in FuzzCanvas.cpp.
2)
In this fuzzer, after creating the paint from a shader, the paint
can be drawn on either GPU canvas or CPU, so a possible way is to
use SkSurface::MakeRenderTarget to create GPU canvas and use a byte
to determine which canvas it will be drawn on.
Change-Id: Ib0385edd0f5ec2f23744aa517135a6955c53ba38
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300618
Commit-Queue: Zepeng Hu <zepenghu@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
2020-07-10 13:36:20 +00:00
|
|
|
#include "include/effects/SkRuntimeEffect.h"
|
2022-04-07 15:20:24 +00:00
|
|
|
#include "src/gpu/ganesh/GrShaderCaps.h"
|
Add SkRuntimeEffect Fuzzer
The major improvement is that now the fuzzer is able to execute
the sksl code (before it just compiled it). The fuzzer will
reserve 256 bytes for providing uniforms to the shader;
meanwhile, the fuzzer will read the remaining bytes as sksl code
to create SkRuntimeEffect. It then creates a shader and executes
it by painting the shader on a canvas.
The code was tested locally with afl-fuzz, and the execution
speed was around 700/sec.
An alternative implementation would have been using Fuzz.h to
read bytes; I decided to go with sk_sp<SkData> since it has a
comparable format to other binary fuzzer and meets all the
functionality in this fuzzer.
For future changes, there are 2 important improvements to the
implementation:
1) Current shader does not have children shaders; thus,
makeShader() will fail if the SkSL ever tries to use an 'in shader'.
As pointed out in patchset 11, after creating the runtime effect,
effect->children().count() will tell you how many children it's
expecting (how many 'in shader' variables were declared). When you
call makeShader(), the second and third arguments are a
(C-style) array of shader pointers, and
a count (which must match children().count()).
Some helpful examples can be SkRTShader::CreateProc in
SkRuntimeEffect.cpp, make_fuzz_shader in FuzzCanvas.cpp.
2)
In this fuzzer, after creating the paint from a shader, the paint
can be drawn on either GPU canvas or CPU, so a possible way is to
use SkSurface::MakeRenderTarget to create GPU canvas and use a byte
to determine which canvas it will be drawn on.
Change-Id: Ib0385edd0f5ec2f23744aa517135a6955c53ba38
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300618
Commit-Queue: Zepeng Hu <zepenghu@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
2020-07-10 13:36:20 +00:00
|
|
|
|
|
|
|
#include "fuzz/Fuzz.h"
|
|
|
|
|
|
|
|
/**
|
2022-02-12 01:07:54 +00:00
|
|
|
* The fuzzer treats the input bytes as an SkSL program. The requested number of uniforms and
|
|
|
|
* children are automatically synthesized to match the program's needs.
|
2020-08-12 14:25:31 +00:00
|
|
|
*
|
|
|
|
* We fuzz twice, with two different settings for inlining in the SkSL compiler. By default, the
|
|
|
|
* compiler inlines most small to medium functions. This can hide bugs related to function-calling.
|
2022-02-12 01:07:54 +00:00
|
|
|
* So we run the fuzzer once with inlining disabled, and again with it enabled.
|
2020-08-12 14:25:31 +00:00
|
|
|
* This gives us better coverage, and eases the burden on the fuzzer to inject useless noise into
|
|
|
|
* functions to suppress inlining.
|
Add SkRuntimeEffect Fuzzer
The major improvement is that now the fuzzer is able to execute
the sksl code (before it just compiled it). The fuzzer will
reserve 256 bytes for providing uniforms to the shader;
meanwhile, the fuzzer will read the remaining bytes as sksl code
to create SkRuntimeEffect. It then creates a shader and executes
it by painting the shader on a canvas.
The code was tested locally with afl-fuzz, and the execution
speed was around 700/sec.
An alternative implementation would have been using Fuzz.h to
read bytes; I decided to go with sk_sp<SkData> since it has a
comparable format to other binary fuzzer and meets all the
functionality in this fuzzer.
For future changes, there are 2 important improvements to the
implementation:
1) Current shader does not have children shaders; thus,
makeShader() will fail if the SkSL ever tries to use an 'in shader'.
As pointed out in patchset 11, after creating the runtime effect,
effect->children().count() will tell you how many children it's
expecting (how many 'in shader' variables were declared). When you
call makeShader(), the second and third arguments are a
(C-style) array of shader pointers, and
a count (which must match children().count()).
Some helpful examples can be SkRTShader::CreateProc in
SkRuntimeEffect.cpp, make_fuzz_shader in FuzzCanvas.cpp.
2)
In this fuzzer, after creating the paint from a shader, the paint
can be drawn on either GPU canvas or CPU, so a possible way is to
use SkSurface::MakeRenderTarget to create GPU canvas and use a byte
to determine which canvas it will be drawn on.
Change-Id: Ib0385edd0f5ec2f23744aa517135a6955c53ba38
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300618
Commit-Queue: Zepeng Hu <zepenghu@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
2020-07-10 13:36:20 +00:00
|
|
|
*/
|
2022-02-12 01:07:54 +00:00
|
|
|
static bool FuzzSkRuntimeEffect_Once(sk_sp<SkData> codeBytes,
|
|
|
|
const SkRuntimeEffect::Options& options) {
|
2021-02-03 16:15:20 +00:00
|
|
|
SkString shaderText{static_cast<const char*>(codeBytes->data()), codeBytes->size()};
|
2021-04-26 14:53:08 +00:00
|
|
|
SkRuntimeEffect::Result result = SkRuntimeEffect::MakeForShader(shaderText, options);
|
2021-02-03 16:15:20 +00:00
|
|
|
SkRuntimeEffect* effect = result.effect.get();
|
2022-02-12 01:07:54 +00:00
|
|
|
if (!effect) {
|
Add SkRuntimeEffect Fuzzer
The major improvement is that now the fuzzer is able to execute
the sksl code (before it just compiled it). The fuzzer will
reserve 256 bytes for providing uniforms to the shader;
meanwhile, the fuzzer will read the remaining bytes as sksl code
to create SkRuntimeEffect. It then creates a shader and executes
it by painting the shader on a canvas.
The code was tested locally with afl-fuzz, and the execution
speed was around 700/sec.
An alternative implementation would have been using Fuzz.h to
read bytes; I decided to go with sk_sp<SkData> since it has a
comparable format to other binary fuzzer and meets all the
functionality in this fuzzer.
For future changes, there are 2 important improvements to the
implementation:
1) Current shader does not have children shaders; thus,
makeShader() will fail if the SkSL ever tries to use an 'in shader'.
As pointed out in patchset 11, after creating the runtime effect,
effect->children().count() will tell you how many children it's
expecting (how many 'in shader' variables were declared). When you
call makeShader(), the second and third arguments are a
(C-style) array of shader pointers, and
a count (which must match children().count()).
Some helpful examples can be SkRTShader::CreateProc in
SkRuntimeEffect.cpp, make_fuzz_shader in FuzzCanvas.cpp.
2)
In this fuzzer, after creating the paint from a shader, the paint
can be drawn on either GPU canvas or CPU, so a possible way is to
use SkSurface::MakeRenderTarget to create GPU canvas and use a byte
to determine which canvas it will be drawn on.
Change-Id: Ib0385edd0f5ec2f23744aa517135a6955c53ba38
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300618
Commit-Queue: Zepeng Hu <zepenghu@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
2020-07-10 13:36:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
2022-02-12 01:07:54 +00:00
|
|
|
|
|
|
|
// Create storage for our uniforms.
|
|
|
|
sk_sp<SkData> uniformBytes = SkData::MakeZeroInitialized(effect->uniformSize());
|
|
|
|
void* uniformData = uniformBytes->writable_data();
|
|
|
|
|
|
|
|
for (const SkRuntimeEffect::Uniform& u : effect->uniforms()) {
|
|
|
|
// We treat scalars, vectors, matrices and arrays the same. We just figure out how many
|
|
|
|
// uniform slots need to be filled, and write consecutive numbers into those slots.
|
|
|
|
static_assert(sizeof(int) == 4 && sizeof(float) == 4);
|
|
|
|
size_t numFields = u.sizeInBytes() / 4;
|
|
|
|
|
|
|
|
if (u.type == SkRuntimeEffect::Uniform::Type::kInt ||
|
|
|
|
u.type == SkRuntimeEffect::Uniform::Type::kInt2 ||
|
|
|
|
u.type == SkRuntimeEffect::Uniform::Type::kInt3 ||
|
|
|
|
u.type == SkRuntimeEffect::Uniform::Type::kInt4) {
|
|
|
|
int intVal = 0;
|
|
|
|
while (numFields--) {
|
|
|
|
// Assign increasing integer values to each slot (0, 1, 2, ...).
|
|
|
|
*static_cast<int*>(uniformData) = intVal++;
|
|
|
|
uniformData = static_cast<int*>(uniformData) + 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
float floatVal = 0.0f;
|
|
|
|
while (numFields--) {
|
|
|
|
// Assign increasing float values to each slot (0.0, 1.0, 2.0, ...).
|
|
|
|
*static_cast<float*>(uniformData) = floatVal++;
|
|
|
|
uniformData = static_cast<float*>(uniformData) + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create valid children for any requested child effects.
|
|
|
|
std::vector<SkRuntimeEffect::ChildPtr> children;
|
|
|
|
children.reserve(effect->children().size());
|
|
|
|
for (const SkRuntimeEffect::Child& c : effect->children()) {
|
|
|
|
switch (c.type) {
|
|
|
|
case SkRuntimeEffect::ChildType::kShader:
|
|
|
|
children.push_back(SkShaders::Color(SK_ColorRED));
|
|
|
|
break;
|
|
|
|
case SkRuntimeEffect::ChildType::kColorFilter:
|
|
|
|
children.push_back(SkColorFilters::Blend(SK_ColorBLUE, SkBlendMode::kModulate));
|
|
|
|
break;
|
|
|
|
case SkRuntimeEffect::ChildType::kBlender:
|
|
|
|
children.push_back(SkBlenders::Arithmetic(0.50f, 0.25f, 0.10f, 0.05f, false));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sk_sp<SkShader> shader = effect->makeShader(uniformBytes, SkMakeSpan(children));
|
Add SkRuntimeEffect Fuzzer
The major improvement is that now the fuzzer is able to execute
the sksl code (before it just compiled it). The fuzzer will
reserve 256 bytes for providing uniforms to the shader;
meanwhile, the fuzzer will read the remaining bytes as sksl code
to create SkRuntimeEffect. It then creates a shader and executes
it by painting the shader on a canvas.
The code was tested locally with afl-fuzz, and the execution
speed was around 700/sec.
An alternative implementation would have been using Fuzz.h to
read bytes; I decided to go with sk_sp<SkData> since it has a
comparable format to other binary fuzzer and meets all the
functionality in this fuzzer.
For future changes, there are 2 important improvements to the
implementation:
1) Current shader does not have children shaders; thus,
makeShader() will fail if the SkSL ever tries to use an 'in shader'.
As pointed out in patchset 11, after creating the runtime effect,
effect->children().count() will tell you how many children it's
expecting (how many 'in shader' variables were declared). When you
call makeShader(), the second and third arguments are a
(C-style) array of shader pointers, and
a count (which must match children().count()).
Some helpful examples can be SkRTShader::CreateProc in
SkRuntimeEffect.cpp, make_fuzz_shader in FuzzCanvas.cpp.
2)
In this fuzzer, after creating the paint from a shader, the paint
can be drawn on either GPU canvas or CPU, so a possible way is to
use SkSurface::MakeRenderTarget to create GPU canvas and use a byte
to determine which canvas it will be drawn on.
Change-Id: Ib0385edd0f5ec2f23744aa517135a6955c53ba38
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300618
Commit-Queue: Zepeng Hu <zepenghu@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
2020-07-10 13:36:20 +00:00
|
|
|
if (!shader) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setShader(std::move(shader));
|
|
|
|
|
|
|
|
sk_sp<SkSurface> s = SkSurface::MakeRasterN32Premul(128, 128);
|
|
|
|
if (!s) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
s->getCanvas()->drawPaint(paint);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-08-12 14:25:31 +00:00
|
|
|
bool FuzzSkRuntimeEffect(sk_sp<SkData> bytes) {
|
2022-05-11 13:44:28 +00:00
|
|
|
// Test once with optimization disabled...
|
2021-02-03 16:15:20 +00:00
|
|
|
SkRuntimeEffect::Options options;
|
2022-05-11 13:44:28 +00:00
|
|
|
options.forceUnoptimized = true;
|
2021-02-03 16:15:20 +00:00
|
|
|
bool result = FuzzSkRuntimeEffect_Once(bytes, options);
|
2020-08-12 14:25:31 +00:00
|
|
|
|
2022-05-11 13:44:28 +00:00
|
|
|
// ... and then with optimization enabled.
|
|
|
|
options.forceUnoptimized = false;
|
2021-02-03 16:15:20 +00:00
|
|
|
result = FuzzSkRuntimeEffect_Once(bytes, options) || result;
|
2020-08-12 14:25:31 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-09-14 12:37:35 +00:00
|
|
|
#if defined(SK_BUILD_FOR_LIBFUZZER)
|
Add SkRuntimeEffect Fuzzer
The major improvement is that now the fuzzer is able to execute
the sksl code (before it just compiled it). The fuzzer will
reserve 256 bytes for providing uniforms to the shader;
meanwhile, the fuzzer will read the remaining bytes as sksl code
to create SkRuntimeEffect. It then creates a shader and executes
it by painting the shader on a canvas.
The code was tested locally with afl-fuzz, and the execution
speed was around 700/sec.
An alternative implementation would have been using Fuzz.h to
read bytes; I decided to go with sk_sp<SkData> since it has a
comparable format to other binary fuzzer and meets all the
functionality in this fuzzer.
For future changes, there are 2 important improvements to the
implementation:
1) Current shader does not have children shaders; thus,
makeShader() will fail if the SkSL ever tries to use an 'in shader'.
As pointed out in patchset 11, after creating the runtime effect,
effect->children().count() will tell you how many children it's
expecting (how many 'in shader' variables were declared). When you
call makeShader(), the second and third arguments are a
(C-style) array of shader pointers, and
a count (which must match children().count()).
Some helpful examples can be SkRTShader::CreateProc in
SkRuntimeEffect.cpp, make_fuzz_shader in FuzzCanvas.cpp.
2)
In this fuzzer, after creating the paint from a shader, the paint
can be drawn on either GPU canvas or CPU, so a possible way is to
use SkSurface::MakeRenderTarget to create GPU canvas and use a byte
to determine which canvas it will be drawn on.
Change-Id: Ib0385edd0f5ec2f23744aa517135a6955c53ba38
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300618
Commit-Queue: Zepeng Hu <zepenghu@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
2020-07-10 13:36:20 +00:00
|
|
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|
|
|
if (size > 3000) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
auto bytes = SkData::MakeWithoutCopy(data, size);
|
|
|
|
FuzzSkRuntimeEffect(bytes);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|