Commit 965db511 authored by Kenneth Russell's avatar Kenneth Russell Committed by Commit Bot

Revert "Add scaffolding for structured GPU command buffer fuzzer"

This reverts commit 8afc180c.

Reason for revert: broke build on GPU FYI Win x64 debug builder:
https://ci.chromium.org/p/chromium/builders/ci/GPU%20FYI%20Win%20x64%20Builder%20(dbg)/13152?blamelist=1#blamelist-tab

Original change's description:
> Add scaffolding for structured GPU command buffer fuzzer
> 
> This CL contains a basic fuzzer for WebGL shaders that shows some
> essential design ideas:
> 
> 1) a protobuf spec defines how shaders will be generated
> 2) conversion from protobuf message to shader string is
>    provided in its own library that has unit tests
> 3) we add a basic fuzzer to compile shader programs using libANGLE
> 
> This is by no means complete and serves as a foundation for the fuzzer
> so subsequent CLs will be easier to review. Later CLs will slowly complete
> the core grammar for GLSL before incorporating some more complex testcases
> from the Khronos compliance suite.
> 
> BUG=900487
> 
> Change-Id: I67df52a73926d22637afad9a966790f34011175c
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1623556
> Commit-Queue: Ned Williamson <nedwill@google.com>
> Reviewed-by: Peter Kasting <pkasting@chromium.org>
> Reviewed-by: Kenneth Russell <kbr@chromium.org>
> Reviewed-by: Antoine Labour <piman@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#662832}

TBR=pkasting@chromium.org,kbr@chromium.org,piman@chromium.org,xyzzyz@chromium.org,nedwill@google.com

Change-Id: I91debbc67cebc46ecdcaa06b6b1cf587fae781f1
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 900487
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1627825Reviewed-by: default avatarKenneth Russell <kbr@chromium.org>
Commit-Queue: Kenneth Russell <kbr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#662929}
parent 909d1836
...@@ -6,7 +6,6 @@ import("//build/config/jumbo.gni") ...@@ -6,7 +6,6 @@ import("//build/config/jumbo.gni")
import("//build/config/ui.gni") import("//build/config/ui.gni")
import("//testing/libfuzzer/fuzzer_test.gni") import("//testing/libfuzzer/fuzzer_test.gni")
import("//testing/test.gni") import("//testing/test.gni")
import("//third_party/protobuf/proto_library.gni")
import("//ui/gl/features.gni") import("//ui/gl/features.gni")
config("gpu_implementation") { config("gpu_implementation") {
...@@ -197,68 +196,6 @@ jumbo_static_library("test_support") { ...@@ -197,68 +196,6 @@ jumbo_static_library("test_support") {
] ]
} }
if (!is_android && !is_fuchsia) {
proto_library("gl_lpm_fuzzer_proto") {
sources = [
"command_buffer/tests/lpm/gl_lpm_fuzzer.proto",
]
}
static_library("gl_lpm_shader_to_string") {
sources = [
"command_buffer/tests/lpm/gl_lpm_shader_to_string.cc",
"command_buffer/tests/lpm/gl_lpm_shader_to_string.h",
]
deps = [
":gl_lpm_fuzzer_proto",
"//base:base",
]
}
test("gl_lpm_shader_to_string_unittest") {
sources = [
"command_buffer/tests/lpm/gl_lpm_shader_to_string_unittest.cc",
]
deps = [
":gl_lpm_shader_to_string",
"//base/test:run_all_unittests",
"//testing/gtest",
"//third_party/protobuf:protobuf_full",
]
}
fuzzer_test("gl_lpm_fuzzer") {
sources = [
"command_buffer/tests/gl_manager.cc",
"command_buffer/tests/gl_manager.h",
"command_buffer/tests/gl_test_utils.cc",
"command_buffer/tests/gl_test_utils.h",
"command_buffer/tests/lpm/gl_lpm_fuzzer.cc",
]
defines = [ "GL_GLEXT_PROTOTYPES" ]
deps = [
":gl_lpm_fuzzer_proto",
":gl_lpm_shader_to_string",
":gles2",
":test_support",
"//gpu/command_buffer/client:gles2_c_lib",
"//gpu/command_buffer/client:gles2_implementation",
"//gpu/command_buffer/common:gles2_utils",
"//gpu/ipc:gl_in_process_context",
"//gpu/ipc/service:service",
"//testing/gtest:gtest",
"//third_party/libprotobuf-mutator",
"//ui/gfx:gfx",
"//ui/gl:gl",
"//ui/gl/init:init",
]
}
}
test("gl_tests") { test("gl_tests") {
sources = [ sources = [
"command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc", "command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc",
......
...@@ -5,7 +5,7 @@ include_rules = [ ...@@ -5,7 +5,7 @@ include_rules = [
"+third_party/re2", "+third_party/re2",
"+third_party/smhasher", "+third_party/smhasher",
"+third_party/swiftshader", "+third_party/swiftshader",
"+third_party/protobuf", "+third_party/protbuf",
"+third_party/zlib", "+third_party/zlib",
"+crypto", "+crypto",
"+ui/gfx", "+ui/gfx",
......
...@@ -78,14 +78,14 @@ bool GLTestHelper::HasExtension(const char* extension) { ...@@ -78,14 +78,14 @@ bool GLTestHelper::HasExtension(const char* extension) {
} }
bool GLTestHelper::CheckGLError(const char* msg, int line) { bool GLTestHelper::CheckGLError(const char* msg, int line) {
bool success = true; bool success = true;
GLenum error = GL_NO_ERROR; GLenum error = GL_NO_ERROR;
while ((error = glGetError()) != GL_NO_ERROR) { while ((error = glGetError()) != GL_NO_ERROR) {
success = false; success = false;
EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), error) EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), error)
<< "GL ERROR in " << msg << " at line " << line << " : " << error; << "GL ERROR in " << msg << " at line " << line << " : " << error;
} }
return success; return success;
} }
GLuint GLTestHelper::CompileShader(GLenum type, const char* shaderSrc) { GLuint GLTestHelper::CompileShader(GLenum type, const char* shaderSrc) {
...@@ -277,7 +277,7 @@ struct BitmapInfoHeader{ ...@@ -277,7 +277,7 @@ struct BitmapInfoHeader{
uint8_t clr_important[4]; uint8_t clr_important[4];
}; };
} // namespace }
bool GLTestHelper::SaveBackbufferAsBMP( bool GLTestHelper::SaveBackbufferAsBMP(
const char* filename, int width, int height) { const char* filename, int width, int height) {
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
#endif
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES2/gl2extchromium.h>
#include <GLES3/gl3.h>
#include <stdint.h>
#include <vector>
#include "base/command_line.h"
#include "base/i18n/icu_util.h"
#include "base/strings/string_split.h"
#include "gpu/command_buffer/client/gles2_lib.h"
#include "gpu/command_buffer/tests/gl_manager.h"
#include "gpu/command_buffer/tests/gl_test_utils.h"
#include "gpu/command_buffer/tests/lpm/gl_lpm_fuzzer.pb.h"
#include "gpu/command_buffer/tests/lpm/gl_lpm_shader_to_string.h"
#include "gpu/config/gpu_test_config.h"
#include "testing/libfuzzer/proto/lpm_interface.h"
#include "ui/gfx/extension_set.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_version_info.h"
#include "ui/gl/init/gl_factory.h"
struct Env {
Env() {
CHECK(base::i18n::InitializeICU());
base::CommandLine::Init(0, nullptr);
auto* command_line = base::CommandLine::ForCurrentProcess();
// TODO(nedwill): support switches for swiftshader, etc.
command_line->AppendSwitchASCII(switches::kUseGL,
gl::kGLImplementationANGLEName);
command_line->AppendSwitchASCII(switches::kUseANGLE,
gl::kANGLEImplementationNullName);
base::FeatureList::InitializeInstance(std::string(), std::string());
base::MessageLoopForIO message_loop;
gpu::GLTestHelper::InitializeGLDefault();
::gles2::Initialize();
}
};
class ScopedGLManager {
public:
ScopedGLManager() {
gpu::GLManager::Options options;
gl_.Initialize(options);
}
~ScopedGLManager() { gl_.Destroy(); }
private:
gpu::GLManager gl_;
};
GLuint CompileShader(GLenum type, const char* shaderSrc) {
GLuint shader = glCreateShader(type);
// Load the shader source
glShaderSource(shader, 1, &shaderSrc, nullptr);
// Compile the shader
glCompileShader(shader);
return shader;
}
const char* acceptable_errors[] = {
"void function cannot return a value",
"function already has a body",
"undeclared identifier",
"l-value required (can't modify a const)",
"cannot convert from",
"main function cannot return a value",
"illegal use of type 'void'",
"boolean expression expected",
"Missing main()",
"Divide by zero error during constant folding",
// TODO(nedwill): enable GLSL ES 3.00
"operator supported in GLSL ES 3.00 and above only",
"wrong operand types",
"function must have the same return type in all of its declarations",
"function return is not matching type",
"redefinition",
"WARNING:",
"can't modify void",
};
// Filter errors which we don't think interfere with fuzzing everything.
bool ErrorOk(const base::StringPiece line) {
for (base::StringPiece acceptable_error : acceptable_errors) {
if (line.find(acceptable_error) != base::StringPiece::npos) {
return true;
}
}
LOG(WARNING) << "failed due to line: " << line;
return false;
}
bool ErrorsOk(const base::StringPiece log) {
std::vector<std::string> lines = base::SplitString(
log, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
for (const auto& line : lines) {
if (!ErrorOk(line)) {
return false;
}
}
return true;
}
GLuint LoadShader(GLenum type, const fuzzing::Shader& shader_proto) {
std::string shader_s = gl_lpm_fuzzer::GetShader(shader_proto);
if (shader_s.empty()) {
return 0;
}
GLuint shader = CompileShader(type, shader_s.c_str());
// Check the compile status
GLint value = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &value);
if (value == 0) {
char buffer[1024];
GLsizei length = 0;
glGetShaderInfoLog(shader, sizeof(buffer), &length, buffer);
base::StringPiece log(buffer, length);
if (value != 1 && !ErrorsOk(log)) {
LOG(WARNING) << "Encountered an unexpected failure when translating:\n"
<< log << "\nfailed to compile shader:\n"
<< shader_proto.DebugString() << "converted:\n"
<< shader_s;
}
glDeleteShader(shader);
shader = 0;
}
return shader;
}
DEFINE_PROTO_FUZZER(const fuzzing::Session& session) {
static Env* env = new Env();
CHECK(env);
// TODO(nedwill): Creating a new GLManager on each iteration
// is expensive. We should investigate ways to avoid expensive
// initialization.
ScopedGLManager scoped_gl_manager;
GLuint vertex_shader_id =
LoadShader(GL_VERTEX_SHADER, session.vertex_shader());
GLuint fragment_shader_id =
LoadShader(GL_FRAGMENT_SHADER, session.fragment_shader());
if (!vertex_shader_id || !fragment_shader_id) {
return;
}
GLuint program =
gpu::GLTestHelper::SetupProgram(vertex_shader_id, fragment_shader_id);
if (!program) {
return;
}
glUseProgram(program);
// Relink program.
glLinkProgram(program);
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// This proto description is adapted from the one used in clang-proto-fuzzer.
syntax = "proto2";
package fuzzing;
// TODO(nedwill): fuzz the following features
// function prototypes
// (in)variance
// structs
// interface blocks
// swizzles
// all binary operators
// all unary operators
// all ternary operators
// switch/case statements
// loops
// branches (case, break, continue, return, kill)
// preprocessor directives
enum Var {
VAR_0 = 0;
VAR_1 = 1;
VAR_2 = 2;
VAR_3 = 3;
}
message Lvalue {
optional Var var = 1;
}
message Const {
optional int32 val = 1;
}
message BinaryOp {
enum Op {
// TODO: actually use ops from GLSL spec, not c++
PLUS = 0;
MINUS = 1;
MUL = 2;
DIV = 3;
MOD = 4;
XOR = 5;
AND = 6;
OR = 7;
EQ = 8;
NE = 9;
LE = 10;
GE = 11;
LT = 12;
GT = 13;
};
optional Op op = 1;
optional Rvalue left = 2;
optional Rvalue right = 3;
}
message Declare {
optional Type type = 1;
optional Var var = 2;
}
message Rvalue {
oneof rvalue {
Var var = 1;
Const cons = 2;
BinaryOp binary_op = 3;
}
}
message Assignment {
optional Lvalue lvalue = 1;
optional Rvalue rvalue = 2;
}
message IfElse {
optional Rvalue cond = 1;
optional Block if_body = 2;
optional Block else_body = 3;
}
message While {
optional Rvalue cond = 1;
optional Block body = 2;
}
message Statement {
oneof statement {
Assignment assignment = 1;
IfElse ifelse = 2;
While while_stmt = 3;
Rvalue return_stmt = 4;
Declare declare = 5;
}
}
enum FunctionName {
MAIN = 0;
NAME_1 = 1;
NAME_2 = 2;
NAME_3 = 3;
}
message Block {
repeated Statement statements = 1;
}
enum Type {
// Use suffix to avoid clashing with VOID define on Windows
VOID_TYPE = 0;
INT = 1;
}
message Function {
optional FunctionName function_name = 1;
optional Block block = 2;
optional Rvalue return_stmt = 3;
optional Type type = 4;
}
message Shader {
repeated Function functions = 1;
}
message Session {
optional Shader vertex_shader = 1;
optional Shader fragment_shader = 2;
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/tests/lpm/gl_lpm_shader_to_string.h"
#include <ostream>
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
namespace gl_lpm_fuzzer {
std::string GetFunctionName(const fuzzing::FunctionName& function_name) {
if (function_name == fuzzing::MAIN) {
return "main";
}
return "f" + base::NumberToString(function_name);
}
std::string GetType(const fuzzing::Type& type) {
switch (type) {
case fuzzing::VOID_TYPE: {
return "void";
}
case fuzzing::INT: {
return "int";
}
}
CHECK(false);
return "";
}
std::ostream& operator<<(std::ostream& os, const fuzzing::Statement& statement);
std::ostream& operator<<(std::ostream& os, const fuzzing::Rvalue& rvalue);
std::ostream& operator<<(std::ostream& os, const fuzzing::Block& block) {
for (const fuzzing::Statement& statement : block.statements()) {
os << statement;
}
return os;
}
std::ostream& operator<<(std::ostream& os, const fuzzing::IfElse& ifelse) {
return os << "if (" << ifelse.cond() << ") {\n"
<< ifelse.if_body() << "} else {\n"
<< ifelse.else_body() << "}\n";
}
std::ostream& operator<<(std::ostream& os, const fuzzing::Const& cons) {
return os << base::NumberToString(cons.val());
}
std::string GetOp(const fuzzing::BinaryOp::Op op) {
switch (op) {
case fuzzing::BinaryOp::PLUS:
return "+";
case fuzzing::BinaryOp::MINUS:
return "-";
case fuzzing::BinaryOp::MUL:
return "*";
case fuzzing::BinaryOp::DIV:
return "/";
case fuzzing::BinaryOp::MOD:
return "%";
case fuzzing::BinaryOp::XOR:
return "^";
case fuzzing::BinaryOp::AND:
return "&&";
case fuzzing::BinaryOp::OR:
return "||";
case fuzzing::BinaryOp::EQ:
return "==";
case fuzzing::BinaryOp::NE:
return "!=";
case fuzzing::BinaryOp::LE:
return "<=";
case fuzzing::BinaryOp::GE:
return ">=";
case fuzzing::BinaryOp::LT:
return "<";
case fuzzing::BinaryOp::GT:
return ">";
default:
DCHECK(false);
}
return "";
}
std::ostream& operator<<(std::ostream& os, const fuzzing::BinaryOp& binary_op) {
return os << "(" << binary_op.left() << " " << GetOp(binary_op.op()) << " "
<< binary_op.right() << ")";
}
std::ostream& operator<<(std::ostream& os, const fuzzing::Rvalue& rvalue) {
switch (rvalue.rvalue_case()) {
case fuzzing::Rvalue::kVar: {
os << rvalue.var();
break;
}
case fuzzing::Rvalue::kCons: {
os << rvalue.cons();
break;
}
case fuzzing::Rvalue::kBinaryOp: {
os << rvalue.binary_op();
break;
}
case fuzzing::Rvalue::RVALUE_NOT_SET: {
os << "1";
break;
}
}
return os;
}
std::ostream& operator<<(std::ostream& os, const fuzzing::While& while_stmt) {
return os << "while (" << while_stmt.cond() << ") {\n"
<< while_stmt.body() << "}\n";
}
std::string GetVar(const fuzzing::Var& var) {
return "var" + base::NumberToString(var);
}
std::ostream& operator<<(std::ostream& os, const fuzzing::Lvalue& lvalue) {
return os << GetVar(lvalue.var());
}
std::ostream& operator<<(std::ostream& os,
const fuzzing::Assignment& assignment) {
return os << assignment.lvalue() << " = " << assignment.rvalue() << ";\n";
}
std::ostream& operator<<(std::ostream& os, const fuzzing::Declare& declare) {
return os << GetType(declare.type()) << " " << GetVar(declare.var()) << ";\n";
}
std::ostream& operator<<(std::ostream& os,
const fuzzing::Statement& statement) {
switch (statement.statement_case()) {
case fuzzing::Statement::STATEMENT_NOT_SET: {
break;
}
case fuzzing::Statement::kAssignment: {
os << statement.assignment();
break;
}
case fuzzing::Statement::kIfelse: {
os << statement.ifelse();
break;
}
case fuzzing::Statement::kWhileStmt: {
os << statement.while_stmt();
break;
}
case fuzzing::Statement::kReturnStmt: {
os << "return " << statement.return_stmt() << ";\n";
break;
}
case fuzzing::Statement::kDeclare: {
os << statement.declare();
break;
}
}
return os;
}
std::ostream& operator<<(std::ostream& os, const fuzzing::Function& function) {
os << GetType(function.type()) << " "
<< GetFunctionName(function.function_name()) << "() {\n";
os << function.block();
os << "return " << function.return_stmt() << ";\n";
os << "}";
return os;
}
std::ostream& operator<<(std::ostream& os, const fuzzing::Shader& shader) {
int i = 0;
for (const fuzzing::Function& function : shader.functions()) {
os << function;
if (i < shader.functions().size() - 1) {
os << "\n";
}
i++;
}
return os;
}
std::string GetShader(const fuzzing::Shader& shader) {
std::ostringstream os;
os << shader;
return os.str();
}
} // namespace gl_lpm_fuzzer
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GPU_COMMAND_BUFFER_TESTS_LPM_GL_LPM_SHADER_TO_STRING_H_
#define GPU_COMMAND_BUFFER_TESTS_LPM_GL_LPM_SHADER_TO_STRING_H_
#include <string>
#include "gpu/command_buffer/tests/lpm/gl_lpm_fuzzer.pb.h"
namespace gl_lpm_fuzzer {
std::string GetShader(const fuzzing::Shader& shader);
} // namespace gl_lpm_fuzzer
#endif // GPU_COMMAND_BUFFER_TESTS_LPM_GL_LPM_SHADER_TO_STRING_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/tests/lpm/gl_lpm_shader_to_string.h"
#include <string>
#include <utility>
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/protobuf/src/google/protobuf/text_format.h"
class LpmShaderTest
: public ::testing::TestWithParam<std::pair<std::string, std::string>> {};
TEST_P(LpmShaderTest, CheckTranslation) {
const std::pair<std::string, std::string>& param = GetParam();
fuzzing::Shader shader;
EXPECT_TRUE(
google::protobuf::TextFormat::ParseFromString(param.first, &shader));
ASSERT_EQ(gl_lpm_fuzzer::GetShader(shader), param.second);
}
INSTANTIATE_TEST_SUITE_P(LpmFuzzer,
LpmShaderTest,
::testing::Values(std::make_pair(R"(functions {
function_name: MAIN
block {
statements {
assignment {
lvalue {
var: VAR_0
}
rvalue {
}
}
}
}
return_stmt {
}
type: VOID_TYPE
})",
R"(void main() {
var0 = 1;
return 1;
})"),
std::make_pair(R"(functions {
function_name: MAIN
block {
statements {
while_stmt {
cond {
binary_op {
op: PLUS
left {
cons {
val: 0
}
}
right {
}
}
}
body {
}
}
}
}
return_stmt {
}
type: VOID_TYPE
})",
R"(void main() {
while ((0 + 1)) {
}
return 1;
})"),
std::make_pair(R"(functions {
function_name: MAIN
block {
statements {
while_stmt {
cond {
var: VAR_0
}
body {
}
}
}
}
return_stmt {
}
type: VOID_TYPE
}
functions {
function_name: MAIN
block {
statements {
}
}
return_stmt {
}
type: VOID_TYPE
})",
R"(void main() {
while (0) {
}
return 1;
}
void main() {
return 1;
})"),
std::make_pair(R"(functions {
function_name: NAME_2
block {
}
return_stmt {
}
type: VOID_TYPE
}
functions {
function_name: NAME_1
block {
statements {
declare {
type: VOID_TYPE
var: VAR_2
}
}
}
return_stmt {
}
type: VOID_TYPE
})",
R"(void f2() {
return 1;
}
void f1() {
void var2;
return 1;
})"),
std::make_pair(R"(functions {
function_name: NAME_2
block {
}
return_stmt {
}
type: VOID_TYPE
}
functions {
function_name: MAIN
block {
statements {
ifelse {
cond {
cons {
val: 0
}
}
if_body {
}
else_body {
}
}
}
}
return_stmt {
cons {
val: 0
}
}
type: VOID_TYPE
})",
R"(void f2() {
return 1;
}
void main() {
if (0) {
} else {
}
return 0;
})")));
...@@ -219,14 +219,13 @@ static_library("protobuf_full") { ...@@ -219,14 +219,13 @@ static_library("protobuf_full") {
"//third_party/perfetto/protos/ftrace:full", "//third_party/perfetto/protos/ftrace:full",
"//third_party/perfetto/gn:protobuf_full_deps", "//third_party/perfetto/gn:protobuf_full_deps",
# The SQLite fuzzer's corpus generator needs protobuf_full and is not
# included in Chrome.
"//third_party/sqlite:sqlite3_lpm_corpus_gen",
# Some tests inside ChromeOS need reflection to parse golden files. # Some tests inside ChromeOS need reflection to parse golden files.
# Not included in production code. # Not included in production code.
"//chrome/test:usage_time_limit_unittests", "//chrome/test:usage_time_limit_unittests",
# The protobuf-based SQLite and GPU fuzzers need protobuf_full and are not
# included in Chrome.
"//third_party/sqlite:sqlite3_lpm_corpus_gen",
"//gpu:gl_lpm_shader_to_string_unittest",
] ]
sources = protobuf_lite_sources + [ sources = protobuf_lite_sources + [
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment