├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cli ├── README.md ├── gfuzz │ ├── __init__.py │ ├── api.py │ ├── cli.py │ ├── commands │ │ ├── __init__.py │ │ ├── cliopt.py │ │ ├── doxygen │ │ │ ├── __init__.py │ │ │ ├── docker │ │ │ │ ├── Dockerfile │ │ │ │ └── in │ │ │ │ │ ├── Doxyfile.template │ │ │ │ │ └── run.py │ │ │ └── extractor.py │ │ ├── gen │ │ │ ├── __init__.py │ │ │ ├── cpp │ │ │ │ ├── README.md │ │ │ │ ├── __init__.py │ │ │ │ ├── base_schema.yaml │ │ │ │ ├── cpp_sig.py │ │ │ │ ├── gen_cpp.py │ │ │ │ └── test_cpp_sig.py │ │ │ └── gen.py │ │ ├── minimizer.py │ │ └── schema.py │ ├── docker_util.py │ └── schema.py ├── poetry.lock └── pyproject.toml ├── core ├── build_tests.sh ├── graph.hpp ├── graph.proto ├── graphTest.cpp ├── harness.cpp ├── ignorelist.txt ├── json.hpp ├── schema.hpp └── schemaTest.cpp ├── docs ├── .nojekyll ├── README.md ├── _sidebar.md ├── assets │ └── readme_graphs.png ├── experiments │ └── overview.md ├── index.html ├── quick_start │ ├── basic_usage.md │ ├── endpoints.md │ └── installation.md ├── research │ └── GraphFuzz_ICSE_2022.pdf └── schema_format.md └── experiments ├── README.md ├── base └── Dockerfile ├── build ├── custom_endpoints ├── Dockerfile └── in │ ├── build.sh │ ├── lib.h │ └── schema.yaml ├── eigen ├── Dockerfile └── in │ ├── build.sh │ ├── f1 │ ├── fuzz_exec.cpp │ ├── fuzz_write.cpp │ ├── schema.json │ └── schema.yaml │ └── test.sh ├── ex_array_demo ├── Dockerfile └── in │ ├── build.sh │ ├── build_lib.sh │ ├── fuzz │ ├── fuzz_exec.cpp │ ├── fuzz_write.cpp │ ├── schema.json │ └── schema.yaml │ └── lib │ ├── lib.cpp │ └── lib.h ├── ex_auto_cpp ├── Dockerfile ├── README.md ├── in │ ├── auto_schema.yaml │ ├── build.sh │ ├── build_lib.sh │ ├── fuzz │ │ ├── fuzz_exec.cpp │ │ ├── fuzz_write.cpp │ │ └── schema.json │ └── lib │ │ ├── point.cpp │ │ ├── point.h │ │ ├── rect.cpp │ │ └── rect.h └── make_schema.sh ├── hello_graphfuzz ├── Dockerfile └── in │ ├── build.sh │ ├── lib.h │ ├── schema.yaml │ └── schema_verbose.yaml ├── iowow ├── Dockerfile └── in │ ├── bug.sh │ ├── bugs │ ├── bug1.c │ └── bug2.c │ ├── build.sh │ ├── db_tracker.h │ ├── f1 │ ├── fuzz_exec.cpp │ ├── fuzz_write.cpp │ ├── schema.json │ └── schema.yaml │ └── test.sh ├── rdkit ├── Dockerfile ├── build_rdkit.sh └── in │ ├── Fuzz │ ├── build.sh │ ├── fuzz_exec.cpp │ ├── fuzz_write.cpp │ ├── schema.json │ └── schema.yaml │ ├── bugs │ ├── README.md │ ├── bug1.cpp │ ├── bug1.py │ ├── bug1_min.cpp │ ├── bug2.cpp │ ├── bug2_min.cpp │ ├── bug3.cpp │ ├── bug3_min.cpp │ ├── bug4.cpp │ ├── bug4_min.cpp │ ├── bug4_min2.cpp │ ├── bug5.cpp │ ├── bug5_min.cpp │ ├── bug6.cpp │ ├── bug6_min.cpp │ ├── bug7.cpp │ ├── bug7_min.cpp │ ├── bug8.cpp │ ├── bug9.cpp │ └── bug9_min.cpp │ ├── example │ ├── build.sh │ └── test.cpp │ ├── launch.sh │ ├── make.sh │ ├── raw_schema.yaml │ └── test.sh ├── rdkit_demo ├── Dockerfile ├── build_rdkit.sh └── in │ ├── build.sh │ ├── demo.cpp │ ├── schema.yaml │ └── set_flags.sh ├── run ├── skia ├── Dockerfile ├── README.md ├── gf_fuzz │ ├── FuzzCanvas │ │ ├── api_image_filter │ │ │ ├── fuzz_exec.cpp │ │ │ ├── fuzz_write.cpp │ │ │ ├── schema.json │ │ │ └── schema.yaml │ │ ├── api_mock_gpu_canvas │ │ │ ├── BUILD.gn │ │ │ ├── README.md │ │ │ ├── build.sh │ │ │ ├── fuzz_exec.cpp │ │ │ ├── fuzz_write.cpp │ │ │ ├── schema.json │ │ │ └── schema.yaml │ │ ├── api_null_canvas │ │ │ ├── fuzz_exec.cpp │ │ │ ├── fuzz_write.cpp │ │ │ ├── schema.json │ │ │ └── schema.yaml │ │ ├── api_raster_n32_canvas │ │ │ ├── fuzz_exec.cpp │ │ │ ├── fuzz_write.cpp │ │ │ ├── schema.json │ │ │ └── schema.yaml │ │ ├── api_svg_canvas │ │ │ ├── fuzz_exec.cpp │ │ │ ├── fuzz_write.cpp │ │ │ ├── schema.json │ │ │ └── schema.yaml │ │ ├── build_baseline.sh │ │ ├── fuzz_exec.cpp │ │ ├── fuzz_util.h │ │ ├── fuzz_write.cpp │ │ ├── image_filter_deserialize │ │ │ ├── fuzz_exec.cpp │ │ │ ├── fuzz_write.cpp │ │ │ ├── schema.json │ │ │ └── schema.yaml │ │ ├── schema.json │ │ └── schema.yaml │ ├── FuzzDrawFunctions │ │ ├── build_baseline.sh │ │ ├── fuzz_exec.cpp │ │ ├── fuzz_write.cpp │ │ ├── schema.json │ │ └── schema.yaml │ ├── FuzzPathMeasure │ │ ├── fuzz_exec.cpp │ │ ├── fuzz_write.cpp │ │ ├── schema.json │ │ └── schema.yaml │ ├── FuzzPathOp │ │ ├── fuzz_exec.cpp │ │ ├── fuzz_write.cpp │ │ ├── schema.json │ │ └── schema.yaml │ ├── FuzzPolyUtils │ │ ├── fuzz_exec.cpp │ │ ├── fuzz_write.cpp │ │ ├── poly_util.h │ │ ├── schema.json │ │ └── schema.yaml │ ├── FuzzRegionOp │ │ ├── fuzz_exec.cpp │ │ ├── fuzz_write.cpp │ │ ├── schema.json │ │ └── schema.yaml │ ├── FuzzRegionSetPath │ │ ├── fuzz_exec.cpp │ │ ├── fuzz_write.cpp │ │ ├── schema.json │ │ └── schema.yaml │ ├── FuzzSkParagraph │ │ ├── build.sh │ │ ├── build_cov.sh │ │ ├── fuzz_exec.cpp │ │ ├── fuzz_write.cpp │ │ ├── paragraph_util.h │ │ ├── schema.json │ │ └── schema.yaml │ └── gen.sh ├── patch │ ├── BUILD.gn │ └── fuzz │ │ ├── Fuzz.cpp │ │ ├── Fuzz.h │ │ ├── FuzzCanvas.cpp │ │ ├── FuzzCommon.cpp │ │ ├── FuzzCommon.h │ │ ├── FuzzCreateDDL.cpp │ │ ├── FuzzDDLThreading.cpp │ │ ├── FuzzDrawFunctions.cpp │ │ ├── FuzzEncoders.cpp │ │ ├── FuzzGradients.cpp │ │ ├── FuzzMain.cpp │ │ ├── FuzzParsePath.cpp │ │ ├── FuzzPath.cpp │ │ ├── FuzzPathMeasure.cpp │ │ ├── FuzzPathop.cpp │ │ ├── FuzzPolyUtils.cpp │ │ ├── FuzzRRect.cpp │ │ ├── FuzzRegionOp.cpp │ │ ├── FuzzSkParagraph.cpp │ │ ├── FuzzTriangulation.cpp │ │ ├── README.md │ │ ├── coverage │ │ └── oss_fuzz │ │ ├── FuzzAPICreateDDL.cpp │ │ ├── FuzzAPIImageFilter.cpp │ │ ├── FuzzAPISVGCanvas.cpp │ │ ├── FuzzAndroidCodec.cpp │ │ ├── FuzzAnimatedImage.cpp │ │ ├── FuzzDDLThreading.cpp │ │ ├── FuzzDrawFunctions.cpp │ │ ├── FuzzGradients.cpp │ │ ├── FuzzImage.cpp │ │ ├── FuzzImageFilterDeserialize.cpp │ │ ├── FuzzIncrementalImage.cpp │ │ ├── FuzzJPEGEncoder.cpp │ │ ├── FuzzJSON.cpp │ │ ├── FuzzMockGPUCanvas.cpp │ │ ├── FuzzNullCanvas.cpp │ │ ├── FuzzPNGEncoder.cpp │ │ ├── FuzzPathDeserialize.cpp │ │ ├── FuzzPathMeasure.cpp │ │ ├── FuzzPathop.cpp │ │ ├── FuzzPolyUtils.cpp │ │ ├── FuzzRasterN32Canvas.cpp │ │ ├── FuzzRegionDeserialize.cpp │ │ ├── FuzzRegionOp.cpp │ │ ├── FuzzRegionSetPath.cpp │ │ ├── FuzzSKP.cpp │ │ ├── FuzzSKSL2GLSL.cpp │ │ ├── FuzzSKSL2Metal.cpp │ │ ├── FuzzSKSL2Pipeline.cpp │ │ ├── FuzzSKSL2SPIRV.cpp │ │ ├── FuzzSVG.cpp │ │ ├── FuzzSkDescriptorDeserialize.cpp │ │ ├── FuzzSkParagraph.cpp │ │ ├── FuzzSkRuntimeEffect.cpp │ │ ├── FuzzTextBlobDeserialize.cpp │ │ ├── FuzzTriangulation.cpp │ │ └── FuzzWEBPEncoder.cpp └── scripts │ ├── llvm-gcov.sh │ └── run.py └── sqlite3 ├── Dockerfile └── in ├── bug.sh ├── bugs ├── bug1.c └── bug2.c ├── build.sh ├── c_api.yaml ├── db_tracker.h ├── extra.h ├── f1 ├── fuzz_exec.cpp ├── fuzz_write.cpp ├── schema.json └── schema.yaml ├── sql.dict ├── sqlite3.c ├── sqlite3.h └── test.sh /.gitignore: -------------------------------------------------------------------------------- 1 | **/__pycache__ 2 | build/ 3 | python/dist 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(GraphFuzz VERSION 1.0) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_CXX_STANDARD_REQUIRED True) 6 | 7 | include(FindProtobuf) 8 | find_package(Protobuf REQUIRED) 9 | 10 | include_directories(${PROTOBUF_INCLUDE_DIRS}) 11 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 12 | 13 | protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS core/graph.proto) 14 | 15 | add_library(graphfuzz STATIC 16 | core/harness.cpp 17 | core/graph.proto ${PROTO_SRCS} ${PROTO_HDRS} 18 | ) 19 | 20 | install( 21 | TARGETS graphfuzz 22 | LIBRARY DESTINATION lib 23 | ARCHIVE DESTINATION lib 24 | RUNTIME DESTINATION bin 25 | ) 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 Harrison Green 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /cli/README.md: -------------------------------------------------------------------------------- 1 | # Graphfuzz command line interface 2 | 3 | ## Usage: 4 | 5 | ## Crash minimization 6 | 7 | ```sh 8 | $ gfuzz min 9 | ``` 10 | 11 | ## Doxygen generation 12 | 13 | ``` 14 | $ gfuzz doxygen --inputs in1 [in2, in3...] --output 15 | ``` 16 | 17 | ## Schema infererence 18 | 19 | ``` 20 | $ gfuzz schema infer 21 | ``` 22 | -------------------------------------------------------------------------------- /cli/gfuzz/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForAllSecure/GraphFuzz/a3bc8b35fe60de568f3fe1932f1bdd657dd402fa/cli/gfuzz/__init__.py -------------------------------------------------------------------------------- /cli/gfuzz/api.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import yaml 4 | 5 | from parser import parse_sig 6 | 7 | 8 | class API(object): 9 | def __init__(self, fpath): 10 | self.fpath = fpath 11 | self.methods = [] 12 | self.headers = [] 13 | self.cpp_headers = [] 14 | self.initializer = '' 15 | self.finalizer = '' 16 | 17 | if not os.path.exists(self.fpath): 18 | print('[*] Error API file not found: %s' % self.fpath) 19 | return 20 | 21 | api = yaml.safe_load(open(self.fpath, 'r').read()) 22 | 23 | if 'headers' in api: 24 | self.headers = api['headers'] 25 | 26 | if 'cpp_headers' in api: 27 | self.cpp_headers = api['cpp_headers'] 28 | 29 | if 'initializer' in api: 30 | self.initializer = api['initializer'] 31 | 32 | if 'finalizer' in api: 33 | self.finalizer = api['finalizer'] 34 | 35 | for raw_sig in api['methods']: 36 | sig = parse_sig(raw_sig) 37 | 38 | if sig is None: 39 | print('[!] Could not parse signature: %s' % raw_sig) 40 | else: 41 | self.methods.append(sig) 42 | 43 | print('[*] Loaded %d methods' % len(self.methods)) 44 | -------------------------------------------------------------------------------- /cli/gfuzz/cli.py: -------------------------------------------------------------------------------- 1 | 2 | import argparse 3 | 4 | 5 | from .commands import COMMANDS 6 | 7 | 8 | def main(): 9 | parser = argparse.ArgumentParser(description='GraphFuzz CLI') 10 | sub = parser.add_subparsers(dest='mode') 11 | 12 | options = {api._name: api for api in COMMANDS} 13 | 14 | for opt in COMMANDS: 15 | opt.add_args(sub) 16 | 17 | args = parser.parse_args() 18 | 19 | if args.mode is None: 20 | parser.print_help() 21 | exit(0) 22 | elif args.mode in options: 23 | options[args.mode].execute(args) 24 | else: 25 | return 26 | 27 | if __name__=='__main__': 28 | main() 29 | -------------------------------------------------------------------------------- /cli/gfuzz/commands/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from .minimizer import MinAPI 3 | from .doxygen.extractor import DoxygenAPI 4 | from .schema import SchemaAPI 5 | from .gen.gen import GenAPI 6 | 7 | 8 | COMMANDS = [ 9 | MinAPI, 10 | DoxygenAPI, 11 | SchemaAPI, 12 | GenAPI 13 | ] 14 | -------------------------------------------------------------------------------- /cli/gfuzz/commands/cliopt.py: -------------------------------------------------------------------------------- 1 | 2 | class CLIOpt(object): 3 | def __init__(self, name, help_str, register_fn, execute_fn): 4 | self._name = name 5 | self._help_str = help_str 6 | self._register_fn = register_fn 7 | self._execute_fn = execute_fn 8 | 9 | self._subparser = None 10 | 11 | def add_args(self, parser): 12 | sub = parser.add_parser(self._name, help=self._help_str) 13 | self._register_fn(sub) 14 | self._subparser = sub 15 | 16 | def execute(self, args): 17 | res = self._execute_fn(args) 18 | if res == False: 19 | self._subparser.print_help() 20 | -------------------------------------------------------------------------------- /cli/gfuzz/commands/doxygen/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForAllSecure/GraphFuzz/a3bc8b35fe60de568f3fe1932f1bdd657dd402fa/cli/gfuzz/commands/doxygen/__init__.py -------------------------------------------------------------------------------- /cli/gfuzz/commands/doxygen/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM ubuntu:20.04 3 | 4 | RUN apt-get -y update && \ 5 | apt-get -y upgrade && \ 6 | apt-get -y install doxygen git python3 7 | 8 | WORKDIR /src 9 | COPY in ./in 10 | 11 | ENTRYPOINT ["/src/in/run.py"] 12 | -------------------------------------------------------------------------------- /cli/gfuzz/commands/doxygen/docker/in/Doxyfile.template: -------------------------------------------------------------------------------- 1 | EXTRACT_ALL = YES 2 | EXTRACT_STATIC = YES 3 | EXTRACT_LOCAL_CLASSES = YES 4 | EXTRACT_LOCAL_METHODS = YES 5 | 6 | INPUT = {input} 7 | RECURSIVE = true 8 | 9 | GENERATE_XML = YES 10 | XML_PROGRAMLISTING = NO 11 | MACRO_EXPANSION = YES 12 | 13 | GENERATE_HTML = NO 14 | GENERATE_LATEX = NO 15 | GENERATE_RTF = NO 16 | GENERATE_MAN = NO 17 | GENERATE_AUTOGEN_DEF = NO 18 | GENERATE_PERLMOD = NO 19 | -------------------------------------------------------------------------------- /cli/gfuzz/commands/doxygen/docker/in/run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import argparse 4 | import os 5 | import subprocess 6 | 7 | 8 | def _run_doxygen(inputs): 9 | template = open('/src/in/Doxyfile.template', 'r').read() 10 | open('/src/out/Doxyfile', 'w').write(template.format( 11 | input=' '.join(inputs) 12 | )) 13 | 14 | r = subprocess.run('cd /src/out && doxygen', shell=True) 15 | 16 | 17 | def main(): 18 | parser = argparse.ArgumentParser() 19 | parser.add_argument('--inputs', required=True, nargs='+', type=str, 20 | help='Doxygen input paths.') 21 | args = parser.parse_args() 22 | 23 | _run_doxygen(args.inputs) 24 | 25 | 26 | if __name__=='__main__': 27 | main() 28 | -------------------------------------------------------------------------------- /cli/gfuzz/commands/doxygen/extractor.py: -------------------------------------------------------------------------------- 1 | 2 | import argparse 3 | import os 4 | import pathlib 5 | import subprocess 6 | 7 | 8 | from ... import docker_util 9 | from ..cliopt import CLIOpt 10 | 11 | 12 | EXTRACTOR_IMAGE_TAG = 'util_graphfuzz_doxygen_extractor' 13 | 14 | 15 | def build_extractor_image(): 16 | package = pathlib.Path(__file__).parent.absolute() 17 | docker_path = package / 'docker' 18 | 19 | docker_util.build_image(docker_path, EXTRACTOR_IMAGE_TAG) 20 | 21 | 22 | def run_extractor_image(inputs, output): 23 | out = pathlib.Path(output).absolute() 24 | 25 | input_paths = [pathlib.Path(x) for x in inputs] 26 | 27 | # Map input path on host to path inside container. 28 | volumes = { 29 | str(p.absolute()): str('/src/target' / p.relative_to(p.root)) for p in input_paths 30 | } 31 | volumes[str(out)] = '/src/out' 32 | 33 | inner_args = '--inputs ' + ' '.join( 34 | volumes[host] for host in volumes 35 | ) 36 | 37 | docker_util.run_image(EXTRACTOR_IMAGE_TAG, '', volumes, inner_args) 38 | 39 | 40 | def register(sub): 41 | sub.add_argument('--inputs', required=True, nargs='+', type=str, 42 | help='Doxygen input paths.') 43 | sub.add_argument('--output', required=True, type=str, 44 | help='Doxygen output directory.') 45 | 46 | 47 | def execute(args): 48 | docker_util.check_docker() 49 | build_extractor_image() 50 | run_extractor_image(args.inputs, args.output) 51 | 52 | 53 | DoxygenAPI = CLIOpt( 54 | 'doxygen', 55 | 'Build Doxygen xml from source code.', 56 | register, 57 | execute 58 | ) 59 | -------------------------------------------------------------------------------- /cli/gfuzz/commands/gen/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForAllSecure/GraphFuzz/a3bc8b35fe60de568f3fe1932f1bdd657dd402fa/cli/gfuzz/commands/gen/__init__.py -------------------------------------------------------------------------------- /cli/gfuzz/commands/gen/cpp/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # C++ harness generation 4 | 5 | ## Overview 6 | 7 | A C++ schema can be broken down into two components: `types` and `scopes`. 8 | 9 | A `type` is an object and there are two versions: 10 | - `live types` are things like `structs` and `classes` that have explicit constructors and destructors. These objects are tracked by the dataflow graph. 11 | - `simple types` are things like `int`, `float` or `enum` types that exist only within the context of a single function and are embedded in the `context` string during fuzzing. 12 | 13 | A `scope` is a function and for C++ code, we have four types: 14 | - `constructor`: A function with the same name as the enclosing `struct` or `class`. 15 | - `destructor`: A function with the form `~MyStruct`. 16 | - `method`: A function defined for an instance of an object, e.g. `myObj::foo()` 17 | - `static`: A function not bound to a class, e.g. `void foo()`. 18 | 19 | To generate harnesses, we first construct a list of `scopes` by enumerating functions defined in the schema. Each `scope` has a list of input and output `types`. 20 | 21 | In the next stage, we resolve `types` (following typedef's as necessary), and determine the version. For example, `int x` should resolve as a "simple type of size 4" while `MyStruct &ref` should resolve to a "reference to `MyStruct`." 22 | 23 | After the type resolution stage, we can compute the necessary "context" size for a scope and determine how many "live" inputs and outputs there will be. 24 | 25 | Finally, we can layout the scope using a code generation template. We need to do this once for both the "exec" harness and the "write" harness. 26 | 27 | ## Method call 28 | 29 | ```cpp 30 | extern "C" void shim_N(void **in_ref, void **out_ref, const char *context) { 31 | MyClass *ref = (MyClass *)in_ref[0]; 32 | ref->myMethod(); 33 | out_ref[0] = ref; 34 | } 35 | ``` -------------------------------------------------------------------------------- /cli/gfuzz/commands/gen/cpp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForAllSecure/GraphFuzz/a3bc8b35fe60de568f3fe1932f1bdd657dd402fa/cli/gfuzz/commands/gen/cpp/__init__.py -------------------------------------------------------------------------------- /cli/gfuzz/commands/gen/cpp/base_schema.yaml: -------------------------------------------------------------------------------- 1 | simple_int: 2 | type: simple 3 | context_size: 4 4 | name: int 5 | simple_float: 6 | type: simple 7 | context_size: 4 8 | name: float 9 | simple_double: 10 | type: simple 11 | context_size: 8 12 | name: double 13 | simple_void: 14 | type: ignore 15 | name: void 16 | simple_char: 17 | type: simple 18 | context_size: 1 19 | name: char 20 | print_cast: int 21 | simple_size_t: 22 | type: simple 23 | context_size: 8 24 | name: size_t 25 | 26 | simple_bool: 27 | type: simple 28 | context_size: 1 29 | name: bool 30 | print_cast: int 31 | load: " {var_type} {arg_name} = *(static_cast(context + {context_offset})) & 1;\n" 32 | load_arr: | 33 | {var_type} {arg_name}[{count}]; 34 | for (int i = 0; i < {count}; ++i) {arg_name}[i] = *(static_cast(context + {context_offset} + i)) & 1; 35 | 36 | simple_int8_t: 37 | type: simple 38 | context_size: 1 39 | name: int8_t 40 | print_cast: int 41 | simple_int16_t: 42 | type: simple 43 | context_size: 2 44 | name: int16_t 45 | simple_int32_t: 46 | type: simple 47 | context_size: 4 48 | name: int32_t 49 | simple_int64_t: 50 | type: simple 51 | context_size: 8 52 | name: int64_t 53 | simple_uint8_t: 54 | type: simple 55 | context_size: 1 56 | name: uint8_t 57 | print_cast: int 58 | simple_uint16_t: 59 | type: simple 60 | context_size: 2 61 | name: uint16_t 62 | simple_uint32_t: 63 | type: simple 64 | context_size: 4 65 | name: uint32_t 66 | simple_uint64_t: 67 | type: simple 68 | context_size: 8 69 | name: uint64_t 70 | simple_char16_t: 71 | type: simple 72 | context_size: 2 73 | name: char16_t 74 | -------------------------------------------------------------------------------- /cli/gfuzz/commands/gen/gen.py: -------------------------------------------------------------------------------- 1 | 2 | from ..cliopt import CLIOpt 3 | from .cpp.gen_cpp import GenCppAPI 4 | 5 | 6 | COMMANDS = [ 7 | GenCppAPI 8 | ] 9 | 10 | OPTIONS = { 11 | k._name: k for k in COMMANDS 12 | } 13 | 14 | 15 | def register(parser): 16 | sub = parser.add_subparsers(dest='gen_mode') 17 | 18 | for opt in COMMANDS: 19 | opt.add_args(sub) 20 | 21 | 22 | def execute(args): 23 | if args.gen_mode in OPTIONS: 24 | OPTIONS[args.gen_mode].execute(args) 25 | else: 26 | return False 27 | 28 | 29 | GenAPI = CLIOpt( 30 | 'gen', 31 | 'Generate a GraphFuzz harness.', 32 | register, 33 | execute 34 | ) 35 | -------------------------------------------------------------------------------- /cli/gfuzz/commands/minimizer.py: -------------------------------------------------------------------------------- 1 | 2 | import subprocess 3 | import random 4 | 5 | from .cliopt import CLIOpt 6 | 7 | 8 | def template_for(word): 9 | if word.startswith('0x'): 10 | return '' 11 | 12 | return word 13 | 14 | def test_example(fuzzer, example, extra): 15 | open('.tmp_run', 'wb').write(example) 16 | 17 | p = subprocess.run(f'./{fuzzer} .tmp_run {extra}', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 18 | #print(p) 19 | out = p.stderr.decode('ascii') 20 | 21 | tag = '' 22 | if 'error: ' in out: 23 | tag = 'error: ' 24 | elif 'ERROR: ' in out: 25 | tag = 'ERROR: ' 26 | else: 27 | return '' 28 | 29 | e = out.split(tag)[1].split('\n')[0] 30 | 31 | # Replace addresses with a template so ASLR doesn't affect crash output message. 32 | e = e.replace('(','').replace(')','') 33 | words = e.split() 34 | words = [template_for(x) for x in words] 35 | e = ' '.join(words) 36 | 37 | return e 38 | 39 | def mutate(fuzzer, example): 40 | open('.min_in', 'wb').write(example) 41 | 42 | p = subprocess.run( 43 | f'./{fuzzer} --graphfuzz_ignore_invalid --graphfuzz_context_mutation_prob=0 --graphfuzz_mutate_one {random.randint(0,2**32-2)} .min_in .min_out', 44 | shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE 45 | ) 46 | 47 | if p.returncode != 0: 48 | return None 49 | 50 | ex = open('.min_out', 'rb').read() 51 | return ex 52 | 53 | def minimize_crash(fuzzer, crash, extra='', early_stop=50): 54 | print('Minimizing %s...' % crash) 55 | 56 | base = open(crash, 'rb').read() 57 | print('Base case size: %d' % len(base)) 58 | 59 | base_err = test_example(fuzzer, base, extra) 60 | if len(base_err) == 0: 61 | print('Base case doesn\'t crash') 62 | return 63 | 64 | print('---[Crash]---') 65 | print(base_err) 66 | print('-------------') 67 | 68 | print('Minimizing...') 69 | 70 | best = base 71 | 72 | last_min = 0 73 | 74 | i = 0 75 | while True: 76 | if i - last_min >= early_stop: 77 | print('No improvement for %d steps, stopping...' % early_stop) 78 | break 79 | 80 | m = mutate(fuzzer, best) 81 | 82 | # Check length. 83 | if m is None or len(m) >= len(best): 84 | continue 85 | 86 | # Check crash. 87 | i += 1 88 | err = test_example(fuzzer, m, extra) 89 | if err != base_err: 90 | continue 91 | 92 | print('[%d] Found smaller crash: %d' % (i, len(m))) 93 | best = m 94 | last_min = i 95 | 96 | fpath = f'{crash}.min' 97 | open(fpath, 'wb').write(best) 98 | print(f'Minimized crash saved to: {fpath}') 99 | 100 | def register(sub): 101 | sub.add_argument('fuzzer', help='Path to fuzz_exec binary.') 102 | sub.add_argument('crash', help='Path to crash file.') 103 | sub.add_argument('-k', '--early_stop', default=50, type=int, 104 | help='Number of failed steps before quitting.') 105 | sub.add_argument('--extra', default="", help='Extra fuzzer args.') 106 | 107 | def execute(args): 108 | minimize_crash(args.fuzzer, args.crash, args.extra, args.early_stop) 109 | 110 | MinAPI = CLIOpt( 111 | 'min', 112 | 'Minimize a crash file.', 113 | register, 114 | execute 115 | ) 116 | -------------------------------------------------------------------------------- /cli/gfuzz/docker_util.py: -------------------------------------------------------------------------------- 1 | 2 | import pathlib 3 | import subprocess 4 | 5 | 6 | def check_docker(): 7 | """Check if docker is available as a shell command.""" 8 | r = subprocess.run('docker -v', shell=True, stdout=subprocess.PIPE, 9 | stderr=subprocess.PIPE) 10 | 11 | output = r.stdout.decode('ascii') 12 | if 'Docker version' in output: 13 | return 14 | 15 | print('Error: docker not found on path') 16 | exit(-1) 17 | 18 | 19 | def build_image(path: pathlib.Path, tag: str): 20 | """Build a docker image. 21 | 22 | Args: 23 | - path: Path to a folder with a Dockerfile. 24 | - tag: Name to use as a tag. 25 | """ 26 | r = subprocess.run( 27 | f'docker build {path} -t {tag}', 28 | shell=True) 29 | 30 | if r.returncode != 0: 31 | print('Error building image') 32 | exit(-1) 33 | 34 | 35 | def run_image(tag: str, cmd: str, volumes: dict = {}, inner_args: str = '', run_args: str = ''): 36 | """Run a command in a docker image.""" 37 | 38 | volume_str = ' '.join( 39 | f'-v {k}:{volumes[k]}' for k in volumes 40 | ) 41 | 42 | r = subprocess.run( 43 | f'docker run {volume_str} {run_args} -it {tag} {cmd} {inner_args}', 44 | shell=True) 45 | -------------------------------------------------------------------------------- /cli/gfuzz/schema.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Set 3 | import yaml 4 | 5 | 6 | def _validate_obj(name: str, obj: dict, orig_path: str) -> dict: 7 | if not 'type' in obj: 8 | print(f'[!] Error {name} has no attribute "type"') 9 | return None 10 | 11 | obj['orig_path'] = orig_path 12 | obj['headers'] = obj.get('headers') or [] 13 | obj['c_headers'] = obj.get('c_headers') or [] 14 | 15 | # Ensure headers are only .h files. 16 | # obj['headers'] = [x for x in obj['headers'] if x.endswith('.h')] 17 | 18 | obj['name'] = obj.get('name') or '' 19 | 20 | if obj['type'] in ['struct', 'class', 'file']: 21 | obj['methods'] = obj.get('methods') or [] 22 | obj['static_methods'] = obj.get('static_methods') or [] 23 | 24 | return obj 25 | 26 | class Schema(object): 27 | """A schema represents the API surface of a target.""" 28 | 29 | def __init__(self): 30 | self.objects = {} 31 | 32 | def add_all(self, other: 'Schema'): 33 | self.objects.update(other.objects) 34 | 35 | def add_unique(self, obj: dict) -> dict: 36 | v_id = len([k for k in self.objects]) 37 | key = 'part_%d' % v_id 38 | 39 | # Return existing dict or append new. 40 | for k in self.objects: 41 | if self.objects[k]['name'] == obj['name']: 42 | return self.objects[k] 43 | 44 | obj['id'] = v_id 45 | self.objects[key] = obj 46 | return obj 47 | 48 | @staticmethod 49 | def load(path: str, loaded: Set[str] = None) -> 'Schema': 50 | s = Schema() 51 | objects = yaml.safe_load(open(path, 'r')) 52 | 53 | valid = {} 54 | 55 | for k in objects: 56 | if k == 'include': 57 | continue 58 | 59 | res = _validate_obj(k, objects[k], path) 60 | if res is not None: 61 | valid[k] = res 62 | 63 | s.objects = valid 64 | 65 | # Process include list. 66 | if loaded is None: 67 | loaded = set() 68 | 69 | include = objects.get('include') or [] 70 | for sub_path in include: 71 | if sub_path in loaded: 72 | print(f'[*] Skipping duplicate include of "{sub_path}"') 73 | continue 74 | 75 | sub_schema = Schema.load(sub_path, loaded) 76 | loaded.add(sub_schema) 77 | 78 | s.add_all(sub_schema) 79 | 80 | return s 81 | 82 | def save(self, path: str): 83 | open(path, 'w').write(yaml.dump(self.objects)) 84 | 85 | def resolve(self, name: str) -> dict: 86 | for k in self.objects: 87 | obj = self.objects[k] 88 | if obj['name'] == name: 89 | if obj['type'] == 'typedef': 90 | return self.resolve(obj['value']) 91 | else: 92 | return self.objects[k] 93 | 94 | return None 95 | 96 | def assign_ids(self): 97 | """Assign a unique 'id' attribute to each object.""" 98 | i = 0 99 | for k in self.objects: 100 | self.objects[k]['id'] = i 101 | i += 1 102 | -------------------------------------------------------------------------------- /cli/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "gfuzz" 3 | version = "1.0.0" 4 | description = "" 5 | authors = ["hgarrereyn"] 6 | 7 | [tool.poetry.dependencies] 8 | python = "^3.6" 9 | PyYAML = "^5.4.1" 10 | beautifulsoup4 = "^4.9.3" 11 | tqdm = "^4.62.0" 12 | pyparsing = "^2.4.7" 13 | dataclasses = {version = "^0.8", python = ">=3.6, <3.7"} 14 | 15 | [tool.poetry.dev-dependencies] 16 | 17 | [tool.poetry.scripts] 18 | gfuzz = "gfuzz.cli:main" 19 | 20 | [build-system] 21 | requires = ["poetry-core>=1.0.0"] 22 | build-backend = "poetry.core.masonry.api" 23 | -------------------------------------------------------------------------------- /core/build_tests.sh: -------------------------------------------------------------------------------- 1 | 2 | clang++ -o schemaTest \ 3 | schemaTest.cpp \ 4 | -pthread \ 5 | -lgtest 6 | 7 | clang++ -o graphTest \ 8 | graphTest.cpp \ 9 | graph.pb.cc \ 10 | -pthread \ 11 | -lprotobuf \ 12 | -lgtest 13 | -------------------------------------------------------------------------------- /core/graph.proto: -------------------------------------------------------------------------------- 1 | 2 | syntax = "proto3"; 3 | 4 | // A NodeRef identifies a doubly-linked connection between neighboring nodes. 5 | // 6 | // For example, given the graph: 7 | // 8 | // A(0) -> B(1) 9 | // 10 | // Node A would contain a NodeRef in its out_ref list: 11 | // { node_idx: 1, conn_idx: 0 } 12 | // Node B would contain a backreference in its in_ref list: 13 | // { node_idx: 0, conn_idx: 0 } 14 | // 15 | // In a more complex graph such as: 16 | // 17 | // A(0)-\ 18 | // x-C(2) 19 | // B(1)-/ 20 | // 21 | // A has one output (to C), B has one output (to C), C has two inputs (A & B). 22 | // 23 | // Node A contains a single NodeRef in out_ref: 24 | // { node_idx: 2, conn_idx: 0 } 25 | // Node B contains a single NodeRef in out_ref: 26 | // { node_idx: 2, conn_idx: 1 } 27 | // Node C contains two NodeRef's in in_ref: 28 | // [ 29 | // { node_idx: 0, conn_idx: 0 }, 30 | // { node_idx: 1, conn_idx: 0 } 31 | // ] 32 | // 33 | // The "connection index" of a NodeRef is simply the index of the 34 | // complementary NodeRef in the target Node. This attribute simplifies graph 35 | // mutation operations where we need to add and remove nodes efficiently. 36 | message NodeRef { 37 | // The index of the target node. 38 | int32 node_idx = 1; 39 | 40 | // The connection index in the target node. 41 | int32 conn_idx = 2; 42 | } 43 | 44 | /* A node represents a single "scope" */ 45 | message Node { 46 | // Each node has a unique integer index. NodeRef messages use this index 47 | // to uniquely identify nodes in a graph. 48 | int32 index = 1; 49 | 50 | // The type of a node is an integer corresponding to a scope index in a 51 | // schema. Therefore, interpreting the "type" of a node requires a schema. 52 | int32 type = 2; 53 | 54 | // A node's layer describes its position in the hierarchy of the graph. A 55 | // node may only form a forward connection to a node with a higher layer 56 | // value. When a new forward node is added, it inherits the layer value of 57 | // its parent plus 1. A new backward node inherits the layer value of its 58 | // parent minus 1. This formalization ensures the graph has no cycles. 59 | int32 layer = 3; 60 | 61 | // A list of input references. 62 | repeated NodeRef in_ref = 4; 63 | 64 | // A list of output references. 65 | repeated NodeRef out_ref = 5; 66 | 67 | // A variable size bytestring representing ephemeral variable context. 68 | bytes context = 6; 69 | } 70 | 71 | // A graph represents a list of nodes. This is the primary serialization 72 | // container. 73 | message Graph { 74 | repeated Node nodes = 1; 75 | } 76 | -------------------------------------------------------------------------------- /core/graphTest.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "graph.hpp" 3 | 4 | #include 5 | 6 | 7 | TEST(graph, fillTerminal) { 8 | Schema schema = Schema::FromString(R"( 9 | { 10 | "types": [ 11 | {"name": "dat *", "id": 0} 12 | ], 13 | "scopes": [ 14 | { "name": "init_dat", "inputs": [], "outputs": [0], "context": 0 }, 15 | { "name": "consume_dat", "inputs": [0], "outputs": [], "context": 0 } 16 | ] 17 | } 18 | )"); 19 | 20 | ASSERT_EQ(true, schema.Validate()); 21 | TGraph graph(schema); 22 | 23 | graph.AddNode(schema.GetScope(0), 0); 24 | graph.FillTerminal(); 25 | 26 | Node n = graph.g.nodes(1); 27 | 28 | ASSERT_EQ(n.index(), 1); 29 | ASSERT_EQ(n.type(), 1); 30 | ASSERT_EQ(n.in_ref(0).node_idx(), 0); 31 | ASSERT_EQ(n.in_ref(0).conn_idx(), 0); 32 | } 33 | 34 | TEST(graph, fillMultiTerminal) { 35 | Schema schema = Schema::FromString(R"( 36 | { 37 | "types": [ 38 | {"name": "a", "id": 0}, 39 | {"name": "b", "id": 1}, 40 | {"name": "c", "id": 2}, 41 | {"name": "d", "id": 3} 42 | ], 43 | "scopes": [ 44 | { "name": "multi", "inputs": [0,1], "outputs": [2,3], "context": 0 }, 45 | { "name": "init_a", "inputs": [], "outputs": [0], "context": 0 }, 46 | { "name": "consume_a", "inputs": [0], "outputs": [], "context": 0 }, 47 | { "name": "init_b", "inputs": [], "outputs": [1], "context": 0 }, 48 | { "name": "consume_b", "inputs": [1], "outputs": [], "context": 0 }, 49 | { "name": "init_c", "inputs": [], "outputs": [2], "context": 0 }, 50 | { "name": "consume_c", "inputs": [2], "outputs": [], "context": 0 }, 51 | { "name": "init_d", "inputs": [], "outputs": [3], "context": 0 }, 52 | { "name": "consume_d", "inputs": [3], "outputs": [], "context": 0 } 53 | ] 54 | } 55 | )"); 56 | 57 | ASSERT_EQ(true, schema.Validate()); 58 | TGraph graph(schema); 59 | 60 | graph.AddNode(schema.GetScope(0), 0); 61 | graph.FillTerminal(); 62 | 63 | Node multi = graph.g.nodes(0); 64 | 65 | Node a = graph.g.nodes(multi.in_ref(0).node_idx()); 66 | ASSERT_EQ(a.type(), 1); 67 | ASSERT_EQ(a.out_ref(0).node_idx(), 0); 68 | ASSERT_EQ(a.out_ref(0).conn_idx(), 0); 69 | 70 | Node b = graph.g.nodes(multi.in_ref(1).node_idx()); 71 | ASSERT_EQ(b.type(), 3); 72 | ASSERT_EQ(b.out_ref(0).node_idx(), 0); 73 | ASSERT_EQ(b.out_ref(0).conn_idx(), 1); 74 | 75 | Node c = graph.g.nodes(multi.out_ref(0).node_idx()); 76 | ASSERT_EQ(c.type(), 6); 77 | ASSERT_EQ(c.in_ref(0).node_idx(), 0); 78 | ASSERT_EQ(c.in_ref(0).conn_idx(), 0); 79 | 80 | Node d = graph.g.nodes(multi.out_ref(1).node_idx()); 81 | ASSERT_EQ(d.type(), 8); 82 | ASSERT_EQ(d.in_ref(0).node_idx(), 0); 83 | ASSERT_EQ(d.in_ref(0).conn_idx(), 1); 84 | } 85 | 86 | int main(int argc, char **argv) { 87 | testing::InitGoogleTest(&argc, argv); 88 | return RUN_ALL_TESTS(); 89 | } 90 | -------------------------------------------------------------------------------- /core/ignorelist.txt: -------------------------------------------------------------------------------- 1 | 2 | # Ignore GraphFuzz core files 3 | src:.*graphfuzz/src/harness.cpp 4 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForAllSecure/GraphFuzz/a3bc8b35fe60de568f3fe1932f1bdd657dd402fa/docs/.nojekyll -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | * GraphFuzz 2 | * [Overview](/) 3 | * Quick Start 4 | * [0. Installation](quick_start/installation.md) 5 | * [1. Basic Usage](quick_start/basic_usage.md) 6 | * [2. Endpoints](quick_start/endpoints.md) 7 | * Experiments 8 | * [Overview](experiments/overview.md) 9 | * Documentation 10 | * [Schema Format](schema_format.md) 11 | -------------------------------------------------------------------------------- /docs/assets/readme_graphs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForAllSecure/GraphFuzz/a3bc8b35fe60de568f3fe1932f1bdd657dd402fa/docs/assets/readme_graphs.png -------------------------------------------------------------------------------- /docs/experiments/overview.md: -------------------------------------------------------------------------------- 1 | 2 | # Experiments 3 | 4 | We have created a collection of experiments that demonstrate how to use GraphFuzz with toy examples and real open-source projects. The purpose of this section is to demonstrate various features of GraphFuzz in isolation for educational purposes and to demonstrate tips & tricks we learned along the way while trying to apply GraphFuzz to large real-world projects. 5 | 6 | All of these experiments are Dockerized and fully reproducable. We provide some helper scripts to quickly build and run the containers. To run an experiment, first build the base GraphFuzz image: 7 | 8 | ```bash 9 | cd GraphFuzz/experiments 10 | ./build base 11 | ``` 12 | 13 | Then build and run any experiment container: 14 | 15 | ```bash 16 | ./build sqlite3 17 | ./run sqlite3 18 | ``` 19 | 20 | ## Available Experiments 21 | 22 | ### Examples 23 | 24 | | Experiment | Description | 25 | | --- | --- | 26 | | `hello_graphfuzz` | Fuzz a simple C++ API | 27 | | `ex_array_demo` | Demonstrates how to use array argument types | 28 | | `ex_auto_cpp` | Demonstrates how to use the `gfuzz doxygen` tool to automatically generate a schema from C++ source code | 29 | 30 | ### OSS Paper Benchmarks 31 | 32 | In our original paper, we describe the application of GraphFuzz to 5 open-source projects: 33 | 34 | | Experiment | Project | Description | 35 | | --- | --- | --- | 36 | | `skia` | https://skia.org/ | Skia is an open-source 2D graphics library developed by Google and used in projects such as Chromium and Android. | 37 | | `rdkit` | https://www.rdkit.org/ | RDKit is an open-source cheminformatics library written in C++. | 38 | | `eigen` | https://eigen.tuxfamily.org/ | Eigen is a C++ template library for linear algebra: matrices, vectors, numerical solvers, and related algorithms. | 39 | | `sqlite3` | https://www.sqlite.org/ | SQLite is a C-language library that implements a fully-featured SQL database engine. | 40 | | `iowow` | https://iowow.io/ | IOWOW is a C11 persistent key/value storage library based on the skip list data structure. | 41 | 42 | ### Other 43 | 44 | | Experiment | Description | 45 | | --- | --- | 46 | | `rdkit_demo` | Simple demo schema for RDKit as shown in our ICSE 2022 presentation | 47 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | GraphFuzz 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /docs/quick_start/installation.md: -------------------------------------------------------------------------------- 1 | 2 | # Installation 3 | 4 | ## Package managers 5 | 6 | TODO 7 | 8 | ## Build from source: 9 | 10 | Clone the repository: 11 | 12 | ```bash 13 | git clone https://github.com/ForAllSecure/GraphFuzz.git 14 | ``` 15 | 16 | ### 1. `libgraphfuzz` 17 | 18 | `libgraphfuzz` is the runtime graph mutation library that is linked into your fuzzer harness. It is written in C++ and uses a standard CMake build configuration: 19 | 20 | ```bash 21 | cd GraphFuzz/core 22 | mkdir build 23 | cd build 24 | cmake .. 25 | make 26 | make install 27 | ``` 28 | 29 | ### 2. `gfuzz` 30 | 31 | `gfuzz` is a Python command-line tool that builds harness files and performs miscellaneous other functions like graph minimization. It is written in Python and uses the Poetry build system: 32 | 33 | ```bash 34 | cd GraphFuzz/cli 35 | poetry build 36 | poetry export > dist/requirements.txt 37 | python3 -m pip install -r dist/requirements.txt 38 | python3 -m pip install ./dist/gfuzz-*.whl 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/research/GraphFuzz_ICSE_2022.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ForAllSecure/GraphFuzz/a3bc8b35fe60de568f3fe1932f1bdd657dd402fa/docs/research/GraphFuzz_ICSE_2022.pdf -------------------------------------------------------------------------------- /experiments/README.md: -------------------------------------------------------------------------------- 1 | 2 | # GraphFuzz Experiments 3 | 4 | All images are built on the `graphfuzz_base` image described in `./base/Dockerfile`. 5 | 6 | Run `./build base` to build the base image then `./build xyz` to build experiment `xyz` (see list below). The resulting image will be tagged `graphfuzz_xyz`. 7 | 8 | Once built, invoke `docker run` manually, or use the helper `run` script to start an interactive shell. I.e. with `./run xyz`. 9 | 10 | For example, to build and run the Skia experiment from scratch, run: 11 | ``` 12 | ./build base 13 | ./build skia 14 | ./run skia 15 | ``` 16 | 17 | ## Open Source Targets 18 | 19 | - skia 20 | - rdkit 21 | 22 | ## Examples 23 | 24 | - asdf 25 | -------------------------------------------------------------------------------- /experiments/base/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | ENV TERM xterm-256color 3 | 4 | RUN apt-get update && \ 5 | apt-get -y upgrade && \ 6 | apt-get -y install \ 7 | clang make cmake git wget curl tar gdb vim \ 8 | python3 python3-pip libprotobuf-dev protobuf-compiler 9 | 10 | # Install poetry 11 | RUN python3 -m pip install poetry 12 | 13 | WORKDIR /graphfuzz 14 | COPY cli /graphfuzz/cli 15 | COPY core /graphfuzz/core 16 | COPY CMakeLists.txt /graphfuzz/CMakeLists.txt 17 | 18 | # Build and install libgraphfuzz 19 | RUN cd /graphfuzz && \ 20 | mkdir build && \ 21 | cd build && \ 22 | cmake .. && \ 23 | make && \ 24 | make install 25 | 26 | # Install gfuzz python tool 27 | RUN cd /graphfuzz/cli && \ 28 | poetry build && \ 29 | poetry export > dist/requirements.txt && \ 30 | python3 -m pip install -r dist/requirements.txt && \ 31 | python3 -m pip install ./dist/gfuzz-*.whl 32 | -------------------------------------------------------------------------------- /experiments/build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import argparse 3 | from pathlib import Path 4 | import subprocess 5 | from typing import List 6 | 7 | def run(args): 8 | if args.experiment == 'base': 9 | # Build base image in root folder context. 10 | subprocess.run(['docker', 'build', '..', '-f', 'base/Dockerfile', '-t', 'graphfuzz_base']) 11 | else: 12 | # Build experiment in subfolder root. 13 | subprocess.run(['docker', 'build', f'./{args.experiment}', '-f', f'{args.experiment}/Dockerfile', '-t', f'graphfuzz_{args.experiment}']) 14 | 15 | def get_choices() -> List[str]: 16 | return [x.stem for x in Path('.').iterdir() if x.is_dir()] 17 | 18 | def main(): 19 | parser = argparse.ArgumentParser() 20 | parser.add_argument('experiment', choices=get_choices()) 21 | args = parser.parse_args() 22 | run(args) 23 | 24 | if __name__ == '__main__': 25 | main() 26 | -------------------------------------------------------------------------------- /experiments/custom_endpoints/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM graphfuzz_base 2 | 3 | RUN apt-get -y update && apt-get -y install clang++-10 4 | 5 | COPY in /harness/in 6 | WORKDIR /harness/in 7 | 8 | env ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-6.0/bin/llvm-symbolizer 9 | env ASAN_OPTIONS=detect_leaks=0,allocator_may_return_null=1 10 | CMD /bin/zsh 11 | -------------------------------------------------------------------------------- /experiments/custom_endpoints/in/build.sh: -------------------------------------------------------------------------------- 1 | 2 | gfuzz gen cpp schema.yaml . 3 | 4 | clang++-10 \ 5 | -o fuzz_exec \ 6 | fuzz_exec.cpp \ 7 | -fsanitize=fuzzer \ 8 | -lprotobuf -lgraphfuzz 9 | 10 | clang++-10 \ 11 | -o fuzz_write \ 12 | fuzz_write.cpp \ 13 | -fsanitize=fuzzer \ 14 | -lprotobuf -lgraphfuzz 15 | -------------------------------------------------------------------------------- /experiments/custom_endpoints/in/lib.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | class Foo { 6 | public: 7 | Foo(): buffer(0) {} 8 | 9 | void write(char val) { 10 | buffer.push_back(val); 11 | } 12 | 13 | void check() { 14 | if (buffer.size() >= 4 && \ 15 | buffer[0] == 'F' && \ 16 | buffer[1] == 'U' && \ 17 | buffer[2] == 'Z' && \ 18 | buffer[3] == 'Z' 19 | ) { 20 | __builtin_trap(); 21 | } 22 | } 23 | private: 24 | std::vector buffer; 25 | }; 26 | -------------------------------------------------------------------------------- /experiments/custom_endpoints/in/schema.yaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Foo: 4 | type: struct 5 | name: Foo 6 | headers: [lib.h] 7 | methods: 8 | - Foo() 9 | - ~Foo() 10 | - void write(char val) 11 | - void check() 12 | -------------------------------------------------------------------------------- /experiments/eigen/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM graphfuzz_base 2 | 3 | RUN apt-get -y update && apt-get -y install clang++-10 4 | 5 | WORKDIR /src 6 | RUN git clone https://gitlab.com/libeigen/eigen.git 7 | 8 | COPY in /harness/in 9 | WORKDIR /harness/in 10 | 11 | env ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-6.0/bin/llvm-symbolizer 12 | env ASAN_OPTIONS=detect_leaks=0,allocator_may_return_null=1 13 | CMD /bin/zsh 14 | -------------------------------------------------------------------------------- /experiments/eigen/in/build.sh: -------------------------------------------------------------------------------- 1 | # Usage: ./build.sh 2 | 3 | echo "Building $1 exec..." 4 | clang++-10 -g \ 5 | -std=c++17 \ 6 | $1/fuzz_exec.cpp \ 7 | -I/src/eigen \ 8 | -fsanitize=fuzzer,address \ 9 | -lgraphfuzz -lprotobuf \ 10 | -o $1/fuzz_exec 11 | 12 | echo "Building $1 write..." 13 | clang++-10 \ 14 | -std=c++17 \ 15 | $1/fuzz_write.cpp \ 16 | -I/src/eigen \ 17 | -fsanitize=fuzzer,address \ 18 | -lgraphfuzz -lprotobuf \ 19 | -o $1/fuzz_write 20 | -------------------------------------------------------------------------------- /experiments/eigen/in/f1/schema.yaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | struct_MatrixXf: 4 | headers: 5 | - 6 | default_destructor: true 7 | type: struct 8 | name: Eigen::MatrixXf 9 | methods: 10 | - Eigen::MatrixXf(int, int) 11 | - set: 12 | inputs: ['Eigen::MatrixXf'] 13 | outputs: ['Eigen::MatrixXf'] 14 | args: ['int', 'int', 'float'] 15 | exec: | 16 | $i0->operator()($a0, $a1) = $a2; 17 | $o0 = $i0; 18 | - void operator+=(Eigen::MatrixXf) 19 | - void operator-=(Eigen::MatrixXf) 20 | - void operator*=(float) 21 | - void operator*=(Eigen::MatrixXf) 22 | - void operator*=(Eigen::VectorXf) 23 | - void operator/=(float) 24 | - void resize(int, int) 25 | - void transpose() 26 | - void conjugate() 27 | - void adjoint() 28 | - void transposeInPlace() 29 | - float sum() 30 | - float prod() 31 | - float mean() 32 | - float minCoeff() 33 | - float maxCoeff() 34 | - float trace() 35 | static_methods: 36 | - Eigen::MatrixXf Eigen::Matrix2f() 37 | - Eigen::MatrixXf Eigen::Matrix3f() 38 | - Eigen::MatrixXf Eigen::Matrix4f() 39 | 40 | struct_VectorXf: 41 | headers: 42 | - 43 | default_destructor: true 44 | type: struct 45 | name: Eigen::VectorXf 46 | methods: 47 | - Eigen::VectorXf(int) 48 | - set: 49 | inputs: ['Eigen::VectorXf'] 50 | outputs: ['Eigen::VectorXf'] 51 | args: ['int', 'float'] 52 | exec: | 53 | $i0->operator()($a0) = $a1; 54 | $o0 = $i0; 55 | - void operator+=(Eigen::VectorXf) 56 | - void operator-=(Eigen::VectorXf) 57 | - void operator*=(float) 58 | - void operator*=(Eigen::MatrixXf) 59 | - void operator*=(Eigen::VectorXf) 60 | - void operator/=(float) 61 | - void resize(int) 62 | - void transpose() 63 | - float sum() 64 | - float prod() 65 | - float mean() 66 | - float minCoeff() 67 | - float maxCoeff() 68 | - float trace() 69 | static_methods: 70 | - Eigen::VectorXf Eigen::Vector2f() 71 | - Eigen::VectorXf Eigen::Vector3f() 72 | - Eigen::VectorXf Eigen::Vector4f() 73 | -------------------------------------------------------------------------------- /experiments/eigen/in/test.sh: -------------------------------------------------------------------------------- 1 | ./build.sh f1 2 | 3 | cd f1 && \ 4 | mkdir -p artifacts && mkdir -p corpus && \ 5 | ./fuzz_exec --graphfuzz_init_corpus ./corpus && \ 6 | ./fuzz_exec ./corpus --graphfuzz_catch=6 -fork=32 -ignore_crashes=1 -artifact_prefix="./artifacts/" 7 | -------------------------------------------------------------------------------- /experiments/ex_array_demo/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM graphfuzz_base 2 | 3 | COPY in /harness/in 4 | WORKDIR /harness/in 5 | 6 | RUN ./build_lib.sh && ./build.sh 7 | 8 | ENV ASAN_OPTIONS=detect_leaks=0 9 | ENV ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-6.0/bin/llvm-symbolizer 10 | -------------------------------------------------------------------------------- /experiments/ex_array_demo/in/build.sh: -------------------------------------------------------------------------------- 1 | 2 | cd fuzz 3 | 4 | clang++ \ 5 | fuzz_exec.cpp \ 6 | -I../lib -L../lib \ 7 | -ltest -lgraphfuzz -lprotobuf \ 8 | -fsanitize=fuzzer,address \ 9 | -o fuzz_exec 10 | 11 | clang++ \ 12 | fuzz_write.cpp \ 13 | -I../lib -L../lib \ 14 | -ltest -lgraphfuzz -lprotobuf \ 15 | -fsanitize=fuzzer,address \ 16 | -o fuzz_write 17 | -------------------------------------------------------------------------------- /experiments/ex_array_demo/in/build_lib.sh: -------------------------------------------------------------------------------- 1 | 2 | cd lib 3 | clang++ -c lib.cpp 4 | llvm-ar-6.0 rc libtest.a lib.o 5 | -------------------------------------------------------------------------------- /experiments/ex_array_demo/in/fuzz/fuzz_exec.cpp: -------------------------------------------------------------------------------- 1 | #include "lib.h" 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | extern "C" int graphfuzz_try(); 9 | 10 | extern "C" void __attribute__((visibility ("default"))) global_init(int *argc, char ***argv) { 11 | 12 | } 13 | 14 | extern "C" void __attribute__((visibility ("default"))) shim_init() { 15 | 16 | } 17 | 18 | extern "C" void __attribute__((visibility ("default"))) shim_finalize() { 19 | 20 | } 21 | 22 | 23 | #define MAKE(t) static_cast(calloc(sizeof(t), 1)) 24 | 25 | struct GFUZZ_BUNDLE { 26 | public: 27 | void *active; 28 | void *inactive; 29 | GFUZZ_BUNDLE(void *_active, void *_inactive): active(_active), inactive(_inactive) {} 30 | }; 31 | 32 | #define BUNDLE(a,b) new GFUZZ_BUNDLE((void *)a, (void *)b) 33 | 34 | 35 | 36 | /* CPPScope(name=fuzz1) */ 37 | extern "C" void shim_0(void **in_ref, void **out_ref, const char *context) { 38 | Test *_i0 = reinterpret_cast(in_ref[0]); 39 | int _a0[4]; 40 | memcpy(&_a0, context + 0, 4 * 4); 41 | Test *_o0; 42 | _i0->fuzz1(_a0); 43 | _o0 = _i0; 44 | 45 | out_ref[0] = reinterpret_cast(_o0); 46 | } 47 | 48 | 49 | /* CPPScope(name=fuzz2) */ 50 | extern "C" void shim_1(void **in_ref, void **out_ref, const char *context) { 51 | Test *_i0 = reinterpret_cast(in_ref[0]); 52 | int _a0[32]; 53 | memcpy(&_a0, context + 0, 4 * 32); 54 | float _a1[8]; 55 | memcpy(&_a1, context + 128, 4 * 8); 56 | Test *_o0; 57 | _i0->fuzz2(_a0, _a1); 58 | _o0 = _i0; 59 | 60 | out_ref[0] = reinterpret_cast(_o0); 61 | } 62 | 63 | 64 | /* CPPScope(name=(auto) Test::Test();) */ 65 | extern "C" void shim_2(void **in_ref, void **out_ref, const char *context) { 66 | Test *_o0; 67 | _o0 = MAKE(Test); 68 | Test ref = Test(); 69 | *_o0 = ref; 70 | 71 | 72 | out_ref[0] = reinterpret_cast(_o0); 73 | } 74 | 75 | 76 | /* CPPScope(name=(auto) Test::~Test();) */ 77 | extern "C" void shim_3(void **in_ref, void **out_ref, const char *context) { 78 | Test *_i0 = reinterpret_cast(in_ref[0]); 79 | free(_i0); 80 | 81 | 82 | } 83 | 84 | 85 | void __attribute__((visibility ("default"))) (*FUZZER_SHIMS[])(void **, void **, const char *) = { 86 | &shim_0, 87 | &shim_1, 88 | &shim_2, 89 | &shim_3, 90 | }; 91 | 92 | -------------------------------------------------------------------------------- /experiments/ex_array_demo/in/fuzz/schema.json: -------------------------------------------------------------------------------- 1 | {"types": [{"id": 0, "name": "Test"}], "scopes": [{"name": "fuzz1", "inputs": [0], "outputs": [0], "context": 16}, {"name": "fuzz2", "inputs": [0], "outputs": [0], "context": 160}, {"name": "(auto) Test::Test();", "inputs": [], "outputs": [0], "context": 0}, {"name": "(auto) Test::~Test();", "inputs": [0], "outputs": [], "context": 0}]} -------------------------------------------------------------------------------- /experiments/ex_array_demo/in/fuzz/schema.yaml: -------------------------------------------------------------------------------- 1 | 2 | struct_Test: 3 | type: struct 4 | name: Test 5 | default_destructor: true 6 | headers: 7 | - lib.h 8 | methods: 9 | - Test() 10 | - fuzz1: 11 | inputs: ['Test'] 12 | outputs: ['Test'] 13 | args: ['int[4]'] 14 | exec: | 15 | $i0->fuzz1($a0); 16 | $o0 = $i0; 17 | - fuzz2: 18 | inputs: ['Test'] 19 | outputs: ['Test'] 20 | args: ['int[32]', 'float[8]'] 21 | exec: | 22 | $i0->fuzz2($a0, $a1); 23 | $o0 = $i0; 24 | -------------------------------------------------------------------------------- /experiments/ex_array_demo/in/lib/lib.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "lib.h" 3 | -------------------------------------------------------------------------------- /experiments/ex_array_demo/in/lib/lib.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Test { 4 | public: 5 | Test() {} 6 | void fuzz1(int a[4]) { 7 | if (a[2] == 3 && a[3] == 4) __builtin_trap(); 8 | } 9 | void fuzz2(int a[32], float b[8]) {} 10 | }; 11 | -------------------------------------------------------------------------------- /experiments/ex_auto_cpp/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM graphfuzz_base 2 | 3 | COPY in /harness/in 4 | 5 | RUN cd /harness/in && \ 6 | ./build_lib.sh && \ 7 | ./build.sh 8 | 9 | WORKDIR /harness/in 10 | ENV ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-6.0/bin/llvm-symbolizer 11 | -------------------------------------------------------------------------------- /experiments/ex_auto_cpp/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Auto C++ example 3 | 4 | This folder contains an example of using the gfuzz doxygen extractor to automatically generate a C++ schema. 5 | 6 | # Overview 7 | 8 | (Note: make sure `gfuzz` (`graphfuzz/python/gfuzz`) is on your PATH.) 9 | 10 | Run the doxygen extractor with: 11 | 12 | ```sh 13 | $ gfuzz doxygen --inputs ./in/src --output ./in/doxygen_output 14 | ``` 15 | 16 | This step will launch a new docker container with doxygen and set up the proper Doxyfile to parse the target. The output xml will be saved to `./in/doxygen_output/xml`. 17 | 18 | Next, we can automatically infer the schema with: 19 | 20 | ```sh 21 | $ gfuzz schema infer ./in/doxygen_output/xml ./in/auto_schema.yaml 22 | ``` 23 | 24 | Finally, we can generate the harness files with: 25 | 26 | ``` 27 | $ gfuzz gen cpp ./in/auto_schema.yaml ./in/ 28 | ``` 29 | 30 | --- 31 | 32 | Build and launch the docker container with: 33 | ```sh 34 | $ cd graphfuzz/examples/auto_cpp 35 | $ gfuzz run . 36 | ``` 37 | 38 | Inside the container, build the fuzzers (`fuzz_exec`, `fuzz_write`) with: 39 | ```sh 40 | $ ./build_fuzzer.sh 41 | ``` 42 | 43 | You can fuzz with the libFuzzer binary `fuzz_exec`: 44 | ```sh 45 | $ ./fuzz_exec -fork=10 ... 46 | ``` 47 | 48 | Once you have a crash, you can view it with `fuzz_write`: 49 | ```sh 50 | $ ./fuzz_write ./crash-xxx 51 | ``` 52 | 53 | You can also minimize the crash with: 54 | ```sh 55 | $ gfuzz min ./fuzz_exec ./crash-xxx 56 | ``` 57 | 58 | # Handling `assert()`'s 59 | 60 | In this example, `Rect::setVal(float)` will throw assertion errors on invalid arguments which is a common pattern for safe C++ code. In this case, we don't care about these assertion errors. 61 | 62 | To bypass this, you can supply a list of signal numbers that should be ignored with `--graphfuzz_catch`. For example, to catch SIGABRT (raised by `assert()`), we can run the fuzzer like: 63 | 64 | ```sh 65 | $ ./fuzz_exec --graphfuzz_catch=6 66 | ``` 67 | 68 | In this mode, GraphFuzz will catch the error and cleanly exit the test case. However, this raises a new problem: we will suddenly hit a lot of memory leaks which triggers AddressSanitizer. To turn of leak detection, we can set `ASAN_OPTIONS` to `detect_leaks=0`, for example: 69 | 70 | ```sh 71 | $ ASAN_OPTIONS=detect_leaks=0 ./fuzz_exec --graphfuzz_catch=6 72 | ``` 73 | -------------------------------------------------------------------------------- /experiments/ex_auto_cpp/in/auto_schema.yaml: -------------------------------------------------------------------------------- 1 | enum_PointType: 2 | headers: 3 | - point.h 4 | name: PointType 5 | type: enum 6 | values: 7 | - POINT_SMALL 8 | - POINT_LARGE 9 | - POINT_CRASH 10 | struct_Point: 11 | default_destructor: true 12 | headers: 13 | - point.h 14 | methods: 15 | - Point(point_coord _x, point_coord _y) 16 | - void set(PointType _typ) 17 | - void offset(point_coord _x, point_coord _y) 18 | name: Point 19 | static_methods: 20 | - Point MakeZero() 21 | type: struct 22 | struct_Rect: 23 | default_destructor: true 24 | headers: 25 | - rect.h 26 | methods: 27 | - Rect() 28 | - void setA(Point &p) 29 | - void setB(Point &p) 30 | - void setVal(float v) 31 | - int area() 32 | - void fuzzFunc(int z) 33 | name: Rect 34 | static_methods: [] 35 | type: struct 36 | typedef_point_coord: 37 | headers: 38 | - point.h 39 | name: point_coord 40 | type: typedef 41 | value: int 42 | -------------------------------------------------------------------------------- /experiments/ex_auto_cpp/in/build.sh: -------------------------------------------------------------------------------- 1 | 2 | cd fuzz 3 | 4 | clang++ \ 5 | fuzz_exec.cpp \ 6 | -I../lib -L../lib \ 7 | -ltest -lgraphfuzz -lprotobuf \ 8 | -fsanitize=fuzzer,address \ 9 | -o fuzz_exec 10 | 11 | clang++ \ 12 | fuzz_write.cpp \ 13 | -I../lib -L../lib \ 14 | -ltest -lgraphfuzz -lprotobuf \ 15 | -fsanitize=fuzzer,address \ 16 | -o fuzz_write 17 | -------------------------------------------------------------------------------- /experiments/ex_auto_cpp/in/build_lib.sh: -------------------------------------------------------------------------------- 1 | 2 | cd lib 3 | clang++ -c *.cpp 4 | llvm-ar-6.0 rc libtest.a *.o 5 | -------------------------------------------------------------------------------- /experiments/ex_auto_cpp/in/fuzz/schema.json: -------------------------------------------------------------------------------- 1 | {"types": [{"id": 1, "name": "Point"}, {"id": 2, "name": "Rect"}], "scopes": [{"name": "(auto) Point::Point(point_coord _x, point_coord _y);", "inputs": [], "outputs": [1], "context": 8}, {"name": "(auto) Point::void set(PointType _typ);", "inputs": [1], "outputs": [1], "context": 1}, {"name": "(auto) Point::void offset(point_coord _x, point_coord _y);", "inputs": [1], "outputs": [1], "context": 8}, {"name": "(auto) Point::Point MakeZero();", "inputs": [], "outputs": [1], "context": 0}, {"name": "(auto) Point::~Point();", "inputs": [1], "outputs": [], "context": 0}, {"name": "(auto) Rect::Rect();", "inputs": [], "outputs": [2], "context": 0}, {"name": "(auto) Rect::void setA(Point & p);", "inputs": [2, 1], "outputs": [2, 1], "context": 0}, {"name": "(auto) Rect::void setB(Point & p);", "inputs": [2, 1], "outputs": [2, 1], "context": 0}, {"name": "(auto) Rect::void setVal(float v);", "inputs": [2], "outputs": [2], "context": 4}, {"name": "(auto) Rect::int area();", "inputs": [2], "outputs": [2], "context": 0}, {"name": "(auto) Rect::void fuzzFunc(int z);", "inputs": [2], "outputs": [2], "context": 4}, {"name": "(auto) Rect::~Rect();", "inputs": [2], "outputs": [], "context": 0}]} -------------------------------------------------------------------------------- /experiments/ex_auto_cpp/in/lib/point.cpp: -------------------------------------------------------------------------------- 1 | #include "point.h" 2 | 3 | void Point::offset(point_coord _x, point_coord _y) { 4 | this->x += x; 5 | this->y += y; 6 | } 7 | -------------------------------------------------------------------------------- /experiments/ex_auto_cpp/in/lib/point.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | typedef int point_coord; 5 | 6 | enum PointType { 7 | POINT_SMALL, 8 | POINT_LARGE, 9 | POINT_CRASH, 10 | }; 11 | 12 | struct Point { 13 | public: 14 | PointType typ; 15 | point_coord x, y; 16 | 17 | Point(point_coord _x, point_coord _y): x(_x), y(_y) {} 18 | 19 | void set(PointType _typ) { 20 | typ = _typ; 21 | } 22 | 23 | static Point MakeZero() { 24 | return Point {0,0}; 25 | } 26 | 27 | void offset(point_coord _x, point_coord _y); 28 | }; 29 | -------------------------------------------------------------------------------- /experiments/ex_auto_cpp/in/lib/rect.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include "rect.h" 7 | 8 | 9 | void Rect::fuzzFunc(int z) { 10 | if (z != 1337) return; 11 | 12 | if (this->a.typ != PointType::POINT_CRASH) return; 13 | if (this->b.typ != PointType::POINT_CRASH) return; 14 | 15 | if (this->area() != 100) return; 16 | 17 | if (val >= 0.7 && val < 0.8) { 18 | __builtin_trap(); 19 | } 20 | } 21 | 22 | int Rect::area() { 23 | int width = abs(this->a.x - this->b.x); 24 | int height = abs(this->a.y - this->b.y); 25 | return width * height; 26 | } 27 | -------------------------------------------------------------------------------- /experiments/ex_auto_cpp/in/lib/rect.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "point.h" 5 | 6 | struct Rect { 7 | private: 8 | Point a, b; 9 | float val; 10 | 11 | public: 12 | Rect(): a(0,0), b(0,0) {} 13 | void setA(Point &p) {a = p;}; 14 | void setB(Point &p) {b = p;}; 15 | void setVal(float v) {val = v;}; 16 | int area(); 17 | void fuzzFunc(int z); 18 | }; 19 | -------------------------------------------------------------------------------- /experiments/ex_auto_cpp/make_schema.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Context is graphfuzz/experiments/ex_auto_cpp 4 | pdir=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P ) 5 | cd "$pdir" 6 | 7 | # Run Doxygen to extract C++ metadata: 8 | mkdir -p ./doxygen_output 9 | gfuzz doxygen --inputs ./in/lib --output ./doxygen_output 10 | 11 | # Process the Doxygen XML and generate a GraphFuzz schema: 12 | gfuzz schema infer ./doxygen_output/xml ./in/auto_schema.yaml 13 | 14 | # Cleanup doxygen output: 15 | rm -rf ./doxygen_output 16 | 17 | # Generate fuzzer harnesses from the schema: 18 | mkdir -p ./in/fuzz 19 | gfuzz gen cpp ./in/auto_schema.yaml ./in/fuzz 20 | -------------------------------------------------------------------------------- /experiments/hello_graphfuzz/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM graphfuzz_base 2 | 3 | RUN apt-get -y update && apt-get -y install clang++-10 4 | 5 | COPY in /harness/in 6 | WORKDIR /harness/in 7 | 8 | env ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-6.0/bin/llvm-symbolizer 9 | env ASAN_OPTIONS=detect_leaks=0,allocator_may_return_null=1 10 | CMD /bin/zsh 11 | -------------------------------------------------------------------------------- /experiments/hello_graphfuzz/in/build.sh: -------------------------------------------------------------------------------- 1 | 2 | gfuzz gen cpp schema.yaml . 3 | 4 | clang++-10 \ 5 | -o fuzz_exec \ 6 | fuzz_exec.cpp \ 7 | -fsanitize=fuzzer \ 8 | -lprotobuf -lgraphfuzz 9 | 10 | clang++-10 \ 11 | -o fuzz_write \ 12 | fuzz_write.cpp \ 13 | -fsanitize=fuzzer \ 14 | -lprotobuf -lgraphfuzz 15 | -------------------------------------------------------------------------------- /experiments/hello_graphfuzz/in/lib.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | class Foo { 6 | public: 7 | Foo(): buffer(0) {} 8 | 9 | void write(char val) { 10 | buffer.push_back(val); 11 | } 12 | 13 | void check() { 14 | if (buffer.size() >= 4 && \ 15 | buffer[0] == 'F' && \ 16 | buffer[1] == 'U' && \ 17 | buffer[2] == 'Z' && \ 18 | buffer[3] == 'Z' 19 | ) { 20 | __builtin_trap(); 21 | } 22 | } 23 | private: 24 | std::vector buffer; 25 | }; 26 | -------------------------------------------------------------------------------- /experiments/hello_graphfuzz/in/schema.yaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Foo: 4 | type: struct 5 | name: Foo 6 | headers: [lib.h] 7 | methods: 8 | - Foo() 9 | - ~Foo() 10 | - void write(char val) 11 | - void check() 12 | -------------------------------------------------------------------------------- /experiments/hello_graphfuzz/in/schema_verbose.yaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Foo: 4 | type: struct 5 | name: Foo 6 | headers: [lib.h] 7 | methods: 8 | - Foo(): 9 | outputs: ['Foo'] 10 | exec: | 11 | $o0 = new Foo(); 12 | - ~Foo(): 13 | inputs: ['Foo'] 14 | exec: | 15 | delete $i0; 16 | - void write(char val): 17 | inputs: ['Foo'] 18 | outputs: ['Foo'] 19 | args: ['char'] 20 | exec: | 21 | $i0->write($a0); 22 | $o0 = $i0; 23 | - void check(): 24 | inputs: ['Foo'] 25 | outputs: ['Foo'] 26 | exec: | 27 | $i0->check(); 28 | $o0 = $i0; 29 | -------------------------------------------------------------------------------- /experiments/iowow/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM graphfuzz_base 2 | 3 | RUN apt-get -y update && apt-get -y install clang++-10 4 | 5 | RUN git clone https://github.com/Softmotions/iowow.git 6 | WORKDIR iowow 7 | RUN mkdir build && \ 8 | cd build && \ 9 | CC=clang-10 CFLAGS="-fsanitize=fuzzer-no-link,address" cmake .. -DCMAKE_BUILD_TYPE=Debug && \ 10 | make -j8 && \ 11 | make install 12 | 13 | COPY in /harness/in 14 | WORKDIR /harness/in 15 | 16 | env LD_LIBRARY_PATH=/usr/local/lib 17 | env ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-6.0/bin/llvm-symbolizer 18 | env ASAN_OPTIONS=detect_leaks=0 19 | CMD /bin/zsh 20 | -------------------------------------------------------------------------------- /experiments/iowow/in/bug.sh: -------------------------------------------------------------------------------- 1 | 2 | clang -g \ 3 | $1 \ 4 | -liowow -fsanitize=address \ 5 | -o out 6 | -------------------------------------------------------------------------------- /experiments/iowow/in/bugs/bug1.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | int main() { 5 | IWKV kv; 6 | IWKV_OPTS opts = { 7 | .path = "test.db", 8 | .oflags = IWKV_TRUNC 9 | }; 10 | (void)iwkv_open(&opts, &kv); 11 | IWDB db; 12 | uint32_t id; 13 | (void)iwkv_new_db(kv, 0, &id, &db); 14 | iwkv_db_set_meta(db, "hello", 6); 15 | iwkv_db_destroy(&db); 16 | iwkv_close(&kv); 17 | } 18 | -------------------------------------------------------------------------------- /experiments/iowow/in/bugs/bug2.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | int main() { 5 | IWKV kv; 6 | IWKV_OPTS opts = { 7 | .path = "test.db", 8 | .oflags = IWKV_TRUNC 9 | }; 10 | (void)iwkv_open(&opts, &kv); 11 | IWDB db; 12 | uint32_t id; 13 | (void)iwkv_new_db(kv, IWDB_VNUM64_KEYS, &id, &db); 14 | IWKV_val key = { .data = "abc", .size = 0 }; 15 | IWKV_cursor cur = 0; 16 | iwkv_cursor_open(db, &cur, IWKV_CURSOR_EQ, &key); 17 | iwkv_cursor_close(&cur); 18 | iwkv_db_destroy(&db); 19 | iwkv_close(&kv); 20 | } 21 | -------------------------------------------------------------------------------- /experiments/iowow/in/build.sh: -------------------------------------------------------------------------------- 1 | # Usage: ./build.sh 2 | 3 | echo "Building $1 exec..." 4 | clang++-10 -g \ 5 | $1/fuzz_exec.cpp \ 6 | -I. \ 7 | -fsanitize=fuzzer,address \ 8 | -liowow -lgraphfuzz -lprotobuf \ 9 | -o $1/fuzz_exec 10 | 11 | echo "Building $1 write..." 12 | clang++-10 \ 13 | $1/fuzz_write.cpp \ 14 | -I. \ 15 | -fsanitize=fuzzer,address \ 16 | -liowow -lgraphfuzz -lprotobuf \ 17 | -o $1/fuzz_write 18 | -------------------------------------------------------------------------------- /experiments/iowow/in/db_tracker.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | static vector open_dbs = vector(); 10 | static int curr_id = 0; 11 | 12 | IWKV *new_db() { 13 | string name = std::tmpnam(nullptr); 14 | 15 | IWKV_OPTS opts = { 16 | .path = name.c_str() 17 | }; 18 | 19 | IWKV *kv; 20 | kv = (IWKV *)calloc(1, sizeof(IWKV)); 21 | iwrc rc = iwkv_open(&opts, kv); 22 | 23 | open_dbs.push_back(kv); 24 | return kv; 25 | } 26 | 27 | void close_all() { 28 | for (int i = 0; i < open_dbs.size(); ++i) { 29 | IWKV *kv = open_dbs[i]; 30 | iwkv_close(kv); 31 | free(kv); 32 | } 33 | 34 | open_dbs.clear(); 35 | curr_id = 0; 36 | } 37 | 38 | int next_db_id() { 39 | curr_id += 1; 40 | return curr_id; 41 | } 42 | -------------------------------------------------------------------------------- /experiments/iowow/in/f1/schema.json: -------------------------------------------------------------------------------- 1 | {"types": [{"id": 3, "name": "IWKV"}, {"id": 4, "name": "IWDB"}, {"id": 5, "name": "IWKV_val"}, {"id": 6, "name": "IWKV_cursor"}], "scopes": [{"name": "open", "inputs": [], "outputs": [3], "context": 0}, {"name": "close", "inputs": [3], "outputs": [], "context": 0}, {"name": "iwkv_db_destroy(IWDB *dbp);", "inputs": [4], "outputs": [], "context": 0}, {"name": "iwkv_new_db", "inputs": [3], "outputs": [3, 4], "context": 4}, {"name": "iwkv_get(IWDB db, const IWKV_val *key, IWKV_val *oval);", "inputs": [4, 5], "outputs": [4, 5], "context": 0}, {"name": "iwkv_db_set_meta(IWDB db, void *buf, size_t sz);", "inputs": [4], "outputs": [4], "context": 101}, {"name": "iwkv_db_get_meta", "inputs": [4], "outputs": [4], "context": 0}, {"name": "(auto) IWDB::void iwkv_db_cache_release(IWDB db);", "inputs": [4], "outputs": [4], "context": 0}, {"name": "(auto) IWDB::void iwkv_put(IWDB db, IWKV_val * key, IWKV_val * val, uint8_t opflags);", "inputs": [4, 5, 5], "outputs": [4, 5, 5], "context": 1}, {"name": "(auto) IWDB::void iwkv_del(IWDB db, const IWKV_val * key, iwkv_opflags opflags);", "inputs": [4, 5], "outputs": [4, 5], "context": 1}, {"name": "create", "inputs": [], "outputs": [5], "context": 101}, {"name": "delete", "inputs": [5], "outputs": [], "context": 0}, {"name": "create", "inputs": [4, 5], "outputs": [4, 5, 6], "context": 1}, {"name": "close", "inputs": [6], "outputs": [], "context": 0}]} -------------------------------------------------------------------------------- /experiments/iowow/in/f1/schema.yaml: -------------------------------------------------------------------------------- 1 | 2 | config: 3 | type: config 4 | finalizer: | 5 | close_all(); 6 | 7 | typedef_iwkv_opflags: 8 | type: typedef 9 | value: uint8_t 10 | name: iwkv_opflags 11 | 12 | enum_IWKV_cursor_op: 13 | type: enum 14 | name: IWKV_cursor_op 15 | values: 16 | - IWKV_CURSOR_BEFORE_FIRST 17 | - IWKV_CURSOR_AFTER_LAST 18 | - IWKV_CURSOR_NEXT 19 | - IWKV_CURSOR_PREV 20 | - IWKV_CURSOR_EQ 21 | - IWKV_CURSOR_GE 22 | 23 | struct_IWKV: 24 | type: struct 25 | name: IWKV 26 | headers: ['', 'db_tracker.h'] 27 | static_methods: 28 | - open: 29 | outputs: ['IWKV'] 30 | exec: | 31 | $o0 = new_db(); 32 | - close: 33 | inputs: ['IWKV'] 34 | exec: | 35 | // forget 36 | 37 | struct_IWDB: 38 | type: struct 39 | name: IWDB 40 | headers: [''] 41 | static_methods: 42 | # - iwkv_db: 43 | # inputs: ['IWKV'] 44 | # outputs: ['IWKV', 'IWDB'] 45 | # args: ['int', 'int'] 46 | # exec: | 47 | # $o1 = MAKE(IWDB); 48 | # iwkv_db(*$i0, $a0, $a1, $o1); 49 | # $o0 = $i0; 50 | - iwkv_db_destroy(IWDB *dbp);: 51 | inputs: ['IWDB'] 52 | exec: | 53 | // iwkv_db_destroy($i0); 54 | - iwkv_new_db: 55 | inputs: ['IWKV'] 56 | outputs: ['IWKV', 'IWDB'] 57 | args: ['int'] 58 | exec: | 59 | $o1 = MAKE(IWDB); 60 | uint32_t a; 61 | iwkv_new_db(*$i0, $a0, &a, $o1); 62 | $o0 = $i0; 63 | - void iwkv_db_cache_release(IWDB db); 64 | - void iwkv_put(IWDB db, IWKV_val *key, IWKV_val *val, uint8_t opflags); 65 | - iwkv_get(IWDB db, const IWKV_val *key, IWKV_val *oval);: 66 | inputs: ['IWDB', 'IWKV_val'] 67 | outputs: ['IWDB', 'IWKV_val'] 68 | exec: | 69 | IWKV_val oval; 70 | iwkv_get(*$i0, $i1, &oval); 71 | $o0 = $i0; 72 | $o1 = $i1; 73 | - iwkv_db_set_meta(IWDB db, void *buf, size_t sz);: 74 | inputs: ['IWDB'] 75 | outputs: ['IWDB'] 76 | args: ['char[100]', 'uint8_t'] 77 | exec: | 78 | iwkv_db_set_meta(*$i0, &$a0, $a1 % 100); 79 | $o0 = $i0; 80 | - iwkv_db_get_meta: 81 | inputs: ['IWDB'] 82 | outputs: ['IWDB'] 83 | exec: | 84 | char buffer[100]; 85 | size_t rsz; 86 | iwkv_db_get_meta(*$i0, &buffer, 100, &rsz); 87 | $o0 = $i0; 88 | - void iwkv_del(IWDB db, const IWKV_val *key, iwkv_opflags opflags); 89 | 90 | struct_IWKV_val: 91 | type: struct 92 | name: IWKV_val 93 | headers: [''] 94 | static_methods: 95 | - create: 96 | outputs: ['IWKV_val'] 97 | args: ['char[100]', 'uint8_t'] 98 | exec: | 99 | $o0 = MAKE(IWKV_val); 100 | $o0->data = (char *)calloc(100,1); 101 | memcpy($o0->data, $a0, 100); 102 | $o0->size = $a1 % 100; 103 | - delete: 104 | inputs: ['IWKV_val'] 105 | exec: | 106 | free($i0->data); 107 | free($i0); 108 | 109 | struct_IWKV_cursor: 110 | type: struct 111 | name: IWKV_cursor 112 | headers: [''] 113 | static_methods: 114 | - create: 115 | inputs: ['IWDB', 'IWKV_val'] 116 | outputs: ['IWDB', 'IWKV_val', 'IWKV_cursor'] 117 | args: ['IWKV_cursor_op'] 118 | exec: | 119 | $o2 = MAKE(IWKV_cursor); 120 | iwrc rc = iwkv_cursor_open(*$i0, $o2, $a0, $i1); 121 | if (rc) { 122 | graphfuzz_bail(); 123 | } 124 | $o0 = $i0; 125 | $o1 = $i1; 126 | - close: 127 | inputs: ['IWKV_cursor'] 128 | exec: | 129 | iwkv_cursor_close($i0); 130 | -------------------------------------------------------------------------------- /experiments/iowow/in/test.sh: -------------------------------------------------------------------------------- 1 | 2 | ./build.sh f1 3 | 4 | cd f1 && \ 5 | mkdir artifacts && \ 6 | ./fuzz_exec -fork=32 -ignore_crashes=1 -artifact_prefix="./artifacts/" 7 | -------------------------------------------------------------------------------- /experiments/rdkit/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM graphfuzz_base 2 | 3 | WORKDIR /src 4 | ENV CMAKE_VERSION 3.19.2 5 | RUN apt-get update && apt-get install -y wget sudo && \ 6 | wget https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-Linux-x86_64.sh && \ 7 | chmod +x cmake-$CMAKE_VERSION-Linux-x86_64.sh && \ 8 | ./cmake-$CMAKE_VERSION-Linux-x86_64.sh --skip-license --prefix="/usr/local" && \ 9 | rm cmake-$CMAKE_VERSION-Linux-x86_64.sh && \ 10 | rm -rf /usr/local/doc/cmake /usr/local/bin/cmake-gui 11 | 12 | RUN cd /src && \ 13 | git clone https://github.com/rdkit/rdkit.git && \ 14 | cd rdkit && \ 15 | git checkout 69b143edd059612c2f28ad898fa2d87dc1525e6f 16 | 17 | COPY build_rdkit.sh /src/build_rdkit.sh 18 | RUN /src/build_rdkit.sh 19 | 20 | COPY in /harness/in 21 | WORKDIR /harness/in 22 | 23 | env ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-6.0/bin/llvm-symbolizer 24 | env ASAN_OPTIONS=detect_leaks=0,allocator_may_return_null=1 25 | -------------------------------------------------------------------------------- /experiments/rdkit/build_rdkit.sh: -------------------------------------------------------------------------------- 1 | 2 | export SRC=/src 3 | 4 | # Build zlib 5 | git clone --depth 1 -b master https://github.com/madler/zlib.git $SRC/zlib 6 | cd $SRC/zlib 7 | OLD_CFLAGS="$CFLAGS" 8 | export LDFLAGS="-fPIC $CFLAGS" 9 | export CFLAGS="-fPIC $CFLAGS" 10 | # Only build static libraries, so we don't accidentally link to zlib dynamically. 11 | ./configure --static 12 | make -j$(nproc) clean 13 | make -j$(nproc) all install 14 | unset LDFLAGS 15 | export CFLAGS="$OLD_CFLAGS" 16 | 17 | # We're building `rdkit` using clang, but the boost package is built using gcc. 18 | # For whatever reason, linking would fail. 19 | # (Mismatch between libstdc++ and libc++ maybe?) 20 | # It works if we build `rdkit` using gcc or build boost using clang instead. 21 | # We've opted for building boost using clang. 22 | cd $SRC && \ 23 | wget --quiet https://sourceforge.net/projects/boost/files/boost/1.69.0/boost_1_69_0.tar.bz2 && \ 24 | tar xjf boost_1_69_0.tar.bz2 && \ 25 | cd $SRC/boost_1_69_0 && \ 26 | ./bootstrap.sh --with-toolset=clang --with-libraries=serialization,system,iostreams,regex && \ 27 | ./b2 -q -j$(nproc) toolset=clang linkflags="-fPIC $CXXFLAGS $CXXFLAGS_EXTRA" cxxflags="-fPIC $CXXFLAGS $CXXFLAGS_EXTRA" link=static install 28 | 29 | cd $SRC/rdkit 30 | 31 | export CC="clang" 32 | export CXX="clang++" 33 | export SANITIZER_FLAGS_address="-fsanitize=address -fsanitize-address-use-after-scope" 34 | export COVERAGE_FLAGS="-fsanitize=fuzzer-no-link" 35 | export CFLAGS="-g -O1 -fno-omit-frame-pointer -gline-tables-only -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION $COVERAGE_FLAGS $SANITIZER_FLAGS_address" 36 | export CXXFLAGS="$CFLAGS" 37 | 38 | mkdir -p build && cd build 39 | 40 | cmake .. \ 41 | -DRDK_BUILD_PYTHON_WRAPPERS=OFF \ 42 | -DRDK_BUILD_FREETYPE_SUPPORT=OFF \ 43 | -DRDK_BUILD_FUZZ_TARGETS=OFF \ 44 | -DRDK_INSTALL_STATIC_LIBS=ON \ 45 | -DBoost_USE_STATIC_LIBS=ON 46 | 47 | make -j$(nproc) 48 | make install 49 | -------------------------------------------------------------------------------- /experiments/rdkit/in/Fuzz/build.sh: -------------------------------------------------------------------------------- 1 | 2 | export BOOSTHOME=/src/boost_1_69_0/boost 3 | export RDBASE=/src/rdkit 4 | 5 | export CPPFLAGS="-I${BOOSTHOME} -I${RDBASE}/Code -fsanitize=address" 6 | 7 | export LDFLAGS="-L${RDBASE}/build/lib -Wl,-rpath,${RDBASE}/build/lib -lRDKitAbbreviations -lRDKitForceFieldHelpers -lRDKitRDStreams -lRDKitAlignment -lRDKitFragCatalog -lRDKitRGroupDecomposition -lRDKitCIPLabeler -lRDKitGraphMol -lRDKitReducedGraphs -lRDKitCatalogs -lRDKitInfoTheory -lRDKitRingDecomposerLib -lRDKitChemReactions -lRDKitMMPA -lRDKitScaffoldNetwork -lRDKitChemTransforms -lRDKitMolAlign -lRDKitShapeHelpers -lRDKitChemicalFeatures -lRDKitMolCatalog -lRDKitSimDivPickers -lRDKitDataStructs -lRDKitMolChemicalFeatures -lRDKitSmilesParse -lRDKitDepictor -lRDKitMolDraw2D -lRDKitSubgraphs -lRDKitDeprotect -lRDKitMolEnumerator -lRDKitSubstructLibrary -lRDKitDescriptors -lRDKitMolHash -lRDKitSubstructMatch -lRDKitDistGeomHelpers -lRDKitMolInterchange -lRDKitTautomerQuery -lRDKitDistGeometry -lRDKitMolStandardize -lRDKitTrajectory -lRDKitEigenSolvers -lRDKitMolTransforms -lRDKitcoordgen -lRDKitFMCS -lRDKitO3AAlign -lRDKitga -lRDKitFileParsers -lRDKitOptimizer -lRDKithc -lRDKitFilterCatalog -lRDKitPartialCharges -lRDKitmaeparser -lRDKitFingerprints -lRDKitRDGeneral -lRDKitForceField -lRDKitRDGeometryLib" 8 | 9 | export CXX="clang++-10" 10 | 11 | echo "[*] Building proto..." 12 | (cd /harness/graphfuzz/src/ && \ 13 | protoc --cpp_out=. graph.proto) 14 | 15 | echo "[*] Building executor..." 16 | $CXX -g -c ${CPPFLAGS} -fsanitize=address fuzz_exec.cpp 17 | 18 | echo "[*] Building writer..." 19 | $CXX -g -c ${CPPFLAGS} -fsanitize=address fuzz_write.cpp 20 | 21 | echo "[*] Building graphfuzz..." 22 | $CXX -g -c /harness/graphfuzz/src/harness.cpp -DTRACE_MUTATIONS 23 | $CXX -g -c /harness/graphfuzz/src/graph.pb.cc 24 | 25 | echo "[*] Linking graphfuzz executor..." 26 | $CXX -g harness.o graph.pb.o fuzz_exec.o \ 27 | -fsanitize=address,fuzzer \ 28 | -lprotobuf -lssl -lcrypto ${LDFLAGS} \ 29 | -o fuzz_exec 30 | 31 | echo "[*] Linking graphfuzz writer..." 32 | $CXX -g harness.o graph.pb.o fuzz_write.o \ 33 | -fsanitize=address,fuzzer \ 34 | -lprotobuf -lssl -lcrypto ${LDFLAGS} \ 35 | -o fuzz_write 36 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/README.md: -------------------------------------------------------------------------------- 1 | # Bugs 2 | 3 | ### bug1: SEGV in RWMol::commitBatchEdit (https://github.com/rdkit/rdkit/issues/4122) 4 | 5 | ``` 6 | After certain sequences of adding/removing atoms in a RWMol in batch edit mode, RWMol::commitBatchEdit can segfault. Depending on the call sequence, this either segfaults which crashes the program or performs a heap-buffer-overflow and reads unallocated heap memory (which is only detectible with ASAN). 7 | ``` 8 | 9 | ### bug4: RWMol::setAtomBookmark can retain stale pointers and lead to UAF (https://github.com/rdkit/rdkit/issues/4126) 10 | 11 | ``` 12 | Invoking RWMol::setAtomBookmark implicitly copies an Atom pointer and subsequent calls to RWMol::clearAtomBookmark can invoke methods on the Atom (i.e. to check if the index matches the query index). However, this RWMol does not take ownership of the Atom pointer since the destructor will not free the Atom. Given this API, it appears to be legal to bookmark an atom in one RWMol while it is owned by a different RWMol which can lead to memory corruption as described below. 13 | 14 | Note that similar behavior is probably possible with Bond ownership. 15 | ``` 16 | 17 | ### bug5: SEGV in ROMol::getAtomDegree if atom is not in graph (https://github.com/rdkit/rdkit/issues/4127) 18 | 19 | ``` 20 | Invoking ROMol::getAtomDegree on an Atom * that is not contained in the molecule graph can segfault. 21 | ``` 22 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | #define MAKE(t) static_cast(calloc(sizeof(t), 1)) 5 | 6 | struct GFUZZ_BUNDLE { 7 | public: 8 | void *active; 9 | void *inactive; 10 | GFUZZ_BUNDLE(void *_active, void *_inactive): active(_active), inactive(_inactive) {}; 11 | }; 12 | 13 | #define BUNDLE(a,b) new GFUZZ_BUNDLE((void *)a, (void *)b) 14 | 15 | int main() { 16 | RDKit::RWMol *var_0; 17 | { // begin shim_0 18 | var_0 = new RDKit::RWMol(); 19 | } // end shim_0 20 | RDKit::RWMol *var_1; 21 | { // begin shim_9 22 | var_0->beginBatchEdit(); 23 | var_1 = var_0; 24 | } // end shim_9 25 | RDKit::RWMol *var_2; 26 | { // begin shim_2 27 | var_1->addAtom(true); 28 | var_2 = var_1; 29 | } // end shim_2 30 | RDKit::RWMol *var_3; 31 | { // begin shim_11 32 | var_2->commitBatchEdit(); 33 | var_3 = var_2; 34 | } // end shim_11 35 | { // begin shim_1 36 | delete var_3; 37 | } // end shim_1 38 | } 39 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug1.py: -------------------------------------------------------------------------------- 1 | 2 | from rdkit.Chem import AllChem as Chem 3 | 4 | m = Chem.RWMol() 5 | m.BeginBatchEdit() 6 | m.AddAtom(Chem.Atom(1)) 7 | m.CommitBatchEdit() 8 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug1_min.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | RDKit::RWMol *mol = new RDKit::RWMol(); 5 | mol->beginBatchEdit(); 6 | mol->addAtom(true); 7 | mol->commitBatchEdit(); 8 | } 9 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug2.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | 6 | #define MAKE(t) static_cast(calloc(sizeof(t), 1)) 7 | 8 | struct GFUZZ_BUNDLE { 9 | public: 10 | void *active; 11 | void *inactive; 12 | GFUZZ_BUNDLE(void *_active, void *_inactive): active(_active), inactive(_inactive) {}; 13 | }; 14 | 15 | #define BUNDLE(a,b) new GFUZZ_BUNDLE((void *)a, (void *)b) 16 | 17 | int main() { 18 | RDKit::RWMol *var_0; 19 | { // begin shim_0 20 | var_0 = new RDKit::RWMol(); 21 | } // end shim_0 22 | RDKit::Atom *var_1; 23 | { // begin shim_17 24 | var_1 = MAKE(RDKit::Atom); 25 | RDKit::Atom ref = RDKit::Atom(); 26 | *var_1 = ref; 27 | } // end shim_17 28 | RDKit::RWMol *var_2; 29 | RDKit::Atom *var_3; 30 | { // begin shim_3 31 | var_0->addAtom(var_1, 0, 0); 32 | var_2 = var_0; 33 | var_3 = var_1; 34 | } // end shim_3 35 | { // begin shim_1 36 | delete var_2; 37 | } // end shim_1 38 | { // begin shim_48 39 | free(var_3); 40 | } // end shim_48 41 | } 42 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug2_min.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #define MAKE(t) dynamic_cast(static_cast(calloc(1, sizeof(t)))) 8 | 9 | int main() { 10 | RDKit::RWMol * mol = new RDKit::RWMol(); 11 | 12 | RDKit::Atom *var_1; 13 | var_1 = MAKE(RDKit::Atom); 14 | *var_1 = RDKit::Atom(1); 15 | 16 | std::cout << var_1->getAtomicNum() << std::endl; 17 | RDKit::Atom *b = var_1->copy(); 18 | 19 | mol->addAtom(var_1, 0, 0); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | #define MAKE(t) static_cast(calloc(sizeof(t), 1)) 8 | 9 | struct GFUZZ_BUNDLE { 10 | public: 11 | void *active; 12 | void *inactive; 13 | GFUZZ_BUNDLE(void *_active, void *_inactive): active(_active), inactive(_inactive) {}; 14 | }; 15 | 16 | #define BUNDLE(a,b) new GFUZZ_BUNDLE((void *)a, (void *)b) 17 | 18 | int main() { 19 | RDKit::Bond *var_0; 20 | { // begin shim_94 21 | var_0 = new RDKit::Bond(); 22 | } // end shim_94 23 | RDKit::ROMol *var_1; 24 | { // begin shim_22 25 | var_1 = new RDKit::ROMol(); 26 | } // end shim_22 27 | RDKit::Bond *var_2; 28 | RDKit::ROMol *var_3; 29 | { // begin shim_105 30 | var_0->setOwningMol(var_1); 31 | var_2 = var_0; 32 | var_3 = var_1; 33 | } // end shim_105 34 | { // begin shim_24 35 | delete var_3; 36 | } // end shim_24 37 | RDKit::Bond *var_4; 38 | { // begin shim_112 39 | var_2->setBeginAtomIdx(0); 40 | var_4 = var_2; 41 | } // end shim_112 42 | { // begin shim_123 43 | delete var_4; 44 | } // end shim_123 45 | } 46 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug3_min.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | int main() { 9 | RDKit::Bond *bond = new RDKit::Bond(); 10 | RDKit::ROMol *mol = new RDKit::ROMol(); 11 | bond->setOwningMol(mol); 12 | delete mol; 13 | bond->setBeginAtomIdx(0); 14 | } 15 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | #define MAKE(t) static_cast(calloc(sizeof(t), 1)) 8 | 9 | struct GFUZZ_BUNDLE { 10 | public: 11 | void *active; 12 | void *inactive; 13 | GFUZZ_BUNDLE(void *_active, void *_inactive): active(_active), inactive(_inactive) {}; 14 | }; 15 | 16 | #define BUNDLE(a,b) new GFUZZ_BUNDLE((void *)a, (void *)b) 17 | 18 | int main() { 19 | RDKit::ROMol *var_0; 20 | { // begin shim_22 21 | var_0 = new RDKit::ROMol(); 22 | } // end shim_22 23 | RDKit::Atom *var_1; 24 | { // begin shim_50 25 | var_1 = new RDKit::Atom(); 26 | } // end shim_50 27 | RDKit::ROMol *var_2; 28 | RDKit::Atom *var_3; 29 | { // begin shim_5 30 | var_0->setAtomBookmark(var_1, 0); 31 | var_2 = var_0; 32 | var_3 = var_1; 33 | } // end shim_5 34 | RDKit::RWMol *var_4; 35 | { // begin shim_30 36 | var_4 = new RDKit::RWMol(); 37 | } // end shim_30 38 | RDKit::RWMol *var_5; 39 | { // begin shim_26 40 | var_4->addAtom(var_3, 0, true); 41 | var_5 = var_4; 42 | } // end shim_26 43 | { // begin shim_31 44 | delete var_5; 45 | } // end shim_31 46 | RDKit::Atom *var_6; 47 | { // begin shim_50 48 | var_6 = new RDKit::Atom(); 49 | } // end shim_50 50 | RDKit::ROMol *var_7; 51 | RDKit::Atom *var_8; 52 | { // begin shim_8 53 | var_2->clearAtomBookmark(0, var_6); 54 | var_7 = var_2; 55 | var_8 = var_6; 56 | } // end shim_8 57 | { // begin shim_24 58 | delete var_7; 59 | } // end shim_24 60 | { // begin shim_91 61 | delete var_8; 62 | } // end shim_91 63 | } 64 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug4_min.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | RDKit::RWMol *mol1 = new RDKit::RWMol(); 6 | RDKit::Atom *atom1 = new RDKit::Atom(); 7 | mol1->setAtomBookmark(atom1, 0); 8 | 9 | RDKit::RWMol *mol2 = new RDKit::RWMol(); 10 | mol2->addAtom(atom1, false, true); 11 | 12 | // atom1 is freed because mol2 has ownership 13 | delete mol2; 14 | 15 | RDKit::Atom *atom2 = new RDKit::Atom(); 16 | 17 | // atom1 is used because mol1 has ownership 18 | mol1->clearAtomBookmark(0, atom2); 19 | } 20 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug4_min2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | void foo(RDKit::Atom *atom) { 8 | RDKit::RWMol mol; 9 | mol.addAtom(atom, false, true); 10 | // mol destructor is called 11 | } 12 | 13 | int main() { 14 | RDKit::ROMol mol; 15 | RDKit::Atom *atom = new RDKit::Atom(); 16 | mol.setAtomBookmark(atom, 0); 17 | 18 | foo(atom); 19 | 20 | RDKit::Atom *atom2 = new RDKit::Atom(); 21 | mol.clearAtomBookmark(0, atom2); 22 | } 23 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug5.cpp: -------------------------------------------------------------------------------- 1 | #include "" 2 | #include "" 3 | #include "" 4 | #include "" 5 | 6 | 7 | #define MAKE(t) static_cast(calloc(sizeof(t), 1)) 8 | 9 | struct GFUZZ_BUNDLE { 10 | public: 11 | void *active; 12 | void *inactive; 13 | GFUZZ_BUNDLE(void *_active, void *_inactive): active(_active), inactive(_inactive) {}; 14 | }; 15 | 16 | #define BUNDLE(a,b) new GFUZZ_BUNDLE((void *)a, (void *)b) 17 | 18 | int main() { 19 | RDKit::Atom *var_0; 20 | { // begin shim_50 21 | var_0 = new RDKit::Atom(); 22 | } // end shim_50 23 | RDKit::ROMol *var_1; 24 | { // begin shim_22 25 | var_1 = new RDKit::ROMol(); 26 | } // end shim_22 27 | RDKit::ROMol *var_2; 28 | RDKit::Atom *var_3; 29 | { // begin shim_3 30 | var_1->getAtomDegree(var_0); 31 | var_2 = var_1; 32 | var_3 = var_0; 33 | } // end shim_3 34 | { // begin shim_24 35 | delete var_2; 36 | } // end shim_24 37 | { // begin shim_91 38 | delete var_3; 39 | } // end shim_91 40 | } 41 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug5_min.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | RDKit::Atom *atom = new RDKit::Atom(); 6 | RDKit::ROMol *mol = new RDKit::ROMol(); 7 | mol->getAtomDegree(atom); 8 | } 9 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | #define MAKE(t) static_cast(calloc(sizeof(t), 1)) 8 | 9 | struct GFUZZ_BUNDLE { 10 | public: 11 | void *active; 12 | void *inactive; 13 | GFUZZ_BUNDLE(void *_active, void *_inactive): active(_active), inactive(_inactive) {}; 14 | }; 15 | 16 | #define BUNDLE(a,b) new GFUZZ_BUNDLE((void *)a, (void *)b) 17 | 18 | int main() { 19 | RDKit::Atom *var_0; 20 | { // begin shim_50 21 | var_0 = new RDKit::Atom(); 22 | } // end shim_50 23 | RDKit::RWMol *var_1; 24 | { // begin shim_30 25 | var_1 = new RDKit::RWMol(); 26 | } // end shim_30 27 | RDKit::RWMol *var_2; 28 | { // begin shim_26 29 | var_1->addAtom(var_0, 0, true); 30 | var_2 = var_1; 31 | } // end shim_26 32 | RDKit::RWMol *var_3; 33 | RDKit::Bond *var_4; 34 | { // begin shim_29 35 | var_4 = var_2->createPartialBond(0, RDKit::Bond::BondType::DOUBLE); 36 | var_3 = var_2; 37 | } // end shim_29 38 | { // begin shim_31 39 | delete var_3; 40 | } // end shim_31 41 | RDKit::Bond *var_5; 42 | { // begin shim_113 43 | var_4->setEndAtomIdx(62976); 44 | var_5 = var_4; 45 | } // end shim_113 46 | { // begin shim_123 47 | delete var_5; 48 | } // end shim_123 49 | } 50 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug6_min.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | RDKit::RWMol *mol = new RDKit::RWMol(); 6 | RDKit::Atom *atom = new RDKit::Atom(); 7 | mol->addAtom(atom, true, true); 8 | RDKit::Bond *bond = mol->createPartialBond(0, RDKit::Bond::BondType::SINGLE); 9 | delete mol; 10 | bond->setEndAtomIdx(1); 11 | } 12 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | #define MAKE(t) static_cast(calloc(sizeof(t), 1)) 10 | 11 | struct GFUZZ_BUNDLE { 12 | public: 13 | void *active; 14 | void *inactive; 15 | GFUZZ_BUNDLE(void *_active, void *_inactive): active(_active), inactive(_inactive) {}; 16 | }; 17 | 18 | #define BUNDLE(a,b) new GFUZZ_BUNDLE((void *)a, (void *)b) 19 | 20 | int main() { 21 | RDKit::ROMol *var_0; 22 | { // begin shim_22 23 | var_0 = new RDKit::ROMol(); 24 | } // end shim_22 25 | RDKit::Atom *var_1; 26 | { // begin shim_50 27 | var_1 = new RDKit::Atom(); 28 | } // end shim_50 29 | RDKit::ROMol *var_2; 30 | RDKit::Atom *var_3; 31 | { // begin shim_8 32 | var_0->replaceAtomBookmark(var_1, 35783448); 33 | var_2 = var_0; 34 | var_3 = var_1; 35 | } // end shim_8 36 | RDKit::ROMol *var_4; 37 | RDKit::Atom *var_5; 38 | { // begin shim_8 39 | var_2->replaceAtomBookmark(var_3, 248); 40 | var_4 = var_2; 41 | var_5 = var_3; 42 | } // end shim_8 43 | { // begin shim_91 44 | delete var_5; 45 | } // end shim_91 46 | RDKit::ROMol *var_6; 47 | RDKit::ROMol *var_7; 48 | { // begin shim_23 49 | var_6 = new RDKit::ROMol(*var_4, 0, 8192); 50 | var_7 = var_4; 51 | } // end shim_23 52 | { // begin shim_24 53 | delete var_7; 54 | } // end shim_24 55 | { // begin shim_24 56 | delete var_6; 57 | } // end shim_24 58 | } 59 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug7_min.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | int main() { 10 | 11 | RDKit::ROMol *mol = new RDKit::ROMol(); 12 | RDKit::Atom *atom = new RDKit::Atom(); 13 | mol->replaceAtomBookmark(atom, 0); 14 | mol->replaceAtomBookmark(atom, 1); 15 | 16 | 17 | RDKit::ROMol *var_0; 18 | { // begin shim_22 19 | var_0 = new RDKit::ROMol(); 20 | } // end shim_22 21 | RDKit::Atom *var_1; 22 | { // begin shim_50 23 | var_1 = new RDKit::Atom(); 24 | } // end shim_50 25 | RDKit::ROMol *var_2; 26 | RDKit::Atom *var_3; 27 | { // begin shim_8 28 | var_0->replaceAtomBookmark(var_1, 35783448); 29 | var_2 = var_0; 30 | var_3 = var_1; 31 | } // end shim_8 32 | RDKit::ROMol *var_4; 33 | RDKit::Atom *var_5; 34 | { // begin shim_8 35 | var_2->replaceAtomBookmark(var_3, 248); 36 | var_4 = var_2; 37 | var_5 = var_3; 38 | } // end shim_8 39 | { // begin shim_91 40 | delete var_5; 41 | } // end shim_91 42 | RDKit::ROMol *var_6; 43 | RDKit::ROMol *var_7; 44 | { // begin shim_23 45 | var_6 = new RDKit::ROMol(*var_4, 0, 8192); 46 | var_7 = var_4; 47 | } // end shim_23 48 | { // begin shim_24 49 | delete var_7; 50 | } // end shim_24 51 | { // begin shim_24 52 | delete var_6; 53 | } // end shim_24 54 | } 55 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug8.cpp: -------------------------------------------------------------------------------- 1 | #include "" 2 | #include "" 3 | #include "" 4 | #include "" 5 | #include "" 6 | #include "" 7 | 8 | 9 | #define MAKE(t) static_cast(calloc(sizeof(t), 1)) 10 | 11 | struct GFUZZ_BUNDLE { 12 | public: 13 | void *active; 14 | void *inactive; 15 | GFUZZ_BUNDLE(void *_active, void *_inactive): active(_active), inactive(_inactive) {}; 16 | }; 17 | 18 | #define BUNDLE(a,b) new GFUZZ_BUNDLE((void *)a, (void *)b) 19 | 20 | int main() { 21 | RDKit::Atom *var_0; 22 | { // begin shim_52 23 | var_0 = new RDKit::Atom(); 24 | } // end shim_52 25 | RDKit::RWMol *var_1; 26 | { // begin shim_32 27 | var_1 = new RDKit::RWMol(); 28 | } // end shim_32 29 | RDKit::RWMol *var_2; 30 | { // begin shim_28 31 | var_1->addAtom(var_0, 1, true); 32 | var_2 = var_1; 33 | } // end shim_28 34 | RDKit::ROMol *var_3; 35 | { // begin shim_24 36 | var_3 = new RDKit::ROMol(); 37 | } // end shim_24 38 | RDKit::RWMol *var_4; 39 | RDKit::Bond *var_5; 40 | { // begin shim_31 41 | var_5 = var_2->createPartialBond(0, RDKit::Bond::BondType::UNSPECIFIED); 42 | var_4 = var_2; 43 | } // end shim_31 44 | RDKit::ROMol *var_6; 45 | { // begin shim_97 46 | var_5->setOwningMol(*var_3); 47 | var_6 = var_3; 48 | } // end shim_97 49 | RDKit::RWMol *var_7; 50 | RDKit::Bond *var_8; 51 | { // begin shim_31 52 | var_8 = var_4->createPartialBond(0, RDKit::Bond::BondType::UNSPECIFIED); 53 | var_7 = var_4; 54 | } // end shim_31 55 | { // begin shim_33 56 | delete var_7; 57 | } // end shim_33 58 | RDKit::Bond *var_9; 59 | { // begin shim_115 60 | var_8->setEndAtomIdx(68714752); 61 | var_9 = var_8; 62 | } // end shim_115 63 | RDKit::ROMol *var_10; 64 | { // begin shim_96 65 | var_9->setOwningMol(var_6); 66 | var_10 = var_6; 67 | } // end shim_96 68 | { // begin shim_26 69 | delete var_10; 70 | } // end shim_26 71 | } 72 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug9.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | #define MAKE(t) static_cast(calloc(sizeof(t), 1)) 10 | 11 | struct GFUZZ_BUNDLE { 12 | public: 13 | void *active; 14 | void *inactive; 15 | GFUZZ_BUNDLE(void *_active, void *_inactive): active(_active), inactive(_inactive) {}; 16 | }; 17 | 18 | #define BUNDLE(a,b) new GFUZZ_BUNDLE((void *)a, (void *)b) 19 | 20 | int main() { 21 | RDKit::ROMol *var_0; 22 | { // begin shim_24 23 | var_0 = new RDKit::ROMol(); 24 | } // end shim_24 25 | RDKit::Conformer *var_1; 26 | { // begin shim_128 27 | var_1 = new RDKit::Conformer(); 28 | } // end shim_128 29 | RDKit::ROMol *var_2; 30 | { // begin shim_5 31 | var_0->addConformer(var_1, 0); 32 | var_2 = var_0; 33 | } // end shim_5 34 | GFUZZ_BUNDLE *var_3; 35 | { // begin shim_3 36 | RDKit::Conformer *conf = new RDKit::Conformer(); 37 | *conf = var_2->getConformer(0); 38 | var_3 = BUNDLE(conf, var_2); 39 | } // end shim_3 40 | RDGeom::Point3D *var_4; 41 | { // begin shim_142 42 | var_4 = new RDGeom::Point3D(); 43 | } // end shim_142 44 | GFUZZ_BUNDLE *var_5; 45 | RDGeom::Point3D *var_6; 46 | { // begin shim_151 47 | ((RDKit::Conformer *)var_3->active)->setAtomPos(-1, *var_4); 48 | var_5 = ((RDKit::Conformer *)var_3->active); 49 | var_6 = var_4; 50 | } // end shim_151 51 | GFUZZ_BUNDLE *var_7; 52 | RDGeom::Point3D *var_8; 53 | { // begin shim_151 54 | ((RDKit::Conformer *)var_5->active)->setAtomPos(0, *var_6); 55 | var_7 = ((RDKit::Conformer *)var_5->active); 56 | var_8 = var_6; 57 | } // end shim_151 58 | { // begin shim_146 59 | delete var_8; 60 | } // end shim_146 61 | RDKit::ROMol *var_9; 62 | { // begin shim_4 63 | var_9 = (RDKit::ROMol *)var_7->inactive; 64 | delete var_7; 65 | } // end shim_4 66 | { // begin shim_26 67 | delete var_9; 68 | } // end shim_26 69 | } 70 | -------------------------------------------------------------------------------- /experiments/rdkit/in/bugs/bug9_min.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | RDKit::Conformer *conf = new RDKit::Conformer(); 6 | RDGeom::Point3D *point = new RDGeom::Point3D(); 7 | conf->setAtomPos(0xffffffff, *point); 8 | } 9 | -------------------------------------------------------------------------------- /experiments/rdkit/in/example/build.sh: -------------------------------------------------------------------------------- 1 | 2 | export BOOSTHOME=/src/boost_1_69_0/boost 3 | export RDBASE=/src/rdkit 4 | 5 | export CPPFLAGS="-I${BOOSTHOME} -I${RDBASE}/Code -fsanitize=address" 6 | 7 | export LDFLAGS="-L${RDBASE}/build/lib -Wl,-rpath,${RDBASE}/build/lib -lRDKitAbbreviations -lRDKitForceFieldHelpers -lRDKitRDStreams -lRDKitAlignment -lRDKitFragCatalog -lRDKitRGroupDecomposition -lRDKitCIPLabeler -lRDKitGraphMol -lRDKitReducedGraphs -lRDKitCatalogs -lRDKitInfoTheory -lRDKitRingDecomposerLib -lRDKitChemReactions -lRDKitMMPA -lRDKitScaffoldNetwork -lRDKitChemTransforms -lRDKitMolAlign -lRDKitShapeHelpers -lRDKitChemicalFeatures -lRDKitMolCatalog -lRDKitSimDivPickers -lRDKitDataStructs -lRDKitMolChemicalFeatures -lRDKitSmilesParse -lRDKitDepictor -lRDKitMolDraw2D -lRDKitSubgraphs -lRDKitDeprotect -lRDKitMolEnumerator -lRDKitSubstructLibrary -lRDKitDescriptors -lRDKitMolHash -lRDKitSubstructMatch -lRDKitDistGeomHelpers -lRDKitMolInterchange -lRDKitTautomerQuery -lRDKitDistGeometry -lRDKitMolStandardize -lRDKitTrajectory -lRDKitEigenSolvers -lRDKitMolTransforms -lRDKitcoordgen -lRDKitFMCS -lRDKitO3AAlign -lRDKitga -lRDKitFileParsers -lRDKitOptimizer -lRDKithc -lRDKitFilterCatalog -lRDKitPartialCharges -lRDKitmaeparser -lRDKitFingerprints -lRDKitRDGeneral -lRDKitForceField -lRDKitRDGeometryLib" 8 | 9 | clang++ -g \ 10 | ${CPPFLAGS} ${LDFLAGS} \ 11 | -o test \ 12 | test.cpp 13 | -------------------------------------------------------------------------------- /experiments/rdkit/in/example/test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | RDKit::RWMol *ptr = RDKit::SmilesToMol("C[C@H](F)c1ccc(C#N)cc1"); 12 | std::cout << ptr->getNumAtoms() << std::endl; 13 | } 14 | -------------------------------------------------------------------------------- /experiments/rdkit/in/launch.sh: -------------------------------------------------------------------------------- 1 | nohup ./test.sh ./Fuzz 40 > out.log & 2 | -------------------------------------------------------------------------------- /experiments/rdkit/in/make.sh: -------------------------------------------------------------------------------- 1 | 2 | export BOOSTHOME=/src/boost_1_69_0/boost 3 | export RDBASE=/src/rdkit 4 | 5 | export CPPFLAGS="-I${BOOSTHOME} -I${RDBASE}/Code -fsanitize=address" 6 | 7 | export LDFLAGS="-L${RDBASE}/build/lib -Wl,-rpath,${RDBASE}/build/lib -lRDKitAbbreviations -lRDKitForceFieldHelpers -lRDKitRDStreams -lRDKitAlignment -lRDKitFragCatalog -lRDKitRGroupDecomposition -lRDKitCIPLabeler -lRDKitGraphMol -lRDKitReducedGraphs -lRDKitCatalogs -lRDKitInfoTheory -lRDKitRingDecomposerLib -lRDKitChemReactions -lRDKitMMPA -lRDKitScaffoldNetwork -lRDKitChemTransforms -lRDKitMolAlign -lRDKitShapeHelpers -lRDKitChemicalFeatures -lRDKitMolCatalog -lRDKitSimDivPickers -lRDKitDataStructs -lRDKitMolChemicalFeatures -lRDKitSmilesParse -lRDKitDepictor -lRDKitMolDraw2D -lRDKitSubgraphs -lRDKitDeprotect -lRDKitMolEnumerator -lRDKitSubstructLibrary -lRDKitDescriptors -lRDKitMolHash -lRDKitSubstructMatch -lRDKitDistGeomHelpers -lRDKitMolInterchange -lRDKitTautomerQuery -lRDKitDistGeometry -lRDKitMolStandardize -lRDKitTrajectory -lRDKitEigenSolvers -lRDKitMolTransforms -lRDKitcoordgen -lRDKitFMCS -lRDKitO3AAlign -lRDKitga -lRDKitFileParsers -lRDKitOptimizer -lRDKithc -lRDKitFilterCatalog -lRDKitPartialCharges -lRDKitmaeparser -lRDKitFingerprints -lRDKitRDGeneral -lRDKitForceField -lRDKitRDGeometryLib" 8 | 9 | clang++ -g \ 10 | ${CPPFLAGS} ${LDFLAGS} \ 11 | -o bug \ 12 | $1 13 | -------------------------------------------------------------------------------- /experiments/rdkit/in/test.sh: -------------------------------------------------------------------------------- 1 | 2 | cd $1 3 | 4 | ./build.sh 5 | 6 | mkdir -p corpus 7 | mkdir -p artifacts 8 | 9 | ./fuzz_exec \ 10 | --graphfuzz_trace_mutations \ 11 | ./corpus \ 12 | -artifact_prefix='./artifacts/' \ 13 | -fork=$2 \ 14 | --graphfuzz_catch=6 \ 15 | -ignore_crashes=1 16 | -------------------------------------------------------------------------------- /experiments/rdkit_demo/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM graphfuzz_base 2 | 3 | WORKDIR /src 4 | ENV CMAKE_VERSION 3.19.2 5 | RUN apt-get update && apt-get install -y wget sudo && \ 6 | wget https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-Linux-x86_64.sh && \ 7 | chmod +x cmake-$CMAKE_VERSION-Linux-x86_64.sh && \ 8 | ./cmake-$CMAKE_VERSION-Linux-x86_64.sh --skip-license --prefix="/usr/local" && \ 9 | rm cmake-$CMAKE_VERSION-Linux-x86_64.sh && \ 10 | rm -rf /usr/local/doc/cmake /usr/local/bin/cmake-gui 11 | 12 | RUN cd /src && \ 13 | git clone https://github.com/rdkit/rdkit.git && \ 14 | cd rdkit && \ 15 | git checkout 69b143edd059612c2f28ad898fa2d87dc1525e6f 16 | 17 | COPY build_rdkit.sh /src/build_rdkit.sh 18 | RUN /src/build_rdkit.sh 19 | 20 | RUN cd /src && \ 21 | wget https://github.com/sharkdp/bat/releases/download/v0.20.0/bat-v0.20.0-x86_64-unknown-linux-musl.tar.gz && \ 22 | tar xvzf bat-v0.20.0-x86_64-unknown-linux-musl.tar.gz && \ 23 | cp bat-v0.20.0-x86_64-unknown-linux-musl/bat /usr/local/bin/bat 24 | 25 | COPY in /harness/in 26 | WORKDIR /harness/in 27 | 28 | env ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-6.0/bin/llvm-symbolizer 29 | env ASAN_OPTIONS=detect_leaks=0,allocator_may_return_null=1 30 | -------------------------------------------------------------------------------- /experiments/rdkit_demo/build_rdkit.sh: -------------------------------------------------------------------------------- 1 | 2 | export SRC=/src 3 | 4 | # Build zlib 5 | git clone --depth 1 -b master https://github.com/madler/zlib.git $SRC/zlib 6 | cd $SRC/zlib 7 | OLD_CFLAGS="$CFLAGS" 8 | export LDFLAGS="-fPIC $CFLAGS" 9 | export CFLAGS="-fPIC $CFLAGS" 10 | # Only build static libraries, so we don't accidentally link to zlib dynamically. 11 | ./configure --static 12 | make -j$(nproc) clean 13 | make -j$(nproc) all install 14 | unset LDFLAGS 15 | export CFLAGS="$OLD_CFLAGS" 16 | 17 | # We're building `rdkit` using clang, but the boost package is built using gcc. 18 | # For whatever reason, linking would fail. 19 | # (Mismatch between libstdc++ and libc++ maybe?) 20 | # It works if we build `rdkit` using gcc or build boost using clang instead. 21 | # We've opted for building boost using clang. 22 | cd $SRC && \ 23 | wget --quiet https://sourceforge.net/projects/boost/files/boost/1.69.0/boost_1_69_0.tar.bz2 && \ 24 | tar xjf boost_1_69_0.tar.bz2 && \ 25 | cd $SRC/boost_1_69_0 && \ 26 | ./bootstrap.sh --with-toolset=clang --with-libraries=serialization,system,iostreams,regex && \ 27 | ./b2 -q -j$(nproc) toolset=clang linkflags="-fPIC $CXXFLAGS $CXXFLAGS_EXTRA" cxxflags="-fPIC $CXXFLAGS $CXXFLAGS_EXTRA" link=static install 28 | 29 | cd $SRC/rdkit 30 | 31 | export CC="clang" 32 | export CXX="clang++" 33 | export SANITIZER_FLAGS_address="-fsanitize=address -fsanitize-address-use-after-scope" 34 | export COVERAGE_FLAGS="-fsanitize=fuzzer-no-link" 35 | export CFLAGS="-g -O1 -fno-omit-frame-pointer -gline-tables-only -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION $COVERAGE_FLAGS $SANITIZER_FLAGS_address" 36 | export CXXFLAGS="$CFLAGS" 37 | 38 | mkdir -p build && cd build 39 | 40 | cmake .. \ 41 | -DRDK_BUILD_PYTHON_WRAPPERS=OFF \ 42 | -DRDK_BUILD_FREETYPE_SUPPORT=OFF \ 43 | -DRDK_BUILD_FUZZ_TARGETS=OFF \ 44 | -DRDK_INSTALL_STATIC_LIBS=ON \ 45 | -DBoost_USE_STATIC_LIBS=ON 46 | 47 | make -j$(nproc) 48 | make install 49 | -------------------------------------------------------------------------------- /experiments/rdkit_demo/in/build.sh: -------------------------------------------------------------------------------- 1 | 2 | gfuzz gen cpp schema.yaml . 3 | 4 | source ./set_flags.sh 5 | 6 | clang++ fuzz_exec.cpp -o fuzz_exec ${CPPFLAGS} ${LDFLAGS} -fsanitize=address,fuzzer -lgraphfuzz -lprotobuf 7 | 8 | clang++ fuzz_write.cpp -o fuzz_write ${CPPFLAGS} ${LDFLAGS} -fsanitize=address,fuzzer -lgraphfuzz -lprotobuf 9 | -------------------------------------------------------------------------------- /experiments/rdkit_demo/in/demo.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | int main() { 8 | RDKit::RWMol mol; 9 | 10 | RDKit::Atom a1(6); 11 | a1.setIsAromatic(true); 12 | 13 | RDKit::Atom a2(7); 14 | 15 | // Add atom 1 and 2 to bookmark #123 16 | // 17 | // Bookmark #123: [a1, a2] 18 | mol.setAtomBookmark(&a1, 123); 19 | mol.setAtomBookmark(&a2, 123); 20 | 21 | for (RDKit::Atom *a : mol.getAllAtomsWithBookmark(123)) { 22 | std::cout << "Num: " << a->getAtomicNum() << ", aromatic: " << a->getIsAromatic() << std::endl; 23 | } 24 | 25 | // Remove atom 1 from bookmark #123 26 | mol.clearAtomBookmark(123, &a1); 27 | 28 | // Delete bookmark #123 29 | mol.clearAtomBookmark(123); 30 | } 31 | -------------------------------------------------------------------------------- /experiments/rdkit_demo/in/schema.yaml: -------------------------------------------------------------------------------- 1 | 2 | struct_RWMol: 3 | type: struct 4 | name: RDKit::RWMol 5 | alloc_with_new: true 6 | headers: [''] 7 | methods: 8 | - RDKit::RWMol() 9 | - ~RDKit::RWMol() 10 | - void setAtomBookmark(RDKit::Atom *, int) 11 | - void clearAtomBookmark(int) 12 | - void clearAtomBookmark(int, RDKit::Atom *) 13 | - getAllAtomsWithBookmark(int): 14 | inputs: ['RDKit::RWMol'] 15 | outputs: ['RDKit::RWMol'] 16 | args: ['int'] 17 | exec: | 18 | if ($i0->hasAtomBookmark($a0)) { 19 | for (RDKit::Atom *atom : $i0->getAllAtomsWithBookmark($a0)) { 20 | atom->getAtomicNum(); 21 | } 22 | } 23 | $o0 = $i0; 24 | 25 | struct_Atom: 26 | type: struct 27 | name: RDKit::Atom 28 | alloc_with_new: true 29 | headers: [''] 30 | methods: 31 | - RDKit::Atom(int) 32 | - ~RDKit::Atom() 33 | - void setIsAromatic(bool) 34 | - bool getIsAromatic() 35 | - int getAtomicNum() 36 | -------------------------------------------------------------------------------- /experiments/rdkit_demo/in/set_flags.sh: -------------------------------------------------------------------------------- 1 | export BOOSTHOME=/src/boost_1_69_0/boost 2 | export RDBASE=/src/rdkit 3 | export CPPFLAGS="-I${BOOSTHOME} -I${RDBASE}/Code -fsanitize=address" 4 | export LDFLAGS="-L${RDBASE}/build/lib -Wl,-rpath,${RDBASE}/build/lib -lRDKitAbbreviations -lRDKitForceFieldHelpers -lRDKitRDStreams -lRDKitAlignment -lRDKitFragCatalog -lRDKitRGroupDecomposition -lRDKitCIPLabeler -lRDKitGraphMol -lRDKitReducedGraphs -lRDKitCatalogs -lRDKitInfoTheory -lRDKitRingDecomposerLib -lRDKitChemReactions -lRDKitMMPA -lRDKitScaffoldNetwork -lRDKitChemTransforms -lRDKitMolAlign -lRDKitShapeHelpers -lRDKitChemicalFeatures -lRDKitMolCatalog -lRDKitSimDivPickers -lRDKitDataStructs -lRDKitMolChemicalFeatures -lRDKitSmilesParse -lRDKitDepictor -lRDKitMolDraw2D -lRDKitSubgraphs -lRDKitDeprotect -lRDKitMolEnumerator -lRDKitSubstructLibrary -lRDKitDescriptors -lRDKitMolHash -lRDKitSubstructMatch -lRDKitDistGeomHelpers -lRDKitMolInterchange -lRDKitTautomerQuery -lRDKitDistGeometry -lRDKitMolStandardize -lRDKitTrajectory -lRDKitEigenSolvers -lRDKitMolTransforms -lRDKitcoordgen -lRDKitFMCS -lRDKitO3AAlign -lRDKitga -lRDKitFileParsers -lRDKitOptimizer -lRDKithc -lRDKitFilterCatalog -lRDKitPartialCharges -lRDKitmaeparser -lRDKitFingerprints -lRDKitRDGeneral -lRDKitForceField -lRDKitRDGeometryLib" 5 | -------------------------------------------------------------------------------- /experiments/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import argparse 3 | from pathlib import Path 4 | import subprocess 5 | from typing import List 6 | 7 | def run(args): 8 | subprocess.run(['docker', 'run', '-it', '--rm', f'graphfuzz_{args.experiment}', '/bin/bash']) 9 | 10 | def get_choices() -> List[str]: 11 | return [x.stem for x in Path('.').iterdir() if x.is_dir()] 12 | 13 | def main(): 14 | parser = argparse.ArgumentParser() 15 | parser.add_argument('experiment', choices=get_choices()) 16 | args = parser.parse_args() 17 | run(args) 18 | 19 | if __name__ == '__main__': 20 | main() 21 | -------------------------------------------------------------------------------- /experiments/skia/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM graphfuzz_base 2 | 3 | RUN apt-get -y update && apt-get -y install \ 4 | autoconf libtool libc6-dbg \ 5 | ninja-build liblzma-dev libz-dev pkg-config binutils nasm \ 6 | libtool-bin gettext \ 7 | gdb valgrind vim \ 8 | freeglut3-dev \ 9 | libfontconfig-dev \ 10 | libfreetype6-dev \ 11 | libgif-dev \ 12 | libgl1-mesa-dev \ 13 | libglu1-mesa-dev \ 14 | libharfbuzz-dev \ 15 | libicu-dev \ 16 | libjpeg-dev \ 17 | libpng-dev \ 18 | libwebp-dev \ 19 | python3-lxml doxygen zsh \ 20 | lcov \ 21 | libssl-dev 22 | 23 | # Use a pinned version of Skia for experiment reproducability. 24 | # bd816d3c5298f6eada11e18fc9e4ad08214c0dfc: May 14th, 2021 25 | WORKDIR /src 26 | RUN git clone https://github.com/google/skia.git && \ 27 | cd skia && \ 28 | git checkout bd816d3c5298f6eada11e18fc9e4ad08214c0dfc 29 | 30 | # Sync Skia dependencies. 31 | WORKDIR /src/skia 32 | RUN python2 tools/git-sync-deps 33 | RUN CLANGDIR="${HOME}/clang" && \ 34 | CC= CXX= infra/bots/assets/clang_linux/create.py -t "$CLANGDIR" 35 | 36 | # Build libprotobuf with the Skia toolchain using std=c++17 and the libc++ stdlib. 37 | WORKDIR /src 38 | RUN wget https://github.com/protocolbuffers/protobuf/releases/download/v3.15.8/protobuf-all-3.15.8.tar.gz 39 | RUN tar -xf protobuf-all-3.15.8.tar.gz 40 | WORKDIR /src/protobuf-3.15.8 41 | RUN ./configure CC=/root/clang/bin/clang CXX=/root/clang/bin/clang++ CXXFLAGS="-std=c++17 -stdlib=libc++" LDFLAGS="-stdlib=libc++" prefix=/usr && \ 42 | make -j8 && \ 43 | make install 44 | RUN ldconfig 45 | 46 | WORKDIR /src/skia 47 | 48 | # We use two builds of Skia: 49 | # - full: ASAN instrumented, with fuzzers 50 | # - cov_full: ASAN instrumented with coverage instrumentation (-fprofile-arcs,-ftest-coverage,--coverage) 51 | 52 | # For ease of development, we first build and cache an unmodified version of Skia and then add fuzzer files 53 | # and perform a partial rebuild. 54 | 55 | # Build Skia fuzzers with ASAN. 56 | RUN mkdir -p out/full && \ 57 | echo 'cc = "/root/clang/bin/clang"\ncxx = "/root/clang/bin/clang++"\nsanitize = "ASAN"\nextra_cflags = [ "-fsanitize=fuzzer-no-link,address" ]\nextra_ldflags = [ "-fuse-ld=lld", "-Wl,-rpath,/root/clang/lib", "-fsanitize=fuzzer-no-link,address" ]\nis_official_build=false\nis_component_build = false\nskia_enable_gpu = true\nskia_build_fuzzers=true' > out/full/args.gn && \ 58 | bin/gn gen out/full && \ 59 | ninja -C out/full 60 | 61 | # Build Skia fuzzers with ASAN and coverage instrumentation. 62 | RUN mkdir -p out/cov_full && \ 63 | echo 'cc = "/root/clang/bin/clang"\ncxx = "/root/clang/bin/clang++"\nsanitize = "ASAN"\nextra_cflags = [ "-fsanitize=fuzzer-no-link,address","-fprofile-arcs","-ftest-coverage","-fno-inline" ]\nextra_ldflags = [ "-fuse-ld=lld", "-Wl,-rpath,/root/clang/lib", "-fsanitize=fuzzer-no-link,address","--coverage" ]\nis_official_build=false\nis_component_build = false\nskia_enable_gpu = true\nskia_build_fuzzers=true' > out/cov_full/args.gn && \ 64 | bin/gn gen out/cov_full && \ 65 | ninja -C out/cov_full 66 | 67 | RUN apt-get install -y npm && npm install -g lcov-parse 68 | 69 | # Copy GraphFuzz harnesses into Skia build tree. 70 | COPY gf_fuzz /src/skia/gf_fuzz 71 | 72 | # Copy GraphFuzz core into Skia build tree. 73 | RUN mkdir /src/skia/graphfuzz && \ 74 | cp -r /graphfuzz/src /src/skia/graphfuzz/src 75 | 76 | # Patch Skia build rules. 77 | COPY patch/BUILD.gn /src/skia/BUILD.gn 78 | 79 | # Copy annotated Skia fuzzers into build tree. 80 | # Note: The existing Skia fuzzers have been modified to explicitly annotate 81 | # endpoint usage with the FUZZ_ENDPOINT macro. This was done strictly for the 82 | # purpose of benchmarking and is not necessary for normal GraphFuzz usage. 83 | RUN rm -rf /src/skia/fuzz 84 | COPY patch/fuzz /src/skia/fuzz 85 | RUN find /src/skia/fuzz -type f -exec touch {} + 86 | 87 | # Rebuild proto 88 | RUN cd /src/skia/graphfuzz/src && \ 89 | LD_LIBRARY_PATH=/root/clang/lib protoc --cpp_out=. graph.proto 90 | 91 | # Build fuzzers 92 | RUN cd /src/skia && \ 93 | bin/gn gen out/full/ && \ 94 | bin/gn gen out/cov_full/ && \ 95 | ninja -C out/full && \ 96 | ninja -C out/cov_full 97 | 98 | # Copy run scripts. 99 | COPY scripts /home/scripts 100 | WORKDIR /home/scripts 101 | 102 | env ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-6.0/bin/llvm-symbolizer 103 | env ASAN_OPTIONS=detect_leaks=0,allocator_may_return_null=1 104 | -------------------------------------------------------------------------------- /experiments/skia/README.md: -------------------------------------------------------------------------------- 1 | # Skia 2 | 3 | Skia is a graphics library maintained by Google and used in Chromium and Android. In this experiment, we create "mirror" harnesses for several existing OSS-Fuzz harnesses and compare the development cost and generated coverage. 4 | 5 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzCanvas/api_image_filter/schema.yaml: -------------------------------------------------------------------------------- 1 | include: 2 | - "../schema.yaml" 3 | 4 | struct_harness: 5 | type: struct 6 | name: harness 7 | headers: 8 | - SkPaint.h 9 | static_methods: 10 | - harness: 11 | inputs: ['sk_sp'] 12 | exec: | 13 | SkPaint paint; 14 | paint.setImageFilter(*$i0); 15 | SkBitmap bitmap; 16 | SkCanvas canvas(bitmap); 17 | canvas.saveLayer(SkRect::MakeWH(500, 500), &paint); 18 | delete $i0; 19 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzCanvas/api_mock_gpu_canvas/README.md: -------------------------------------------------------------------------------- 1 | 2 | I found it difficult to link to the correct gpu dependencies outside of the Skia build system. 3 | 4 | To build this harness, we need to copy some files into the Skia build tree and modify their build script. 5 | 6 | Specifically we do the following: 7 | 8 | 1. Copy -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzCanvas/api_mock_gpu_canvas/build.sh: -------------------------------------------------------------------------------- 1 | export CXX="/root/clang/bin/clang++" 2 | 3 | 4 | echo "[*] Reset build tree..." 5 | rm -rf /src/skia/graphfuzz 6 | mkdir /src/skia/graphfuzz 7 | 8 | echo "[*] Copy harness files..." 9 | cp /harness/in/FuzzCanvas/api_mock_gpu_canvas/fuzz_exec.cpp /src/skia/graphfuzz 10 | 11 | echo "[*] replace BUILD.gn ..." 12 | cp /harness/in/FuzzCanvas/api_mock_gpu_canvas/BUILD.gn /src/skia/BUILD.gn 13 | 14 | echo "[*] Building new targets using Skia build system..." 15 | cd /src/skia 16 | ninja -C out/full \ 17 | gf_mock_gpu_exec 18 | 19 | echo "[*] (cov) Building new targets using Skia build system..." 20 | cd /src/skia 21 | ninja -C out/cov_full \ 22 | gf_mock_gpu_exec 23 | 24 | echo "[*] Building proto..." 25 | (cd /harness/graphfuzz/src/ && \ 26 | protoc --cpp_out=. graph.proto) 27 | 28 | cd /harness/in/FuzzCanvas/api_mock_gpu_canvas 29 | 30 | echo "[*] Building graphfuzz..." 31 | $CXX -g -c /harness/graphfuzz/src/harness.cpp 32 | $CXX -g -c /harness/graphfuzz/src/graph.pb.cc 33 | 34 | echo "[*] Linking graphfuzz executor..." 35 | $CXX -g harness.o graph.pb.o \ 36 | -fsanitize=fuzzer,address \ 37 | -lprotobuf \ 38 | -L/src/skia/out/full -lgf_mock_gpu_exec \ 39 | -Wl,-rpath,/src/skia/out/full \ 40 | -o fuzz_exec 41 | 42 | echo "[*] Linking graphfuzz writer..." 43 | $CXX -g fuzz_write.cpp harness.o graph.pb.o \ 44 | -fsanitize=fuzzer,address \ 45 | -lprotobuf \ 46 | -o fuzz_write 47 | 48 | echo "[*] (cov) Linking graphfuzz executor..." 49 | $CXX -g harness.o graph.pb.o \ 50 | -fsanitize=fuzzer,address \ 51 | -lprotobuf \ 52 | -L/src/skia/out/cov_full -lgf_mock_gpu_exec \ 53 | -Wl,-rpath,/src/skia/out/cov_full \ 54 | -o fuzz_exec_cov 55 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzCanvas/api_mock_gpu_canvas/schema.yaml: -------------------------------------------------------------------------------- 1 | include: 2 | - "../schema.yaml" 3 | 4 | bundle: 5 | type: bundle 6 | name: bundle 7 | active: SkCanvas 8 | inactive: SkSurface 9 | 10 | struct_foo: 11 | headers: 12 | - SkSurface.h 13 | - include/gpu/GrDirectContext.h 14 | - include/gpu/gl/GrGLFunctions.h 15 | - src/gpu/GrDirectContextPriv.h 16 | - src/gpu/gl/GrGLGpu.h 17 | - src/gpu/gl/GrGLUtil.h 18 | - tools/gpu/GrContextFactory.h 19 | type: struct 20 | name: foo 21 | static_methods: 22 | - api_mock_gpu_canvas: 23 | outputs: ['bundle'] 24 | exec: | 25 | sk_sp *parent = MAKE(sk_sp); 26 | 27 | constexpr SkISize kCanvasSize = {128, 160}; 28 | 29 | sk_gpu_test::GrContextFactory f; 30 | GrDirectContext *gpu_context = f.get(sk_gpu_test::GrContextFactory::kMock_ContextType); 31 | 32 | *parent = SkSurface::MakeRenderTarget( 33 | gpu_context, 34 | SkBudgeted::kNo, 35 | SkImageInfo::Make(kCanvasSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType)); 36 | 37 | SkCanvas *canvas = parent->get()->getCanvas(); 38 | $o0 = BUNDLE(canvas, parent); 39 | - delete: 40 | inputs: ['bundle'] 41 | exec: | 42 | delete $i0; 43 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzCanvas/api_null_canvas/schema.yaml: -------------------------------------------------------------------------------- 1 | include: 2 | - "../schema.yaml" 3 | 4 | bundle: 5 | type: bundle 6 | name: bundle 7 | active: SkCanvas 8 | inactive: SkNullCanvas 9 | 10 | struct_foo: 11 | headers: 12 | - include/utils/SkNullCanvas.h 13 | type: struct 14 | name: foo 15 | static_methods: 16 | - api_null_canvas: 17 | outputs: ['bundle'] 18 | exec: | 19 | std::unique_ptr *parent = MAKE(std::unique_ptr); 20 | *parent = SkMakeNullCanvas(); 21 | SkCanvas *canvas = parent->get(); 22 | $o0 = BUNDLE(canvas, parent); 23 | - delete: 24 | inputs: ['bundle'] 25 | exec: | 26 | delete $i0; 27 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzCanvas/api_raster_n32_canvas/schema.yaml: -------------------------------------------------------------------------------- 1 | include: 2 | - "../schema.yaml" 3 | 4 | bundle: 5 | type: bundle 6 | name: bundle 7 | active: SkCanvas 8 | inactive: SkSurface 9 | 10 | struct_foo: 11 | headers: 12 | - SkSurface.h 13 | type: struct 14 | name: foo 15 | static_methods: 16 | - api_null_canvas: 17 | outputs: ['bundle'] 18 | exec: | 19 | sk_sp *parent = MAKE(sk_sp); 20 | *parent = SkSurface::MakeRasterN32Premul(128,160); 21 | SkCanvas *canvas = parent->get()->getCanvas(); 22 | $o0 = BUNDLE(canvas, parent); 23 | - delete: 24 | inputs: ['bundle'] 25 | exec: | 26 | delete $i0; 27 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzCanvas/api_svg_canvas/schema.yaml: -------------------------------------------------------------------------------- 1 | include: 2 | - "../schema.yaml" 3 | 4 | bundle: 5 | type: bundle 6 | name: bundle 7 | active: SkCanvas 8 | inactive: SkSurface 9 | 10 | struct_foo: 11 | headers: 12 | - include/svg/SkSVGCanvas.h 13 | type: struct 14 | name: foo 15 | static_methods: 16 | - api_null_canvas: 17 | outputs: ['bundle'] 18 | exec: | 19 | SkNullWStream *stream = new SkNullWStream(); 20 | SkRect bounds = SkRect::MakeIWH(150, 150); 21 | std::unique_ptr *parent = MAKE(std::unique_ptr); 22 | *parent = SkSVGCanvas::Make(bounds, stream); 23 | SkCanvas *canvas = parent->get(); 24 | $o0 = BUNDLE(canvas, parent); 25 | - delete: 26 | inputs: ['bundle'] 27 | exec: | 28 | delete $i0; 29 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzCanvas/build_baseline.sh: -------------------------------------------------------------------------------- 1 | 2 | echo "[*] Build baseline fuzzer." 3 | /root/clang/bin/clang++ \ 4 | /src/skia/fuzz/FuzzDrawFunctions.cpp \ 5 | /src/skia/fuzz/oss_fuzz/FuzzDrawFunctions.cpp \ 6 | /src/skia/fuzz/Fuzz.cpp \ 7 | /src/skia/fuzz/FuzzCommon.cpp \ 8 | -I /src/skia/ \ 9 | -L /src/skia/out/asan/ -lskia \ 10 | -Wl,-rpath,/src/skia/out/asan \ 11 | -fsanitize=address,fuzzer \ 12 | -o api_draw_functions 13 | 14 | echo "[*] Build baseline fuzzer with coverage." 15 | /root/clang/bin/clang++ \ 16 | /src/skia/fuzz/FuzzDrawFunctions.cpp \ 17 | /src/skia/fuzz/oss_fuzz/FuzzDrawFunctions.cpp \ 18 | /src/skia/fuzz/Fuzz.cpp \ 19 | /src/skia/fuzz/FuzzCommon.cpp \ 20 | -I /src/skia/ \ 21 | -L /src/skia/out/cov/ -lskia \ 22 | -Wl,-rpath,/src/skia/out/cov \ 23 | -fsanitize=address,fuzzer \ 24 | -o api_draw_functions_cov 25 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzCanvas/image_filter_deserialize/schema.yaml: -------------------------------------------------------------------------------- 1 | include: 2 | - "../schema.yaml" 3 | 4 | struct_harness: 5 | type: struct 6 | name: harness 7 | headers: 8 | - SkPaint.h 9 | static_methods: 10 | - harness: 11 | inputs: ['sk_sp'] 12 | args: ['uint32_t[256]', 'uint8_t[256]'] 13 | exec: | 14 | auto filter = *$i0; 15 | if (filter == nullptr) return; 16 | 17 | SkBitmap bitmap; 18 | bitmap.tryAllocN32Pixels(256, 256); 19 | 20 | auto data = filter->serialize(); 21 | const unsigned char* ptr = static_cast(data->data()); 22 | unsigned char* p = const_cast(ptr); 23 | size_t len = data->size(); 24 | 25 | // Bitflips 26 | for (int i = 0; i < 256; ++i) { 27 | size_t pos = $a0[i] % len; 28 | p[pos] = $a1[i]; 29 | } 30 | 31 | auto deserializedFil = SkImageFilter::Deserialize(ptr, len); 32 | SkPaint paint; 33 | paint.setImageFilter(deserializedFil); 34 | 35 | SkCanvas canvas(bitmap); 36 | canvas.saveLayer(SkRect::MakeWH(256, 256), &paint); 37 | canvas.restore(); 38 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzDrawFunctions/build_baseline.sh: -------------------------------------------------------------------------------- 1 | 2 | echo "[*] Build baseline fuzzer." 3 | /root/clang/bin/clang++ \ 4 | /src/skia/fuzz/FuzzDrawFunctions.cpp \ 5 | /src/skia/fuzz/oss_fuzz/FuzzDrawFunctions.cpp \ 6 | /src/skia/fuzz/Fuzz.cpp \ 7 | /src/skia/fuzz/FuzzCommon.cpp \ 8 | -I /src/skia/ \ 9 | -L /src/skia/out/asan/ -lskia \ 10 | -Wl,-rpath,/src/skia/out/asan \ 11 | -fsanitize=address,fuzzer \ 12 | -o api_draw_functions 13 | 14 | echo "[*] Build baseline fuzzer with coverage." 15 | /root/clang/bin/clang++ \ 16 | /src/skia/fuzz/FuzzDrawFunctions.cpp \ 17 | /src/skia/fuzz/oss_fuzz/FuzzDrawFunctions.cpp \ 18 | /src/skia/fuzz/Fuzz.cpp \ 19 | /src/skia/fuzz/FuzzCommon.cpp \ 20 | -I /src/skia/ \ 21 | -L /src/skia/out/cov/ -lskia \ 22 | -Wl,-rpath,/src/skia/out/cov \ 23 | -fsanitize=address,fuzzer \ 24 | -o api_draw_functions_cov 25 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzPathMeasure/schema.json: -------------------------------------------------------------------------------- 1 | {"types": [{"id": 1, "name": "SkPath"}, {"id": 2, "name": "SkPathMeasure"}, {"id": 3, "name": "SkRect"}, {"id": 4, "name": "SkPoint"}], "scopes": [{"name": "(auto) SkPath::SkPath();", "inputs": [], "outputs": [1], "context": 0}, {"name": "(auto) SkPath::void moveTo(SkScalar None, SkScalar None);", "inputs": [1], "outputs": [1], "context": 8}, {"name": "(auto) SkPath::void lineTo(SkScalar None, SkScalar None);", "inputs": [1], "outputs": [1], "context": 8}, {"name": "(auto) SkPath::void quadTo(SkScalar None, SkScalar None, SkScalar None, SkScalar None);", "inputs": [1], "outputs": [1], "context": 16}, {"name": "(auto) SkPath::void conicTo(SkScalar None, SkScalar None, SkScalar None, SkScalar None, SkScalar None);", "inputs": [1], "outputs": [1], "context": 20}, {"name": "(auto) SkPath::void cubicTo(SkScalar None, SkScalar None, SkScalar None, SkScalar None, SkScalar None, SkScalar None);", "inputs": [1], "outputs": [1], "context": 24}, {"name": "(auto) SkPath::void close();", "inputs": [1], "outputs": [1], "context": 0}, {"name": "(auto) SkPath::SkRect getBounds();", "inputs": [1], "outputs": [1, 3], "context": 0}, {"name": "(auto) SkPath::~SkPath();", "inputs": [1], "outputs": [], "context": 0}, {"name": "(auto) SkPathMeasure::SkPathMeasure(const SkPath & path, bool forceClosed, SkScalar resScale);", "inputs": [1], "outputs": [2, 1], "context": 5}, {"name": "(auto) SkPathMeasure::bool getPosTan(SkScalar distance, SkPoint * position, SkVector * tangent);", "inputs": [2, 4, 4], "outputs": [2, 4, 4], "context": 4}, {"name": "(auto) SkPathMeasure::bool getSegment(SkScalar startD, SkScalar stopD, SkPath * dst, bool startWithMoveTo);", "inputs": [2, 1], "outputs": [2, 1], "context": 9}, {"name": "(auto) SkPathMeasure::bool nextContour();", "inputs": [2], "outputs": [2], "context": 0}, {"name": "(auto) SkPathMeasure::~SkPathMeasure();", "inputs": [2], "outputs": [], "context": 0}, {"name": "(auto) SkRect::SkRect MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h);", "inputs": [], "outputs": [3], "context": 16}, {"name": "(auto) SkRect::~SkRect();", "inputs": [3], "outputs": [], "context": 0}, {"name": "(auto) SkPoint::SkPoint Make(SkScalar x, SkScalar y);", "inputs": [], "outputs": [4], "context": 8}, {"name": "(auto) SkPoint::~SkPoint();", "inputs": [4], "outputs": [], "context": 0}]} -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzPathMeasure/schema.yaml: -------------------------------------------------------------------------------- 1 | 2 | typedef_SkScalar: 3 | headers: 4 | - SkScalar.h 5 | name: SkScalar 6 | type: typedef 7 | value: float 8 | 9 | struct_SkPath: 10 | type: struct 11 | name: SkPath 12 | default_destructor: true 13 | headers: 14 | - include/core/SkPath.h 15 | methods: 16 | - SkPath() 17 | - void moveTo(SkScalar, SkScalar) 18 | - void lineTo(SkScalar, SkScalar) 19 | - void quadTo(SkScalar, SkScalar, SkScalar, SkScalar) 20 | - void conicTo(SkScalar, SkScalar, SkScalar, SkScalar, SkScalar) 21 | - void cubicTo(SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar) 22 | - void close() 23 | - SkRect getBounds() 24 | 25 | struct_SkPathMeasure: 26 | type: struct 27 | name: SkPathMeasure 28 | default_destructor: true 29 | alloc_with_new: true 30 | headers: 31 | - include/core/SkPathMeasure.h 32 | methods: 33 | - SkPathMeasure(const SkPath& path, bool forceClosed, SkScalar resScale) 34 | - bool getPosTan(SkScalar distance, SkPoint* position, SkVector* tangent) 35 | - bool getSegment(SkScalar startD, SkScalar stopD, SkPath* dst, bool startWithMoveTo) 36 | - bool nextContour() 37 | 38 | struct_SkRect: 39 | type: struct 40 | name: SkRect 41 | default_destructor: true 42 | headers: 43 | - include/core/SkRect.h 44 | static_methods: 45 | - SkRect MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) 46 | 47 | struct_SkPoint: 48 | type: struct 49 | name: SkPoint 50 | default_destructor: true 51 | headers: 52 | - include/core/SkPoint.h 53 | static_methods: 54 | - SkPoint Make(SkScalar x, SkScalar y) 55 | 56 | typedef_SkVector: 57 | headers: 58 | - SkPoint.h 59 | name: SkVector 60 | type: typedef 61 | value: SkPoint 62 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzPathOp/schema.json: -------------------------------------------------------------------------------- 1 | {"types": [{"id": 1, "name": "SkPath"}, {"id": 2, "name": "SkOpBuilder"}, {"id": 3, "name": "SkRect"}], "scopes": [{"name": "(auto) SkPath::SkPath();", "inputs": [], "outputs": [1], "context": 0}, {"name": "(auto) SkPath::void moveTo(SkScalar None, SkScalar None);", "inputs": [1], "outputs": [1], "context": 8}, {"name": "(auto) SkPath::void lineTo(SkScalar None, SkScalar None);", "inputs": [1], "outputs": [1], "context": 8}, {"name": "(auto) SkPath::void quadTo(SkScalar None, SkScalar None, SkScalar None, SkScalar None);", "inputs": [1], "outputs": [1], "context": 16}, {"name": "(auto) SkPath::void conicTo(SkScalar None, SkScalar None, SkScalar None, SkScalar None, SkScalar None);", "inputs": [1], "outputs": [1], "context": 20}, {"name": "(auto) SkPath::void cubicTo(SkScalar None, SkScalar None, SkScalar None, SkScalar None, SkScalar None, SkScalar None);", "inputs": [1], "outputs": [1], "context": 24}, {"name": "(auto) SkPath::void close();", "inputs": [1], "outputs": [1], "context": 0}, {"name": "(auto) SkPath::SkRect getBounds();", "inputs": [1], "outputs": [1, 3], "context": 0}, {"name": "(auto) SkPath::void setFillType(SkPathFillType None);", "inputs": [1], "outputs": [1], "context": 1}, {"name": "(auto) SkPath::~SkPath();", "inputs": [1], "outputs": [], "context": 0}, {"name": "(auto) SkOpBuilder::SkOpBuilder();", "inputs": [], "outputs": [2], "context": 0}, {"name": "(auto) SkOpBuilder::void add(const SkPath & path, SkPathOp op);", "inputs": [2, 1], "outputs": [2, 1], "context": 1}, {"name": "(auto) SkOpBuilder::bool resolve(SkPath * result);", "inputs": [2, 1], "outputs": [2, 1], "context": 0}, {"name": "(auto) SkOpBuilder::bool Simplify(const SkPath & path, SkPath * result);", "inputs": [1, 1], "outputs": [1, 1], "context": 0}, {"name": "(auto) SkOpBuilder::bool Op(const SkPath & one, const SkPath & two, SkPathOp op, SkPath * result);", "inputs": [1, 1, 1], "outputs": [1, 1, 1], "context": 1}, {"name": "(auto) SkOpBuilder::bool AsWinding(const SkPath & path, SkPath * result);", "inputs": [1, 1], "outputs": [1, 1], "context": 0}, {"name": "(auto) SkOpBuilder::bool TightBounds(const SkPath & path, SkRect * result);", "inputs": [1, 3], "outputs": [1, 3], "context": 0}, {"name": "(auto) SkOpBuilder::~SkOpBuilder();", "inputs": [2], "outputs": [], "context": 0}, {"name": "(auto) SkRect::SkRect MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h);", "inputs": [], "outputs": [3], "context": 16}, {"name": "(auto) SkRect::~SkRect();", "inputs": [3], "outputs": [], "context": 0}]} -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzPathOp/schema.yaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | typedef_SkScalar: 4 | headers: 5 | - SkScalar.h 6 | name: SkScalar 7 | type: typedef 8 | value: float 9 | 10 | struct_SkPath: 11 | type: struct 12 | name: SkPath 13 | default_destructor: true 14 | headers: 15 | - include/core/SkPath.h 16 | methods: 17 | - SkPath() 18 | - void moveTo(SkScalar, SkScalar) 19 | - void lineTo(SkScalar, SkScalar) 20 | - void quadTo(SkScalar, SkScalar, SkScalar, SkScalar) 21 | - void conicTo(SkScalar, SkScalar, SkScalar, SkScalar, SkScalar) 22 | - void cubicTo(SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar) 23 | - void close() 24 | - SkRect getBounds() 25 | - void setFillType(SkPathFillType) 26 | 27 | struct_SkOpBuilder: 28 | type: struct 29 | name: SkOpBuilder 30 | default_destructor: true 31 | headers: 32 | - include/pathops/SkPathOps.h 33 | methods: 34 | - SkOpBuilder() 35 | - void add(const SkPath& path, SkPathOp op) 36 | - bool resolve(SkPath* result) 37 | static_methods: 38 | - bool Simplify(const SkPath& path, SkPath* result) 39 | - bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) 40 | - bool AsWinding(const SkPath& path, SkPath* result) 41 | - bool TightBounds(const SkPath& path, SkRect* result) 42 | 43 | struct_SkRect: 44 | type: struct 45 | name: SkRect 46 | default_destructor: true 47 | headers: 48 | - include/core/SkRect.h 49 | static_methods: 50 | - SkRect MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) 51 | 52 | enum_SkPathOp: 53 | headers: 54 | - include/pathops/SkPathOps.h 55 | name: SkPathOp 56 | type: enum 57 | values: 58 | - kDifference_SkPathOp 59 | - kIntersect_SkPathOp 60 | - kUnion_SkPathOp 61 | - kXOR_SkPathOp 62 | - kReverseDifference_SkPathOp 63 | 64 | enum_SkPathFillType: 65 | headers: 66 | - include/core/SkPathTypes.h 67 | name: SkPathFillType 68 | type: enum 69 | values: 70 | - kWinding 71 | - kEvenOdd 72 | - kInverseWinding 73 | - kInverseEvenOdd 74 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzPolyUtils/poly_util.h: -------------------------------------------------------------------------------- 1 | 2 | #include "include/core/SkRect.h" 3 | #include "include/core/SkPoint.h" 4 | #include "include/private/SkTemplates.h" 5 | #include "src/utils/SkPolyUtils.h" 6 | 7 | #define MAX_COUNT 512 8 | 9 | class PolyTester { 10 | public: 11 | PolyTester(int _count, SkScalar coords[MAX_COUNT * 2], uint16_t _indexMap[MAX_COUNT]) { 12 | count = _count % MAX_COUNT; 13 | ptr = (SkPoint *)calloc(count, sizeof(SkPoint)); 14 | indexMap = (uint16_t *)calloc(count, sizeof(uint16_t)); 15 | for (int i = 0; i < count; ++i) { 16 | ptr[i].fX = coords[i*2]; 17 | ptr[i].fY = coords[(i*2)+1]; 18 | indexMap[i] = _indexMap[i]; 19 | } 20 | }; 21 | 22 | ~PolyTester() { 23 | free(ptr); 24 | free(indexMap); 25 | } 26 | 27 | void test_SkGetPolygonWinding() { 28 | SkGetPolygonWinding(ptr, count); 29 | } 30 | 31 | void test_SkIsConvexPolygon() { 32 | SkIsConvexPolygon(ptr, count); 33 | } 34 | 35 | void test_SkIsSimplePolygon() { 36 | SkIsSimplePolygon(ptr, count); 37 | } 38 | 39 | void test_SkInsetConvexPolygon(SkScalar inset) { 40 | SkTDArray output; 41 | SkInsetConvexPolygon(ptr, count, inset, &output); 42 | } 43 | 44 | void test_SkOffsetSimplePolygon(SkScalar offset) { 45 | SkRect bounds; 46 | bounds.setBoundsCheck(ptr, count); 47 | 48 | SkTDArray output; 49 | SkOffsetSimplePolygon(ptr, count, bounds, offset, &output); 50 | } 51 | 52 | void test_SkTriangulateSimplePolygon() { 53 | SkTDArray outputIndices; 54 | SkTriangulateSimplePolygon(ptr, indexMap, count, &outputIndices); 55 | } 56 | 57 | private: 58 | SkPoint *ptr; 59 | uint16_t *indexMap; 60 | int count; 61 | }; 62 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzPolyUtils/schema.json: -------------------------------------------------------------------------------- 1 | {"types": [{"id": 1, "name": "PolyTester"}], "scopes": [{"name": "PolyTester(int _count, SkScalar coords[1024], uint16_t _indexMap[512])", "inputs": [], "outputs": [1], "context": 5124}, {"name": "(auto) PolyTester::void test_SkGetPolygonWinding();", "inputs": [1], "outputs": [1], "context": 0}, {"name": "(auto) PolyTester::void test_SkIsConvexPolygon();", "inputs": [1], "outputs": [1], "context": 0}, {"name": "(auto) PolyTester::void test_SkIsSimplePolygon();", "inputs": [1], "outputs": [1], "context": 0}, {"name": "(auto) PolyTester::void test_SkInsetConvexPolygon(SkScalar inset);", "inputs": [1], "outputs": [1], "context": 4}, {"name": "(auto) PolyTester::void test_SkOffsetSimplePolygon(SkScalar offset);", "inputs": [1], "outputs": [1], "context": 4}, {"name": "(auto) PolyTester::void test_SkTriangulateSimplePolygon();", "inputs": [1], "outputs": [1], "context": 0}, {"name": "(auto) PolyTester::~PolyTester();", "inputs": [1], "outputs": [], "context": 0}]} -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzPolyUtils/schema.yaml: -------------------------------------------------------------------------------- 1 | 2 | typedef_SkScalar: 3 | headers: 4 | - SkScalar.h 5 | name: SkScalar 6 | type: typedef 7 | value: float 8 | 9 | struct_PolyTester: 10 | type: struct 11 | name: PolyTester 12 | default_destructor: true 13 | alloc_with_new: true 14 | headers: 15 | - poly_util.h 16 | methods: 17 | - PolyTester(int _count, SkScalar coords[1024], uint16_t _indexMap[512]): 18 | args: ['int', 'SkScalar[1024]', 'uint16_t[512]'] 19 | outputs: ['PolyTester'] 20 | exec: | 21 | $o0 = new PolyTester($a0, $a1, $a2); 22 | - void test_SkGetPolygonWinding() 23 | - void test_SkIsConvexPolygon() 24 | - void test_SkIsSimplePolygon() 25 | - void test_SkInsetConvexPolygon(SkScalar inset) 26 | - void test_SkOffsetSimplePolygon(SkScalar offset) 27 | - void test_SkTriangulateSimplePolygon() 28 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzRegionOp/schema.json: -------------------------------------------------------------------------------- 1 | {"types": [{"id": 0, "name": "SkRegion"}, {"id": 1, "name": "SkIRect"}], "scopes": [{"name": "(auto) SkRegion::SkRegion();", "inputs": [], "outputs": [0], "context": 0}, {"name": "(auto) SkRegion::bool op(const SkIRect & rect, SkRegion::Op op);", "inputs": [0, 1], "outputs": [0, 1], "context": 1}, {"name": "(auto) SkRegion::int computeRegionComplexity();", "inputs": [0], "outputs": [0], "context": 0}, {"name": "(auto) SkRegion::~SkRegion();", "inputs": [0], "outputs": [], "context": 0}, {"name": "(auto) SkIRect::void sort();", "inputs": [1], "outputs": [1], "context": 0}, {"name": "(auto) SkIRect::SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b);", "inputs": [], "outputs": [1], "context": 16}, {"name": "(auto) SkIRect::~SkIRect();", "inputs": [1], "outputs": [], "context": 0}]} -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzRegionOp/schema.yaml: -------------------------------------------------------------------------------- 1 | 2 | struct_SkRegion: 3 | type: struct 4 | name: SkRegion 5 | default_destructor: true 6 | headers: 7 | - include/core/SkRegion.h 8 | methods: 9 | - SkRegion() 10 | - bool op(const SkIRect& rect, SkRegion::Op op) 11 | - int computeRegionComplexity() 12 | 13 | struct_SkIRect: 14 | type: struct 15 | name: SkIRect 16 | default_destructor: true 17 | headers: 18 | - include/core/SkRect.h 19 | methods: 20 | - void sort() 21 | static_methods: 22 | - SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) 23 | 24 | enum_SkRegion::Op: 25 | type: enum 26 | name: SkRegion::Op 27 | values: 28 | - kDifference_Op 29 | - kIntersect_Op 30 | - kUnion_Op 31 | - kXOR_Op 32 | - kReverseDifference_Op 33 | - kReplace_Op 34 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzSkParagraph/build.sh: -------------------------------------------------------------------------------- 1 | 2 | export CXXFLAGS="\ 3 | -std=c++17 \ 4 | -fvisibility-inlines-hidden \ 5 | -stdlib=libc++ \ 6 | -fno-exceptions \ 7 | -Wnon-virtual-dtor \ 8 | -Wno-noexcept-type \ 9 | -Wno-redundant-move \ 10 | -Wno-abstract-vbase-init \ 11 | -Wno-weak-vtables \ 12 | -Wno-c++98-compat \ 13 | -Wno-c++98-compat-pedantic \ 14 | -Wno-undefined-func-template" 15 | 16 | export CXX="/root/clang/bin/clang++" 17 | 18 | echo "[*] Building proto..." 19 | (cd /harness/graphfuzz/src/ && \ 20 | protoc --cpp_out=. graph.proto) 21 | 22 | echo "[*] Building executor..." 23 | $CXX fuzz_exec.cpp \ 24 | /src/skia/tools/Resources.cpp \ 25 | /src/skia/tools/flags/CommandLineFlags.cpp \ 26 | -ferror-limit=0 \ 27 | ${CXXFLAGS} \ 28 | -fPIC -shared \ 29 | -I /src/skia/ \ 30 | -I /src/skia/include/ \ 31 | -I /src/skia/src/core \ 32 | -I /src/skia/include/config \ 33 | -I /src/skia/include/gpu \ 34 | -I /src/skia/include/core \ 35 | -I /src/skia/include/effects \ 36 | -I /src/skia/include/pathops \ 37 | -L /src/skia/out/full -lskia -lskparagraph -lskshaper \ 38 | -Wl,-rpath,/src/skia/out/full \ 39 | -fsanitize=fuzzer-no-link \ 40 | -pthread -g \ 41 | -o libfuzzexec.so 42 | 43 | echo "[*] Building writer..." 44 | $CXX fuzz_write.cpp \ 45 | -fPIC -shared \ 46 | -I /src/skia/ \ 47 | -I /src/skia/include/ \ 48 | -I /src/skia/src/core \ 49 | -I /src/skia/include/config \ 50 | -I /src/skia/include/gpu \ 51 | -I /src/skia/include/core \ 52 | -I /src/skia/include/effects \ 53 | -I /src/skia/include/pathops \ 54 | -L /src/skia/out/full -lskia \ 55 | -Wl,-rpath,/src/skia/out/full \ 56 | -pthread -g \ 57 | -o libfuzzwrite.so 58 | 59 | echo "[*] Building graphfuzz..." 60 | $CXX -g -c /harness/graphfuzz/src/harness.cpp -DTRACE_MUTATIONS 61 | $CXX -g -c /harness/graphfuzz/src/graph.pb.cc 62 | 63 | echo "[*] Linking graphfuzz executor..." 64 | $CXX -g harness.o graph.pb.o \ 65 | -std=c++17 \ 66 | -fsanitize=fuzzer -fsanitize=address \ 67 | -lprotobuf -lfontconfig -lGL \ 68 | -lssl -lcrypto \ 69 | -L/root/clang/lib/ -lc++ \ 70 | -Wl,-rpath,/root/clang/lib/ \ 71 | -L. -lfuzzexec \ 72 | -Wl,-rpath,. \ 73 | -o fuzz_exec 74 | 75 | echo "[*] Linking graphfuzz writer..." 76 | $CXX -g harness.o graph.pb.o \ 77 | -fsanitize=fuzzer -fsanitize=address \ 78 | -lprotobuf -lfontconfig -lGL \ 79 | -lssl -lcrypto \ 80 | -L/root/clang/lib/ -lc++ \ 81 | -Wl,-rpath,/root/clang/lib/ \ 82 | -L. -lfuzzwrite \ 83 | -Wl,-rpath,. \ 84 | -o fuzz_write 85 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzSkParagraph/build_cov.sh: -------------------------------------------------------------------------------- 1 | 2 | export CXXFLAGS="\ 3 | -std=c++17 \ 4 | -fvisibility-inlines-hidden \ 5 | -stdlib=libc++ \ 6 | -fno-exceptions \ 7 | -Wnon-virtual-dtor \ 8 | -Wno-noexcept-type \ 9 | -Wno-redundant-move \ 10 | -Wno-abstract-vbase-init \ 11 | -Wno-weak-vtables \ 12 | -Wno-c++98-compat \ 13 | -Wno-c++98-compat-pedantic \ 14 | -Wno-undefined-func-template" 15 | 16 | export CXX="/root/clang/bin/clang++" 17 | 18 | echo "[*] Building proto..." 19 | (cd /harness/graphfuzz/src/ && \ 20 | protoc --cpp_out=. graph.proto) 21 | 22 | echo "[*] Building executor..." 23 | $CXX fuzz_exec.cpp \ 24 | /src/skia/tools/Resources.cpp \ 25 | /src/skia/tools/flags/CommandLineFlags.cpp \ 26 | --coverage \ 27 | -fno-inline \ 28 | -ferror-limit=0 \ 29 | ${CXXFLAGS} \ 30 | -fPIC -shared \ 31 | -I /src/skia/ \ 32 | -I /src/skia/include/ \ 33 | -I /src/skia/src/core \ 34 | -I /src/skia/include/config \ 35 | -I /src/skia/include/gpu \ 36 | -I /src/skia/include/core \ 37 | -I /src/skia/include/effects \ 38 | -I /src/skia/include/pathops \ 39 | -L /src/skia/out/cov_full -lskia -lskparagraph -lskshaper \ 40 | -Wl,-rpath,/src/skia/out/cov_full \ 41 | -fsanitize=fuzzer-no-link \ 42 | -pthread -g \ 43 | -o libfuzzexeccov.so 44 | 45 | echo "[*] Building graphfuzz..." 46 | $CXX -g -c /harness/graphfuzz/src/harness.cpp 47 | $CXX -g -c /harness/graphfuzz/src/graph.pb.cc 48 | 49 | echo "[*] Linking graphfuzz executor..." 50 | $CXX -g harness.o graph.pb.o \ 51 | -std=c++17 \ 52 | -fno-inline \ 53 | -fsanitize=fuzzer -fsanitize=address \ 54 | -lprotobuf -lfreetype -lfontconfig -lGL \ 55 | -L/root/clang/lib/ -lc++ \ 56 | -Wl,-rpath,/root/clang/lib/ \ 57 | -L. -lfuzzexeccov \ 58 | -Wl,-rpath,. \ 59 | -o fuzz_exec_cov 60 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzSkParagraph/schema.json: -------------------------------------------------------------------------------- 1 | {"types": [{"id": 1, "name": "skia::textlayout::ParagraphStyle"}, {"id": 2, "name": "skia::textlayout::StrutStyle"}, {"id": 6, "name": "skia::textlayout::ParagraphBuilderImpl"}, {"id": 7, "name": "skia::textlayout::TextStyle"}], "scopes": [{"name": "(auto) skia::textlayout::ParagraphStyle::skia::textlayout::ParagraphStyle();", "inputs": [], "outputs": [1], "context": 0}, {"name": "(auto) skia::textlayout::ParagraphStyle::void turnHintingOff();", "inputs": [1], "outputs": [1], "context": 0}, {"name": "(auto) skia::textlayout::ParagraphStyle::void setStrutStyle(skia::textlayout::StrutStyle None);", "inputs": [1, 2], "outputs": [1, 2], "context": 0}, {"name": "(auto) skia::textlayout::ParagraphStyle::void setTextDirection(skia::textlayout::TextDirection None);", "inputs": [1], "outputs": [1], "context": 1}, {"name": "(auto) skia::textlayout::ParagraphStyle::void setTextAlign(skia::textlayout::TextAlign None);", "inputs": [1], "outputs": [1], "context": 1}, {"name": "(auto) skia::textlayout::ParagraphStyle::void setMaxLines(size_t None);", "inputs": [1], "outputs": [1], "context": 8}, {"name": "(auto) skia::textlayout::ParagraphStyle::void setEllipsis({u\"\\u2026\"});", "inputs": [1], "outputs": [1], "context": 0}, {"name": "(auto) skia::textlayout::ParagraphStyle::void setHeight(SkScalar None);", "inputs": [1], "outputs": [1], "context": 4}, {"name": "(auto) skia::textlayout::ParagraphStyle::void setTextHeightBehavior(skia::textlayout::TextHeightBehavior None);", "inputs": [1], "outputs": [1], "context": 1}, {"name": "(auto) skia::textlayout::ParagraphStyle::~skia::textlayout::ParagraphStyle();", "inputs": [1], "outputs": [], "context": 0}, {"name": "(auto) skia::textlayout::StrutStyle::skia::textlayout::StrutStyle();", "inputs": [], "outputs": [2], "context": 0}, {"name": "(auto) skia::textlayout::StrutStyle::~skia::textlayout::StrutStyle();", "inputs": [2], "outputs": [], "context": 0}, {"name": "AddASCIIText", "inputs": [6], "outputs": [6], "context": 259}, {"name": "AddUnicodeText", "inputs": [6], "outputs": [6], "context": 514}, {"name": "AddZalgo", "inputs": [6], "outputs": [6], "context": 771}, {"name": "(auto) skia::textlayout::ParagraphBuilderImpl::skia::textlayout::ParagraphBuilderImpl(const skia::textlayout::ParagraphStyle & style, {sk_make_sp()});", "inputs": [1], "outputs": [6, 1], "context": 0}, {"name": "(auto) skia::textlayout::ParagraphBuilderImpl::void pushStyle(skia::textlayout::TextStyle None);", "inputs": [6, 7], "outputs": [6, 7], "context": 0}, {"name": "(auto) skia::textlayout::ParagraphBuilderImpl::void pop();", "inputs": [6], "outputs": [6], "context": 0}, {"name": "(auto) skia::textlayout::ParagraphBuilderImpl::~skia::textlayout::ParagraphBuilderImpl();", "inputs": [6], "outputs": [], "context": 0}, {"name": "void setFontFamilies_fixed", "inputs": [7], "outputs": [7], "context": 0}, {"name": "(auto) skia::textlayout::TextStyle::skia::textlayout::TextStyle();", "inputs": [], "outputs": [7], "context": 0}, {"name": "(auto) skia::textlayout::TextStyle::~skia::textlayout::TextStyle();", "inputs": [7], "outputs": [], "context": 0}]} -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/FuzzSkParagraph/schema.yaml: -------------------------------------------------------------------------------- 1 | 2 | typedef_SkScalar: 3 | headers: 4 | - SkScalar.h 5 | name: SkScalar 6 | type: typedef 7 | value: float 8 | 9 | struct_skia::textlayout::ParagraphStyle: 10 | type: struct 11 | name: skia::textlayout::ParagraphStyle 12 | default_destructor: true 13 | alloc_with_new: true 14 | headers: 15 | - modules/skparagraph/include/ParagraphStyle.h 16 | methods: 17 | - skia::textlayout::ParagraphStyle() 18 | - void turnHintingOff() 19 | - void setStrutStyle(skia::textlayout::StrutStyle) 20 | - void setTextDirection(skia::textlayout::TextDirection) 21 | - void setTextAlign(skia::textlayout::TextAlign) 22 | - void setMaxLines(size_t) 23 | - void setEllipsis({u"\u2026"}) 24 | - void setHeight(SkScalar) 25 | - void setTextHeightBehavior(skia::textlayout::TextHeightBehavior) 26 | 27 | struct_skia::textlayout::StrutStyle: 28 | type: struct 29 | name: skia::textlayout::StrutStyle 30 | default_destructor: true 31 | alloc_with_new: true 32 | headers: 33 | - modules/skparagraph/include/ParagraphStyle.h 34 | methods: 35 | - skia::textlayout::StrutStyle() 36 | 37 | enum_skia::textlayout::TextDirection: 38 | type: enum 39 | name: skia::textlayout::TextDirection 40 | values: 41 | - kRtl 42 | - kLtr 43 | 44 | enum_skia::textlayout::TextAlign: 45 | type: enum 46 | name: skia::textlayout::TextAlign 47 | values: 48 | - kLeft 49 | - kRight 50 | - kCenter 51 | - kJustify 52 | - kStart 53 | - kEnd 54 | 55 | enum_skia::textlayout::TextHeightBehavior: 56 | type: enum 57 | name: skia::textlayout::TextHeightBehavior 58 | values: 59 | - kAll 60 | - kDisableFirstAscent 61 | - kDisableLastDescent 62 | - kDisableAll 63 | 64 | struct_skia::textlayout::ParagraphBuilderImpl: 65 | type: struct 66 | name: skia::textlayout::ParagraphBuilderImpl 67 | alloc_with_new: true 68 | default_destructor: true 69 | headers: 70 | - modules/skparagraph/src/ParagraphBuilderImpl.h 71 | - ./paragraph_util.h 72 | methods: 73 | - skia::textlayout::ParagraphBuilderImpl(const skia::textlayout::ParagraphStyle& style, {sk_make_sp()}) 74 | - void pushStyle(skia::textlayout::TextStyle) 75 | - void pop() 76 | - AddASCIIText: 77 | inputs: ['skia::textlayout::ParagraphBuilderImpl'] 78 | outputs: ['skia::textlayout::ParagraphBuilderImpl'] 79 | args: ['char[255]', 'int'] 80 | exec: | 81 | unsigned int textSize = $a1 % 255; 82 | $i0->addText($a0, textSize); 83 | $o0 = $i0; 84 | - AddUnicodeText: 85 | inputs: ['skia::textlayout::ParagraphBuilderImpl'] 86 | outputs: ['skia::textlayout::ParagraphBuilderImpl'] 87 | args: ['char16_t[255]', 'int'] 88 | exec: | 89 | unsigned int textSize = $a1 % 255; 90 | $i0->addText(std::u16string($a0, textSize)); 91 | $o0 = $i0; 92 | - AddZalgo: 93 | inputs: ['skia::textlayout::ParagraphBuilderImpl'] 94 | outputs: ['skia::textlayout::ParagraphBuilderImpl'] 95 | args: ['char[255]', 'int', 'uint8_t[512]'] 96 | exec: | 97 | unsigned int textSize = $a1 % 255; 98 | Fuzz f($a2, 512); 99 | AddZalgoText($i0, $a0, textSize, &f); 100 | $o0 = $i0; 101 | 102 | 103 | struct_skia::textlayout::TextStyle: 104 | type: struct 105 | name: skia::textlayout::TextStyle 106 | default_destructor: true 107 | alloc_with_new: true 108 | headers: 109 | - modules/skparagraph/include/TextStyle.h 110 | methods: 111 | - skia::textlayout::TextStyle() 112 | - void setFontFamilies_fixed: 113 | inputs: ['skia::textlayout::TextStyle'] 114 | outputs: ['skia::textlayout::TextStyle'] 115 | exec: | 116 | $i0->setFontFamilies({SkString("Roboto")}); 117 | $o0 = $i0; 118 | -------------------------------------------------------------------------------- /experiments/skia/gf_fuzz/gen.sh: -------------------------------------------------------------------------------- 1 | 2 | 3 | fuzzers=( 4 | "./FuzzCanvas/api_image_filter" 5 | "./FuzzCanvas/api_mock_gpu_canvas" 6 | "./FuzzCanvas/api_null_canvas" 7 | "./FuzzCanvas/api_raster_n32_canvas" 8 | "./FuzzCanvas/api_svg_canvas" 9 | "./FuzzCanvas/image_filter_deserialize" 10 | "./FuzzDrawFunctions" 11 | "./FuzzPathMeasure" 12 | "./FuzzPathOp" 13 | "./FuzzPolyUtils" 14 | "./FuzzRegionOp" 15 | "./FuzzRegionSetPath" 16 | "./FuzzSkParagraph" 17 | ) 18 | 19 | for f in ${fuzzers[@]} 20 | do 21 | (cd $f && gfuzz gen cpp ./schema.yaml . --generate_dry --ignore_keywords SK_WARN_UNUSED_RESULT) 22 | done 23 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/Fuzz.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 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 | 9 | #include "fuzz/Fuzz.h" 10 | #include "fuzz/FuzzCommon.h" 11 | 12 | // UBSAN reminds us that bool can only legally hold 0 or 1. 13 | void Fuzz::next(bool* b) { 14 | uint8_t n; 15 | this->next(&n); 16 | *b = (n & 1) == 1; 17 | } 18 | 19 | void Fuzz::nextBytes(void* n, size_t size) { 20 | if ((fNextByte + size) > fBytes->size()) { 21 | sk_bzero(n, size); 22 | memcpy(n, fBytes->bytes() + fNextByte, fBytes->size() - fNextByte); 23 | fNextByte = fBytes->size(); 24 | return; 25 | } 26 | memcpy(n, fBytes->bytes() + fNextByte, size); 27 | fNextByte += size; 28 | } 29 | 30 | void Fuzz::next(SkRegion* region) { 31 | // See FuzzCommon.h 32 | FuzzNiceRegion(this, region, 10); 33 | } 34 | 35 | void Fuzz::nextRange(float* f, float min, float max) { 36 | this->next(f); 37 | if (!std::isnormal(*f) && *f != 0.0f) { 38 | // Don't deal with infinity or other strange floats. 39 | *f = max; 40 | } 41 | *f = min + std::fmod(std::abs(*f), (max - min + 1)); 42 | } 43 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/FuzzCommon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 | #ifndef FuzzCommon_DEFINED 9 | #define FuzzCommon_DEFINED 10 | 11 | #include "fuzz/Fuzz.h" 12 | #include "include/core/SkMatrix.h" 13 | #include "include/core/SkPath.h" 14 | #include "include/core/SkRRect.h" 15 | #include "include/core/SkRegion.h" 16 | 17 | // allows some float values for path points 18 | void FuzzNicePath(Fuzz* fuzz, SkPath* path, int maxOps); 19 | // allows all float values for path points 20 | void FuzzEvilPath(Fuzz* fuzz, SkPath* path, int last_verb); 21 | 22 | void FuzzNiceRRect(Fuzz* fuzz, SkRRect* rr); 23 | 24 | void FuzzNiceMatrix(Fuzz* fuzz, SkMatrix* m); 25 | 26 | void FuzzNiceRegion(Fuzz* fuzz, SkRegion* region, int maxN); 27 | 28 | #endif 29 | 30 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/FuzzEncoders.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 "fuzz/Fuzz.h" 9 | #include "include/core/SkBitmap.h" 10 | #include "include/core/SkImage.h" 11 | #include "include/core/SkImageInfo.h" 12 | #include "include/core/SkPixmap.h" 13 | #include "include/encode/SkJpegEncoder.h" 14 | #include "include/encode/SkPngEncoder.h" 15 | #include "include/encode/SkWebpEncoder.h" 16 | #include "include/utils/SkRandom.h" 17 | #include "src/core/SkOSFile.h" 18 | 19 | #include 20 | 21 | // These values were picked arbitrarily to hopefully limit the size of the 22 | // serialized SkPixmaps. 23 | constexpr int MAX_WIDTH = 512; 24 | constexpr int MAX_HEIGHT = 512; 25 | 26 | static SkBitmap make_fuzzed_bitmap(Fuzz* fuzz) { 27 | SkBitmap bm; 28 | uint32_t w, h; 29 | fuzz->nextRange(&w, 1, MAX_WIDTH); 30 | fuzz->nextRange(&h, 1, MAX_HEIGHT); 31 | if (!bm.tryAllocPixels(SkImageInfo::MakeN32Premul(w, h))) { 32 | return bm; 33 | } 34 | uint32_t n = w * h; 35 | fuzz->nextN((SkPMColor*)bm.getPixels(), n); 36 | return bm; 37 | } 38 | 39 | DEF_FUZZ(PNGEncoder, fuzz) { 40 | auto bm = make_fuzzed_bitmap(fuzz); 41 | 42 | auto opts = SkPngEncoder::Options{}; 43 | fuzz->nextRange(&opts.fZLibLevel, 0, 9); 44 | 45 | SkDynamicMemoryWStream dest; 46 | SkPngEncoder::Encode(&dest, bm.pixmap(), opts); 47 | } 48 | 49 | DEF_FUZZ(JPEGEncoder, fuzz) { 50 | auto bm = make_fuzzed_bitmap(fuzz); 51 | 52 | auto opts = SkJpegEncoder::Options{}; 53 | fuzz->nextRange(&opts.fQuality, 0, 100); 54 | 55 | SkDynamicMemoryWStream dest; 56 | (void)SkJpegEncoder::Encode(&dest, bm.pixmap(), opts); 57 | } 58 | 59 | DEF_FUZZ(WEBPEncoder, fuzz) { 60 | auto bm = make_fuzzed_bitmap(fuzz); 61 | 62 | auto opts = SkWebpEncoder::Options{}; 63 | fuzz->nextRange(&opts.fQuality, 0.0f, 100.0f); 64 | bool lossy; 65 | fuzz->next(&lossy); 66 | if (lossy) { 67 | opts.fCompression = SkWebpEncoder::Compression::kLossy; 68 | } else { 69 | opts.fCompression = SkWebpEncoder::Compression::kLossless; 70 | } 71 | 72 | SkDynamicMemoryWStream dest; 73 | (void)SkWebpEncoder::Encode(&dest, bm.pixmap(), opts); 74 | } 75 | 76 | // Not a real fuzz endpoint, but a helper to take in real, good images 77 | // and dump out a corpus for this fuzzer. 78 | DEF_FUZZ(_MakeEncoderCorpus, fuzz) { 79 | auto bytes = fuzz->fBytes; 80 | SkDebugf("bytes %d\n", bytes->size()); 81 | auto img = SkImage::MakeFromEncoded(bytes); 82 | if (nullptr == img.get()) { 83 | SkDebugf("invalid image, could not decode\n"); 84 | return; 85 | } 86 | if (img->width() > MAX_WIDTH || img->height() > MAX_HEIGHT) { 87 | SkDebugf("Too big (%d x %d)\n", img->width(), img->height()); 88 | return; 89 | } 90 | std::vector dstPixels; 91 | int rowBytes = img->width() * 4; 92 | dstPixels.resize(img->height() * rowBytes); 93 | SkPixmap pm(SkImageInfo::MakeN32Premul(img->width(), img->height()), 94 | &dstPixels.front(), rowBytes); 95 | if (!img->readPixels(nullptr, pm, 0, 0)) { 96 | SkDebugf("Could not read pixmap\n"); 97 | return; 98 | } 99 | 100 | SkString s("./encoded_corpus/enc_"); 101 | static SkRandom rand; 102 | s.appendU32(rand.nextU()); 103 | auto file = sk_fopen(s.c_str(), SkFILE_Flags::kWrite_SkFILE_Flag); 104 | if (!file) { 105 | SkDebugf("Can't initialize file\n"); 106 | return; 107 | } 108 | auto total = pm.info().bytesPerPixel() * pm.width() * pm.height(); 109 | SkDebugf("Writing %d (%d x %d) bytes\n", total, pm.width(), pm.height()); 110 | // Write out the size in two bytes since that's what the fuzzer will 111 | // read first. 112 | uint32_t w = pm.width(); 113 | sk_fwrite(&w, sizeof(uint32_t), file); 114 | uint32_t h = pm.height(); 115 | sk_fwrite(&h, sizeof(uint32_t), file); 116 | sk_fwrite(pm.addr(), total, file); 117 | sk_fclose(file); 118 | } 119 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/FuzzParsePath.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. 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 "fuzz/Fuzz.h" 9 | #include "include/core/SkString.h" 10 | #include "include/utils/SkParsePath.h" 11 | 12 | #include 13 | 14 | // Most of this is taken from random_parse_path.cpp and adapted to use the Fuzz 15 | // instead of SKRandom 16 | 17 | static const struct Legal { 18 | char fSymbol; 19 | int fScalars; 20 | } gLegal[] = { 21 | { 'M', 2 }, 22 | { 'H', 1 }, 23 | { 'V', 1 }, 24 | { 'L', 2 }, 25 | { 'Q', 4 }, 26 | { 'T', 2 }, 27 | { 'C', 6 }, 28 | { 'S', 4 }, 29 | { 'A', 4 }, 30 | { 'Z', 0 }, 31 | }; 32 | 33 | static bool gEasy = false; // set to true while debugging to suppress unusual whitespace 34 | 35 | // mostly do nothing, then bias towards spaces 36 | static const char gWhiteSpace[] = { 0, 0, 0, 0, 0, 0, 0, 0, ' ', ' ', ' ', ' ', 0x09, 0x0D, 0x0A }; 37 | 38 | static void add_white(Fuzz* fuzz, SkString* atom) { 39 | if (gEasy) { 40 | atom->append(" "); 41 | return; 42 | } 43 | // Use a uint8_t to conserve bytes. This makes our "fuzzed bytes footprint" 44 | // smaller, which leads to more efficient fuzzing. 45 | uint8_t reps; 46 | fuzz->nextRange(&reps, 0, 2); 47 | for (uint8_t rep = 0; rep < reps; ++rep) { 48 | uint8_t index; 49 | fuzz->nextRange(&index, 0, (int) SK_ARRAY_COUNT(gWhiteSpace) - 1); 50 | if (gWhiteSpace[index]) { 51 | atom->append(&gWhiteSpace[index], 1); 52 | } 53 | } 54 | } 55 | 56 | static void add_some_white(Fuzz* fuzz, SkString* atom) { 57 | for(int i = 0; i < 10; i++) { 58 | add_white(fuzz, atom); 59 | } 60 | } 61 | 62 | static void add_comma(Fuzz* fuzz, SkString* atom) { 63 | if (gEasy) { 64 | atom->append(","); 65 | return; 66 | } 67 | add_white(fuzz, atom); 68 | bool b; 69 | fuzz->next(&b); 70 | if (b) { 71 | atom->append(","); 72 | } 73 | add_some_white(fuzz, atom); 74 | } 75 | 76 | SkString MakeRandomParsePathPiece(Fuzz* fuzz) { 77 | SkString atom; 78 | uint8_t index; 79 | fuzz->nextRange(&index, 0, (int) SK_ARRAY_COUNT(gLegal) - 1); 80 | const Legal& legal = gLegal[index]; 81 | gEasy ? atom.append("\n") : add_white(fuzz, &atom); 82 | bool b; 83 | fuzz->next(&b); 84 | char symbol = legal.fSymbol | (b ? 0x20 : 0); 85 | atom.append(&symbol, 1); 86 | uint8_t reps; 87 | fuzz->nextRange(&reps, 1, 3); 88 | for (int rep = 0; rep < reps; ++rep) { 89 | for (int index = 0; index < legal.fScalars; ++index) { 90 | SkScalar coord; 91 | fuzz->nextRange(&coord, 0.0f, 100.0f); 92 | add_white(fuzz, &atom); 93 | atom.appendScalar(coord); 94 | if (rep < reps - 1 && index < legal.fScalars - 1) { 95 | add_comma(fuzz, &atom); 96 | } else { 97 | add_some_white(fuzz, &atom); 98 | } 99 | if ('A' == legal.fSymbol && 1 == index) { 100 | SkScalar s; 101 | fuzz->nextRange(&s, -720.0f, 720.0f); 102 | atom.appendScalar(s); 103 | add_comma(fuzz, &atom); 104 | fuzz->next(&b); 105 | atom.appendU32(b); 106 | add_comma(fuzz, &atom); 107 | fuzz->next(&b); 108 | atom.appendU32(b); 109 | add_comma(fuzz, &atom); 110 | } 111 | } 112 | } 113 | return atom; 114 | } 115 | 116 | DEF_FUZZ(ParsePath, fuzz) { 117 | SkPath path; 118 | SkString spec; 119 | uint8_t count; 120 | fuzz->nextRange(&count, 0, 40); 121 | for (uint8_t i = 0; i < count; ++i) { 122 | spec.append(MakeRandomParsePathPiece(fuzz)); 123 | } 124 | SkDebugf("SkParsePath::FromSVGString(%s, &path);\n",spec.c_str()); 125 | if (!SkParsePath::FromSVGString(spec.c_str(), &path)){ 126 | SkDebugf("Could not decode path\n"); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/FuzzPath.cpp: -------------------------------------------------------------------------------- 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 | // To use this fuzzer follow the libfuzzer directions in 9 | // site/dev/testing/fuzz.md. 10 | 11 | #include "include/core/SkPath.h" 12 | 13 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* buf, size_t size) { 14 | SkPath path; 15 | (void)path.readFromMemory(buf, size); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/FuzzPathMeasure.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google Inc. 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 | #ifdef FUZZ_DRY 9 | #define FUZZ_ENDPOINT(T) 0; 10 | #else 11 | #define FUZZ_ENDPOINT(T) T 12 | #endif 13 | 14 | #include "fuzz/Fuzz.h" 15 | #include "fuzz/FuzzCommon.h" 16 | #include "include/core/SkPathMeasure.h" 17 | 18 | void inline ignoreResult(bool ) {} 19 | 20 | DEF_FUZZ(PathMeasure, fuzz) { 21 | uint8_t bits; 22 | fuzz->next(&bits); 23 | SkScalar distance[6]; 24 | for (auto index = 0; index < 6; ++index) { 25 | fuzz->next(&distance[index]); 26 | } 27 | SkPath path; 28 | FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb); 29 | FUZZ_ENDPOINT(SkRect bounds = path.getBounds(); 30 | SkScalar maxDim = std::max(bounds.width(), bounds.height()); 31 | if (maxDim > 1000000) { 32 | return; 33 | } 34 | SkScalar resScale = maxDim / 1000; 35 | SkPathMeasure measure(path, bits & 1, resScale);) 36 | SkPoint position; 37 | SkVector tangent; 38 | FUZZ_ENDPOINT(ignoreResult(measure.getPosTan(distance[0], &position, &tangent));) 39 | SkPath dst; 40 | FUZZ_ENDPOINT(ignoreResult(measure.getSegment(distance[1], distance[2], &dst, (bits >> 1) & 1)); 41 | ignoreResult(measure.nextContour()); 42 | ignoreResult(measure.getPosTan(distance[3], &position, &tangent)); 43 | ignoreResult(measure.getSegment(distance[4], distance[5], &dst, (bits >> 2) & 1));) 44 | } 45 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/FuzzPolyUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 | #ifdef FUZZ_DRY 9 | #define FUZZ_ENDPOINT(T) 0; 10 | #else 11 | #define FUZZ_ENDPOINT(T) T 12 | #endif 13 | 14 | #include "fuzz/Fuzz.h" 15 | 16 | #include "include/private/SkTemplates.h" 17 | #include "src/utils/SkPolyUtils.h" 18 | 19 | void inline ignoreResult(bool ) {} 20 | 21 | DEF_FUZZ(PolyUtils, fuzz) { 22 | int count; 23 | fuzz->nextRange(&count, 0, 512); 24 | SkAutoSTMalloc<64, SkPoint> polygon(count); 25 | for (int index = 0; index < count; ++index) { 26 | fuzz->next(&polygon[index].fX, &polygon[index].fY); 27 | } 28 | SkRect bounds; 29 | FUZZ_ENDPOINT(bounds.setBoundsCheck(polygon, count);) 30 | 31 | FUZZ_ENDPOINT(ignoreResult(SkGetPolygonWinding(polygon, count)); 32 | ignoreResult(SkIsConvexPolygon(polygon, count)); 33 | ignoreResult(SkIsSimplePolygon(polygon, count));) 34 | 35 | SkScalar inset; 36 | fuzz->next(&inset); 37 | SkTDArray output; 38 | FUZZ_ENDPOINT(ignoreResult(SkInsetConvexPolygon(polygon, count, inset, &output));) 39 | 40 | SkScalar offset; 41 | fuzz->next(&offset); 42 | FUZZ_ENDPOINT(ignoreResult(SkOffsetSimplePolygon(polygon, count, bounds, offset, &output));) 43 | 44 | SkAutoSTMalloc<64, uint16_t> indexMap(count); 45 | for (int index = 0; index < count; ++index) { 46 | fuzz->next(&indexMap[index]); 47 | } 48 | SkTDArray outputIndices; 49 | FUZZ_ENDPOINT(ignoreResult(SkTriangulateSimplePolygon(polygon, indexMap, count, &outputIndices));) 50 | } 51 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/FuzzRRect.cpp: -------------------------------------------------------------------------------- 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 | // To use this fuzzer follow the libfuzzer directions in 9 | // site/dev/testing/fuzz.md. 10 | 11 | #ifdef FUZZ_DRY 12 | #define FUZZ_ENDPOINT(T) 0; 13 | #else 14 | #define FUZZ_ENDPOINT(T) T 15 | #endif 16 | 17 | #include "include/core/SkRRect.h" 18 | 19 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* buf, size_t size) { 20 | SkRRect rrect; 21 | FUZZ_ENDPOINT((void)rrect.readFromMemory(buf, size);) 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/FuzzRegionOp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google Inc. 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 | #ifdef FUZZ_DRY 9 | #define FUZZ_ENDPOINT(T) 0; 10 | #else 11 | #define FUZZ_ENDPOINT(T) T 12 | #endif 13 | 14 | #include "fuzz/Fuzz.h" 15 | #include "fuzz/FuzzCommon.h" 16 | 17 | DEF_FUZZ(RegionOp, fuzz) { // `fuzz -t api -n RegionOp` 18 | SkRegion region; 19 | // FuzzNiceRegion generates a random region by joining a random amount of regions 20 | // together. This fuzzer simply targets that directly. 300 was picked arbitrarily as 21 | // a number over 2^8. 22 | FuzzNiceRegion(fuzz, ®ion, 300); 23 | // Do a computation to make sure region is not optimized out. 24 | FUZZ_ENDPOINT(region.computeRegionComplexity();) 25 | } 26 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/FuzzTriangulation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 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 "fuzz/Fuzz.h" 9 | #include "fuzz/FuzzCommon.h" 10 | #include "include/core/SkPath.h" 11 | #include "src/gpu/GrEagerVertexAllocator.h" 12 | #include "src/gpu/GrTriangulator.h" 13 | #include "src/gpu/geometry/GrPathUtils.h" 14 | 15 | DEF_FUZZ(Triangulation, fuzz) { 16 | 17 | SkPath path; 18 | FuzzEvilPath(fuzz, &path, SkPath::Verb::kDone_Verb); 19 | 20 | SkScalar tol = GrPathUtils::scaleToleranceToSrc(GrPathUtils::kDefaultTolerance, 21 | SkMatrix::I(), path.getBounds()); 22 | 23 | 24 | // TODO(robertphillips): messing w/ the clipBounds might be another axis to fuzz. 25 | // afaict it only affects inverse filled paths. 26 | SkRect clipBounds = path.getBounds(); 27 | 28 | GrCpuVertexAllocator allocator; 29 | bool isLinear; 30 | 31 | GrTriangulator::PathToTriangles(path, tol, clipBounds, &allocator, &isLinear); 32 | allocator.detachVertexData(); // normally handled by the triangulating path renderer. 33 | } 34 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/README.md: -------------------------------------------------------------------------------- 1 | We fuzz Skia using oss-fuzz, which in turn uses fuzzing engines such as libfuzzer, afl-fuzz, 2 | hong-fuzz and others. 3 | 4 | We define a `fuzzer` to be a targeted bit of code that takes a randomized input and executes code 5 | in a specific area. For example, we have a codec fuzzer which takes a mutated png/jpeg or similar 6 | file and attempts to turn it into an `SkImage`. We also have a canvas fuzzer which takes in a random 7 | set of bytes and turns them into calls on `SkCanvas`. 8 | 9 | See [../site/dev/testing/fuzz.md] for more information on building and running fuzzers. 10 | 11 | See also: 12 | - [Creating a binary fuzzer](https://docs.google.com/document/d/1QDX0o8yDdmhbjoudNsXc66iuRXRF5XNNqGnzDzX7c2I/edit) 13 | - [Creating an API fuzzer](https://docs.google.com/document/d/1e3ikXO7SwoBsbsi1MF06vydXRlXvYalVORaiUuOXk2Y/edit) -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/coverage: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2017 Google Inc. 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 | if [ -z "$1" ]; then 8 | cat <<-EOM 9 | Usage: 10 | $0 [afl-out-loc] 11 | 12 | Run something like this: 13 | $0 ~/afl-out 14 | where afl-out is the directory containing all the output of the afl-fuzzers. 15 | You can typically ssh into skia-fuzzer-be-1 and skia-fuzzer-be-2 and run 16 | tar -czf afl-out.tar.gz /mnt/ssd0/fuzzes/afl-out/*/fuzzer0/queue 17 | and extract it locally to get the directories needed to assess coverage. 18 | 19 | EOM 20 | exit 1 21 | fi 22 | 23 | set -x 24 | set -e 25 | 26 | cd "$(dirname "$0")/.." 27 | 28 | EXECUTABLE="fuzz" 29 | 30 | DIR="$(mktemp -d "${TMPDIR:-/tmp}/skia_coverage_XXXXXXXXXX")" 31 | BUILD=out/coverage 32 | 33 | # Build $EXECUTABLE 34 | bin/sync 35 | bin/fetch-gn 36 | 37 | rm -rf $BUILD 38 | 39 | #TODO: make this work with Clang. 40 | ARGS='cc="gcc" cxx="g++" extra_cflags=["--coverage"] extra_ldflags=["--coverage"]' 41 | gn gen --args="$ARGS" "$BUILD" 42 | 43 | ninja -C "$BUILD" "$EXECUTABLE" 44 | 45 | GCOV="$(realpath tools/gcov_shim)" 46 | 47 | # Generate a zero-baseline so files not covered by $EXECUTABLE $@ will 48 | # still show up in the report. This reads the .gcno files that are 49 | # created at compile time. 50 | lcov -q --gcov-tool="$GCOV" -c -b "$BUILD" -d "$BUILD" -o "$DIR"/baseline -i 51 | 52 | # Running the binary generates the real coverage information, the .gcda files. 53 | QUEUES=("$1/api_parse_path/fuzzer0/queue/*" "$1/color_deserialize/fuzzer0/queue/*" "$1/skcodec_scale/fuzzer0/queue/*" "$1/skcodec_mode/fuzzer0/queue/*" "$1/api_draw_functions/fuzzer0/queue/*" "$1/api_gradient/fuzzer0/queue/*" "$1/api_image_filter/fuzzer0/queue/*" "$1/api_pathop/fuzzer0/queue/*" "$1/sksl2glsl/fuzzer0/queue/*" "$1/null_canvas/fuzzer0/queue/*" "$1/pdf_canvas/fuzzer0/queue/*" "$1/n32_canvas/fuzzer0/queue/*") 54 | 55 | ARGS=("-n ParsePath" "-t color_deserialize" "-t image_scale" "-t image_mode" "-n DrawFunctions" "-n Gradients" "-n SerializedImageFilter" "-n Pathop" "-t sksl2glsl" "-n NullCanvas" "-n PDFCanvas" "-n RasterN32Canvas") 56 | 57 | # We can't simply pass the directories to the fuzzers because some of the fuzzes will 58 | # crash or assert, which would kill the call to fuzz prematurely. Instead we run them 59 | # individually using the loops below. 60 | for i in `seq ${#QUEUES[@]}` 61 | do 62 | FILES=${QUEUES[i]} 63 | for f in $FILES 64 | do 65 | # Executing the fuzzes sequentially would take a very long time. So, we run them 66 | # in the background, making sure we don't go crazy and execute them too fast or 67 | # that they execute for a long time. 68 | timeout 10 $BUILD/$EXECUTABLE ${ARGS[i]} -b $f & 69 | sleep .005s 70 | done 71 | done 72 | 73 | sleep 10s 74 | 75 | echo "done running the fuzzes -- generating report" 76 | 77 | lcov -q --gcov-tool="$GCOV" -c -b "$BUILD" -d "$BUILD" -o "$DIR"/coverage 78 | 79 | lcov -q -a "$DIR"/baseline -a "$DIR"/coverage -o "$DIR"/merged 80 | 81 | genhtml -q "$DIR"/merged --legend -o "$DIR"/coverage_report --ignore-errors source 82 | 83 | xdg-open "$DIR"/coverage_report/index.html 84 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzAPICreateDDL.cpp: -------------------------------------------------------------------------------- 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 "fuzz/Fuzz.h" 9 | #include "src/core/SkFontMgrPriv.h" 10 | #include "tools/fonts/TestFontMgr.h" 11 | 12 | void fuzz_CreateDDL(Fuzz* f); 13 | 14 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 15 | gSkFontMgr_DefaultFactory = &ToolUtils::MakePortableFontMgr; 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_CreateDDL(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzAPIImageFilter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 "fuzz/Fuzz.h" 9 | 10 | void fuzz_ImageFilter(Fuzz* f); 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 13 | if (size > 4000) { 14 | return 0; 15 | } 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_ImageFilter(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzAPISVGCanvas.cpp: -------------------------------------------------------------------------------- 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 "fuzz/Fuzz.h" 9 | #include "src/core/SkFontMgrPriv.h" 10 | #include "tools/fonts/TestFontMgr.h" 11 | 12 | void fuzz_SVGCanvas(Fuzz* f); 13 | 14 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 15 | gSkFontMgr_DefaultFactory = &ToolUtils::MakePortableFontMgr; 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_SVGCanvas(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzAndroidCodec.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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/codec/SkAndroidCodec.h" 9 | #include "include/core/SkBitmap.h" 10 | #include "include/core/SkCanvas.h" 11 | #include "include/core/SkData.h" 12 | #include "include/core/SkSurface.h" 13 | 14 | #include "fuzz/Fuzz.h" 15 | 16 | bool FuzzAndroidCodec(sk_sp bytes, uint8_t sampleSize) { 17 | auto codec = SkAndroidCodec::MakeFromData(bytes); 18 | if (!codec) { 19 | return false; 20 | } 21 | 22 | auto size = codec->getSampledDimensions(sampleSize); 23 | auto info = SkImageInfo::MakeN32Premul(size); 24 | SkBitmap bm; 25 | if (!bm.tryAllocPixels(info)) { 26 | // May fail in memory-constrained fuzzing environments 27 | return false; 28 | } 29 | 30 | SkAndroidCodec::AndroidOptions options; 31 | options.fSampleSize = sampleSize; 32 | 33 | auto result = codec->getAndroidPixels(bm.info(), bm.getPixels(), bm.rowBytes(), &options); 34 | switch (result) { 35 | case SkCodec::kSuccess: 36 | case SkCodec::kIncompleteInput: 37 | case SkCodec::kErrorInInput: 38 | break; 39 | default: 40 | return false; 41 | } 42 | 43 | auto surface = SkSurface::MakeRasterN32Premul(size.width(), size.height()); 44 | if (!surface) { 45 | // May return nullptr in memory-constrained fuzzing environments 46 | return false; 47 | } 48 | 49 | surface->getCanvas()->drawImage(bm.asImage(), 0, 0); 50 | return true; 51 | } 52 | 53 | #if defined(SK_BUILD_FOR_LIBFUZZER) 54 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 55 | if (size > 10240) { 56 | return 0; 57 | } 58 | auto bytes = SkData::MakeWithoutCopy(data, size); 59 | Fuzz fuzz(bytes); 60 | uint8_t sampleSize; 61 | fuzz.nextRange(&sampleSize, 1, 64); 62 | bytes = SkData::MakeSubset(bytes.get(), 1, size - 1); 63 | FuzzAndroidCodec(bytes, sampleSize); 64 | return 0; 65 | } 66 | #endif 67 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzAnimatedImage.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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/android/SkAnimatedImage.h" 9 | #include "include/codec/SkAndroidCodec.h" 10 | #include "include/core/SkCanvas.h" 11 | #include "include/core/SkData.h" 12 | #include "include/core/SkSurface.h" 13 | 14 | bool FuzzAnimatedImage(sk_sp bytes) { 15 | auto codec = SkAndroidCodec::MakeFromData(bytes); 16 | if (nullptr == codec) { 17 | return false; 18 | } 19 | auto aImg = SkAnimatedImage::Make(std::move(codec)); 20 | if (nullptr == aImg) { 21 | return false; 22 | } 23 | 24 | auto s = SkSurface::MakeRasterN32Premul(128, 128); 25 | if (!s) { 26 | // May return nullptr in memory-constrained fuzzing environments 27 | return false; 28 | } 29 | 30 | int escape = 0; 31 | while (!aImg->isFinished() && escape < 100) { 32 | aImg->draw(s->getCanvas()); 33 | escape++; 34 | aImg->decodeNextFrame(); 35 | } 36 | return true; 37 | } 38 | 39 | #if defined(SK_BUILD_FOR_LIBFUZZER) 40 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 41 | if (size > 10240) { 42 | return 0; 43 | } 44 | auto bytes = SkData::MakeWithoutCopy(data, size); 45 | FuzzAnimatedImage(bytes); 46 | return 0; 47 | } 48 | #endif 49 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzDDLThreading.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 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 "fuzz/Fuzz.h" 9 | 10 | void fuzz_DDLThreadingGL(Fuzz* f); 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 13 | if (size > 4000) { 14 | return 0; 15 | } 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_DDLThreadingGL(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzDrawFunctions.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 "fuzz/Fuzz.h" 9 | 10 | void fuzz_DrawFunctions(Fuzz* f); 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 13 | if (size > 4000) { 14 | return 0; 15 | } 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_DrawFunctions(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzGradients.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 "fuzz/Fuzz.h" 9 | 10 | void fuzz_Gradients(Fuzz* f); 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 13 | if (size > 4000) { 14 | return 0; 15 | } 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_Gradients(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzImage.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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/SkData.h" 10 | #include "include/core/SkImage.h" 11 | #include "include/core/SkPaint.h" 12 | #include "include/core/SkSurface.h" 13 | 14 | bool FuzzImageDecode(sk_sp bytes) { 15 | auto img = SkImage::MakeFromEncoded(bytes); 16 | if (nullptr == img.get()) { 17 | return false; 18 | } 19 | 20 | auto s = SkSurface::MakeRasterN32Premul(128, 128); 21 | if (!s) { 22 | // May return nullptr in memory-constrained fuzzing environments 23 | return false; 24 | } 25 | 26 | s->getCanvas()->drawImage(img, 0, 0); 27 | return true; 28 | } 29 | 30 | // TODO(kjlubick): remove IS_FUZZING... after https://crrev.com/c/2410304 lands 31 | #if defined(SK_BUILD_FOR_LIBFUZZER) || defined(IS_FUZZING_WITH_LIBFUZZER) 32 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 33 | if (size > 10240) { 34 | return 0; 35 | } 36 | auto bytes = SkData::MakeWithoutCopy(data, size); 37 | FuzzImageDecode(bytes); 38 | return 0; 39 | } 40 | #endif 41 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzImageFilterDeserialize.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google Inc. 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 | 9 | #include "include/core/SkBitmap.h" 10 | #include "include/core/SkCanvas.h" 11 | #include "include/core/SkData.h" 12 | #include "include/core/SkImage.h" 13 | #include "include/core/SkImageFilter.h" 14 | #include "include/core/SkPaint.h" 15 | #include "src/core/SkFontMgrPriv.h" 16 | #include "tools/fonts/TestFontMgr.h" 17 | 18 | void FuzzImageFilterDeserialize(sk_sp bytes) { 19 | const int BitmapSize = 24; 20 | SkBitmap bitmap; 21 | bitmap.allocN32Pixels(BitmapSize, BitmapSize); 22 | SkCanvas canvas(bitmap); 23 | canvas.clear(0x00000000); 24 | 25 | auto flattenable = SkImageFilter::Deserialize(bytes->data(), bytes->size()); 26 | 27 | if (flattenable != nullptr) { 28 | // Let's see if using the filters can cause any trouble... 29 | SkPaint paint; 30 | paint.setImageFilter(flattenable); 31 | canvas.save(); 32 | canvas.clipIRect(bitmap.bounds()); 33 | 34 | // This call shouldn't crash or cause ASAN to flag any memory issues 35 | // If nothing bad happens within this call, everything is fine 36 | canvas.drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint); 37 | 38 | canvas.restore(); 39 | } 40 | } 41 | 42 | // TODO(kjlubick): remove IS_FUZZING... after https://crrev.com/c/2410304 lands 43 | #if defined(SK_BUILD_FOR_LIBFUZZER) || defined(IS_FUZZING_WITH_LIBFUZZER) 44 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 45 | if (size > 10024) { 46 | return 0; 47 | } 48 | gSkFontMgr_DefaultFactory = &ToolUtils::MakePortableFontMgr; 49 | auto bytes = SkData::MakeWithoutCopy(data, size); 50 | FuzzImageFilterDeserialize(bytes); 51 | return 0; 52 | } 53 | #endif 54 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzIncrementalImage.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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/codec/SkCodec.h" 9 | #include "include/core/SkBitmap.h" 10 | #include "include/core/SkData.h" 11 | 12 | bool FuzzIncrementalImageDecode(sk_sp bytes) { 13 | auto codec = SkCodec::MakeFromData(bytes); 14 | if (!codec) { 15 | return false; 16 | } 17 | 18 | SkBitmap bm; 19 | if (!bm.tryAllocPixels(codec->getInfo())) { 20 | // May fail in memory-constrained fuzzing environments 21 | return false; 22 | } 23 | 24 | auto result = codec->startIncrementalDecode(bm.info(), bm.getPixels(), bm.rowBytes()); 25 | if (result != SkCodec::kSuccess) { 26 | return false; 27 | } 28 | 29 | // Deliberately uninitialized to verify that incrementalDecode initializes it when it 30 | // returns kIncompleteInput or kErrorInInput. 31 | int rowsDecoded; 32 | result = codec->incrementalDecode(&rowsDecoded); 33 | switch (result) { 34 | case SkCodec::kIncompleteInput: 35 | case SkCodec::kErrorInInput: 36 | if (rowsDecoded < bm.height()) { 37 | void* dst = SkTAddOffset(bm.getPixels(), rowsDecoded * bm.rowBytes()); 38 | sk_bzero(dst, (bm.height() - rowsDecoded) * bm.rowBytes()); 39 | } 40 | return true; // decoded a partial image 41 | case SkCodec::kSuccess: 42 | return true; 43 | default: 44 | return false; 45 | } 46 | } 47 | 48 | // TODO(kjlubick): remove IS_FUZZING... after https://crrev.com/c/2410304 lands 49 | #if defined(SK_BUILD_FOR_LIBFUZZER) || defined(IS_FUZZING_WITH_LIBFUZZER) 50 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 51 | if (size > 10240) { 52 | return 0; 53 | } 54 | auto bytes = SkData::MakeWithoutCopy(data, size); 55 | FuzzIncrementalImageDecode(bytes); 56 | return 0; 57 | } 58 | #endif 59 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzJPEGEncoder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 "fuzz/Fuzz.h" 9 | 10 | void fuzz_JPEGEncoder(Fuzz* f); 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 13 | if (size > 262150) { 14 | return 0; 15 | } 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_JPEGEncoder(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzJSON.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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/SkData.h" 9 | #include "include/core/SkStream.h" 10 | #include "src/utils/SkJSON.h" 11 | 12 | void FuzzJSON(sk_sp bytes) { 13 | skjson::DOM dom(static_cast(bytes->data()), bytes->size()); 14 | SkDynamicMemoryWStream wstream; 15 | dom.write(&wstream); 16 | } 17 | 18 | // TODO(kjlubick): remove IS_FUZZING... after https://crrev.com/c/2410304 lands 19 | #if defined(SK_BUILD_FOR_LIBFUZZER) || defined(IS_FUZZING_WITH_LIBFUZZER) 20 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 21 | auto bytes = SkData::MakeWithoutCopy(data, size); 22 | FuzzJSON(bytes); 23 | return 0; 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzMockGPUCanvas.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 "fuzz/Fuzz.h" 9 | #include "src/core/SkFontMgrPriv.h" 10 | #include "tools/fonts/TestFontMgr.h" 11 | 12 | void fuzz_MockGPUCanvas(Fuzz* f); 13 | 14 | extern "C" { 15 | 16 | // Set default LSAN options. 17 | // GraphFuzz-note: This breaks when instrumenting with ASAN and gcov so we disable it. 18 | // const char *__lsan_default_options() { 19 | // // Don't print the list of LSAN suppressions on every execution. 20 | // return "print_suppressions=0"; 21 | // } 22 | 23 | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 24 | if (size > 4000) { 25 | return 0; 26 | } 27 | gSkFontMgr_DefaultFactory = &ToolUtils::MakePortableFontMgr; 28 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 29 | fuzz_MockGPUCanvas(&fuzz); 30 | return 0; 31 | } 32 | } // extern "C" 33 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzNullCanvas.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 "fuzz/Fuzz.h" 9 | #include "src/core/SkFontMgrPriv.h" 10 | #include "tools/fonts/TestFontMgr.h" 11 | 12 | void fuzz_NullCanvas(Fuzz* f); 13 | 14 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 15 | if (size > 4000) { 16 | return 0; 17 | } 18 | gSkFontMgr_DefaultFactory = &ToolUtils::MakePortableFontMgr; 19 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 20 | fuzz_NullCanvas(&fuzz); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzPNGEncoder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 "fuzz/Fuzz.h" 9 | 10 | void fuzz_PNGEncoder(Fuzz* f); 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 13 | if (size > 262150) { 14 | return 0; 15 | } 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_PNGEncoder(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzPathDeserialize.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google Inc. 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/SkPath.h" 11 | #include "include/core/SkSurface.h" 12 | #include "src/core/SkReadBuffer.h" 13 | 14 | void FuzzPathDeserialize(SkReadBuffer& buf) { 15 | SkPath path; 16 | buf.readPath(&path); 17 | if (!buf.isValid()) { 18 | return; 19 | } 20 | 21 | auto s = SkSurface::MakeRasterN32Premul(128, 128); 22 | if (!s) { 23 | // May return nullptr in memory-constrained fuzzing environments 24 | return; 25 | } 26 | s->getCanvas()->drawPath(path, SkPaint()); 27 | } 28 | 29 | // TODO(kjlubick): remove IS_FUZZING... after https://crrev.com/c/2410304 lands 30 | #if defined(SK_BUILD_FOR_LIBFUZZER) || defined(IS_FUZZING_WITH_LIBFUZZER) 31 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 32 | if (size < 4 || size > 2000) { 33 | return 0; 34 | } 35 | uint32_t packed; 36 | memcpy(&packed, data, 4); 37 | unsigned version = packed & 0xFF; 38 | if (version != 4) { 39 | // Chrome only will produce version 4, so guide the fuzzer to 40 | // only focus on those branches. 41 | return 0; 42 | } 43 | SkReadBuffer buf(data, size); 44 | FuzzPathDeserialize(buf); 45 | return 0; 46 | } 47 | #endif 48 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzPathMeasure.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 "fuzz/Fuzz.h" 9 | 10 | void fuzz_PathMeasure(Fuzz* f); 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 13 | if (size > 4000) { 14 | return 0; 15 | } 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_PathMeasure(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzPathop.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 "fuzz/Fuzz.h" 9 | 10 | void fuzz_Pathop(Fuzz* f); 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 13 | if (size > 4000) { 14 | return 0; 15 | } 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_Pathop(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzPolyUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 "fuzz/Fuzz.h" 9 | 10 | void fuzz_PolyUtils(Fuzz* f); 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 13 | if (size > 4000) { 14 | return 0; 15 | } 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_PolyUtils(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzRasterN32Canvas.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 "fuzz/Fuzz.h" 9 | #include "src/core/SkFontMgrPriv.h" 10 | #include "tools/fonts/TestFontMgr.h" 11 | 12 | void fuzz_RasterN32Canvas(Fuzz* f); 13 | 14 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 15 | if (size > 4000) { 16 | return 0; 17 | } 18 | gSkFontMgr_DefaultFactory = &ToolUtils::MakePortableFontMgr; 19 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 20 | fuzz_RasterN32Canvas(&fuzz); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzRegionDeserialize.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google Inc. 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 | 9 | #include "include/core/SkCanvas.h" 10 | #include "include/core/SkPaint.h" 11 | #include "include/core/SkSurface.h" 12 | #include "src/core/SkRegionPriv.h" 13 | 14 | bool FuzzRegionDeserialize(sk_sp bytes) { 15 | SkRegion region; 16 | if (!region.readFromMemory(bytes->data(), bytes->size())) { 17 | return false; 18 | } 19 | region.computeRegionComplexity(); 20 | region.isComplex(); 21 | SkRegion r2; 22 | if (region == r2) { 23 | region.contains(0,0); 24 | } else { 25 | region.contains(1,1); 26 | } 27 | auto s = SkSurface::MakeRasterN32Premul(128, 128); 28 | if (!s) { 29 | // May return nullptr in memory-constrained fuzzing environments 30 | return false; 31 | } 32 | s->getCanvas()->drawRegion(region, SkPaint()); 33 | SkDEBUGCODE(SkRegionPriv::Validate(region)); 34 | return true; 35 | } 36 | 37 | // TODO(kjlubick): remove IS_FUZZING... after https://crrev.com/c/2410304 lands 38 | #if defined(SK_BUILD_FOR_LIBFUZZER) || defined(IS_FUZZING_WITH_LIBFUZZER) 39 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 40 | if (size > 512) { 41 | return 0; 42 | } 43 | auto bytes = SkData::MakeWithoutCopy(data, size); 44 | FuzzRegionDeserialize(bytes); 45 | return 0; 46 | } 47 | #endif 48 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzRegionOp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 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 "fuzz/Fuzz.h" 9 | 10 | void fuzz_RegionOp(Fuzz* f); 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 13 | if (size > 8000) { 14 | return 0; 15 | } 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_RegionOp(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzRegionSetPath.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google Inc. 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 "fuzz/Fuzz.h" 9 | #include "fuzz/FuzzCommon.h" 10 | #include "include/core/SkData.h" 11 | #include "include/core/SkPath.h" 12 | #include "include/core/SkRegion.h" 13 | 14 | 15 | void FuzzRegionSetPath(Fuzz* fuzz) { 16 | SkPath p; 17 | FuzzNicePath(fuzz, &p, 1000); 18 | SkRegion r1; 19 | bool initR1; 20 | fuzz->next(&initR1); 21 | if (initR1) { 22 | fuzz->next(&r1); 23 | } 24 | SkRegion r2; 25 | fuzz->next(&r2); 26 | 27 | r1.setPath(p, r2); 28 | 29 | // Do some follow on computations to make sure region is well-formed. 30 | r1.computeRegionComplexity(); 31 | r1.isComplex(); 32 | if (r1 == r2) { 33 | r1.contains(0,0); 34 | } else { 35 | r1.contains(1,1); 36 | } 37 | } 38 | 39 | // TODO(kjlubick): remove IS_FUZZING... after https://crrev.com/c/2410304 lands 40 | #if defined(SK_BUILD_FOR_LIBFUZZER) || defined(IS_FUZZING_WITH_LIBFUZZER) 41 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 42 | if (size > 512) { 43 | return 0; 44 | } 45 | sk_sp bytes(SkData::MakeWithoutCopy(data, size)); 46 | Fuzz fuzz(bytes); 47 | FuzzRegionSetPath(&fuzz); 48 | return 0; 49 | } 50 | #endif 51 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzSKP.cpp: -------------------------------------------------------------------------------- 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/SkData.h" 10 | #include "include/core/SkPicture.h" 11 | #include "include/core/SkStream.h" 12 | #include "include/core/SkSurface.h" 13 | 14 | constexpr static SkISize kCanvasSize= {128, 160}; 15 | 16 | void FuzzSKP(sk_sp bytes) { 17 | sk_sp pic = SkPicture::MakeFromData(bytes->data(), bytes->size()); 18 | if (!pic) { 19 | SkDebugf("[terminated] Couldn't decode as a picture.\n"); 20 | return; 21 | } 22 | sk_sp surface = SkSurface::MakeRasterN32Premul(kCanvasSize.width(), 23 | kCanvasSize.height()); 24 | surface->getCanvas()->drawPicture(pic); 25 | pic->approximateBytesUsed(); 26 | pic->approximateOpCount(); 27 | return; 28 | } 29 | 30 | #if defined(SK_BUILD_FOR_LIBFUZZER) 31 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 32 | auto bytes = SkData::MakeWithoutCopy(data, size); 33 | FuzzSKP(bytes); 34 | return 0; 35 | } 36 | #endif 37 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzSKSL2GLSL.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 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 "src/gpu/GrShaderCaps.h" 9 | #include "src/sksl/SkSLCompiler.h" 10 | 11 | #include "fuzz/Fuzz.h" 12 | 13 | bool FuzzSKSL2GLSL(sk_sp bytes) { 14 | sk_sp caps = SkSL::ShaderCapsFactory::Default(); 15 | SkSL::Compiler compiler(caps.get()); 16 | SkSL::String output; 17 | SkSL::Program::Settings settings; 18 | std::unique_ptr program = compiler.convertProgram( 19 | SkSL::ProgramKind::kFragment, 20 | SkSL::String((const char*) bytes->data(), 21 | bytes->size()), 22 | settings); 23 | if (!program || !compiler.toGLSL(*program, &output)) { 24 | return false; 25 | } 26 | return true; 27 | } 28 | 29 | #if defined(SK_BUILD_FOR_LIBFUZZER) 30 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 31 | if (size > 3000) { 32 | return 0; 33 | } 34 | auto bytes = SkData::MakeWithoutCopy(data, size); 35 | FuzzSKSL2GLSL(bytes); 36 | return 0; 37 | } 38 | #endif 39 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzSKSL2Metal.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 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 "src/gpu/GrShaderCaps.h" 9 | #include "src/sksl/SkSLCompiler.h" 10 | 11 | #include "fuzz/Fuzz.h" 12 | 13 | bool FuzzSKSL2Metal(sk_sp bytes) { 14 | sk_sp caps = SkSL::ShaderCapsFactory::Default(); 15 | SkSL::Compiler compiler(caps.get()); 16 | SkSL::String output; 17 | SkSL::Program::Settings settings; 18 | std::unique_ptr program = compiler.convertProgram( 19 | SkSL::ProgramKind::kFragment, 20 | SkSL::String((const char*) bytes->data(), 21 | bytes->size()), 22 | settings); 23 | if (!program || !compiler.toMetal(*program, &output)) { 24 | return false; 25 | } 26 | return true; 27 | } 28 | 29 | #if defined(SK_BUILD_FOR_LIBFUZZER) 30 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 31 | if (size > 3000) { 32 | return 0; 33 | } 34 | auto bytes = SkData::MakeWithoutCopy(data, size); 35 | FuzzSKSL2Metal(bytes); 36 | return 0; 37 | } 38 | #endif 39 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzSKSL2Pipeline.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 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 "src/gpu/GrShaderCaps.h" 9 | #include "src/sksl/SkSLCompiler.h" 10 | #include "src/sksl/codegen/SkSLPipelineStageCodeGenerator.h" 11 | #include "src/sksl/ir/SkSLVarDeclarations.h" 12 | #include "src/sksl/ir/SkSLVariable.h" 13 | 14 | #include "fuzz/Fuzz.h" 15 | 16 | bool FuzzSKSL2Pipeline(sk_sp bytes) { 17 | sk_sp caps = SkSL::ShaderCapsFactory::Default(); 18 | SkSL::Compiler compiler(caps.get()); 19 | SkSL::Program::Settings settings; 20 | std::unique_ptr program = compiler.convertProgram( 21 | SkSL::ProgramKind::kRuntimeShader, 22 | SkSL::String((const char*) bytes->data(), 23 | bytes->size()), 24 | settings); 25 | if (!program) { 26 | return false; 27 | } 28 | 29 | class Callbacks : public SkSL::PipelineStage::Callbacks { 30 | using String = SkSL::String; 31 | 32 | String declareUniform(const SkSL::VarDeclaration* decl) override { 33 | return decl->var().name(); 34 | } 35 | 36 | void defineFunction(const char* /*decl*/, const char* /*body*/, bool /*isMain*/) override {} 37 | void defineStruct(const char* /*definition*/) override {} 38 | void declareGlobal(const char* /*declaration*/) override {} 39 | 40 | String sampleChild(int index, String coords, String color) override { 41 | String result = "sample(" + SkSL::to_string(index); 42 | if (!coords.empty()) { 43 | result += ", " + coords; 44 | } 45 | if (!color.empty()) { 46 | result += ", " + color; 47 | } 48 | result += ")"; 49 | return result; 50 | } 51 | }; 52 | 53 | Callbacks callbacks; 54 | SkSL::PipelineStage::ConvertProgram(*program, "coords", "inColor", &callbacks); 55 | return true; 56 | } 57 | 58 | #if defined(SK_BUILD_FOR_LIBFUZZER) 59 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 60 | if (size > 3000) { 61 | return 0; 62 | } 63 | auto bytes = SkData::MakeWithoutCopy(data, size); 64 | FuzzSKSL2Pipeline(bytes); 65 | return 0; 66 | } 67 | #endif 68 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzSKSL2SPIRV.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 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 "src/gpu/GrShaderCaps.h" 9 | #include "src/sksl/SkSLCompiler.h" 10 | 11 | #include "fuzz/Fuzz.h" 12 | 13 | bool FuzzSKSL2SPIRV(sk_sp bytes) { 14 | sk_sp caps = SkSL::ShaderCapsFactory::Default(); 15 | SkSL::Compiler compiler(caps.get()); 16 | SkSL::String output; 17 | SkSL::Program::Settings settings; 18 | std::unique_ptr program = compiler.convertProgram( 19 | SkSL::ProgramKind::kFragment, 20 | SkSL::String((const char*) bytes->data(), 21 | bytes->size()), 22 | settings); 23 | if (!program || !compiler.toSPIRV(*program, &output)) { 24 | return false; 25 | } 26 | return true; 27 | } 28 | 29 | #if defined(SK_BUILD_FOR_LIBFUZZER) 30 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 31 | if (size > 3000) { 32 | return 0; 33 | } 34 | auto bytes = SkData::MakeWithoutCopy(data, size); 35 | FuzzSKSL2SPIRV(bytes); 36 | return 0; 37 | } 38 | #endif 39 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzSVG.cpp: -------------------------------------------------------------------------------- 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/SkData.h" 9 | #include "include/core/SkStream.h" 10 | #include "include/core/SkSurface.h" 11 | #include "modules/svg/include/SkSVGDOM.h" 12 | 13 | void FuzzSVG(sk_sp bytes) { 14 | uint8_t w = 100; 15 | uint8_t h = 200; 16 | 17 | SkMemoryStream stream(bytes); 18 | sk_sp dom = SkSVGDOM::MakeFromStream(stream); 19 | if (!dom) { 20 | return; 21 | } 22 | 23 | auto s = SkSurface::MakeRasterN32Premul(128, 128); 24 | if (!s) { 25 | return; 26 | } 27 | SkSize winSize = SkSize::Make(w, h); 28 | dom->setContainerSize(winSize); 29 | dom->containerSize(); 30 | dom->render(s->getCanvas()); 31 | 32 | } 33 | 34 | #if defined(SK_BUILD_FOR_LIBFUZZER) 35 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 36 | if (size > 30000) { 37 | return 0; 38 | } 39 | auto bytes = SkData::MakeWithoutCopy(data, size); 40 | FuzzSVG(bytes); 41 | return 0; 42 | } 43 | #endif 44 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzSkDescriptorDeserialize.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 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 "src/core/SkDescriptor.h" 9 | #include "src/core/SkRemoteGlyphCache.h" 10 | 11 | void FuzzSkDescriptorDeserialize(sk_sp bytes) { 12 | SkAutoDescriptor aDesc; 13 | bool ok = SkFuzzDeserializeSkDescriptor(bytes, &aDesc); 14 | if (!ok) { 15 | return; 16 | } 17 | 18 | auto desc = aDesc.getDesc(); 19 | 20 | desc->computeChecksum(); 21 | desc->isValid(); 22 | 23 | // An arbitrary number 24 | uint32_t tagToFind = 117; 25 | 26 | uint32_t ignore; 27 | desc->findEntry(tagToFind, &ignore); 28 | } 29 | 30 | #if defined(SK_BUILD_FOR_LIBFUZZER) 31 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 32 | if (size > 1024) { 33 | return 0; 34 | } 35 | auto bytes = SkData::MakeWithoutCopy(data, size); 36 | FuzzSkDescriptorDeserialize(bytes); 37 | return 0; 38 | } 39 | #endif 40 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzSkParagraph.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 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 "fuzz/Fuzz.h" 9 | 10 | void fuzz_SkParagraph(Fuzz* f); 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 13 | if (size > 4000) { 14 | return 0; 15 | } 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_SkParagraph(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzSkRuntimeEffect.cpp: -------------------------------------------------------------------------------- 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 | static bool FuzzSkRuntimeEffect_Once(sk_sp bytes, const SkRuntimeEffect::Options& options) { 33 | if (bytes->size() < kReservedBytes) { 34 | return false; 35 | } 36 | sk_sp codeBytes = SkData::MakeSubset(bytes.get(), 0, bytes->size() - kReservedBytes); 37 | 38 | SkString shaderText{static_cast(codeBytes->data()), codeBytes->size()}; 39 | SkRuntimeEffect::Result result = SkRuntimeEffect::MakeForShader(shaderText, options); 40 | SkRuntimeEffect* effect = result.effect.get(); 41 | 42 | if (!effect || effect->uniformSize() > kReservedBytes) { // if there is not enough uniform bytes 43 | return false; 44 | } 45 | sk_sp uniformBytes = 46 | SkData::MakeSubset(bytes.get(), bytes->size() - kReservedBytes, effect->uniformSize()); 47 | auto shader = effect->makeShader(uniformBytes, /*children=*/nullptr, /*childCount=*/0, 48 | /*localMatrix=*/nullptr, /*isOpaque=*/false); 49 | if (!shader) { 50 | return false; 51 | } 52 | SkPaint paint; 53 | paint.setShader(std::move(shader)); 54 | 55 | sk_sp s = SkSurface::MakeRasterN32Premul(128, 128); 56 | if (!s) { 57 | return false; 58 | } 59 | s->getCanvas()->drawPaint(paint); 60 | 61 | return true; 62 | } 63 | 64 | bool FuzzSkRuntimeEffect(sk_sp bytes) { 65 | // Test once with the inliner disabled... 66 | SkRuntimeEffect::Options options; 67 | options.forceNoInline = true; 68 | bool result = FuzzSkRuntimeEffect_Once(bytes, options); 69 | 70 | // ... and then with the inliner enabled. 71 | options.forceNoInline = false; 72 | result = FuzzSkRuntimeEffect_Once(bytes, options) || result; 73 | 74 | return result; 75 | } 76 | 77 | #if defined(SK_BUILD_FOR_LIBFUZZER) 78 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 79 | if (size > 3000) { 80 | return 0; 81 | } 82 | auto bytes = SkData::MakeWithoutCopy(data, size); 83 | FuzzSkRuntimeEffect(bytes); 84 | return 0; 85 | } 86 | #endif 87 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzTextBlobDeserialize.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 "src/core/SkFontMgrPriv.h" 12 | #include "src/core/SkReadBuffer.h" 13 | #include "src/core/SkTextBlobPriv.h" 14 | #include "tools/fonts/TestFontMgr.h" 15 | 16 | void FuzzTextBlobDeserialize(SkReadBuffer& buf) { 17 | auto tb = SkTextBlobPriv::MakeFromBuffer(buf); 18 | if (!buf.isValid()) { 19 | return; 20 | } 21 | 22 | auto s = SkSurface::MakeRasterN32Premul(128, 128); 23 | if (!s) { 24 | // May return nullptr in memory-constrained fuzzing environments 25 | return; 26 | } 27 | s->getCanvas()->drawTextBlob(tb, 200, 200, SkPaint()); 28 | } 29 | 30 | // TODO(kjlubick): remove IS_FUZZING... after https://crrev.com/c/2410304 lands 31 | #if defined(SK_BUILD_FOR_LIBFUZZER) || defined(IS_FUZZING_WITH_LIBFUZZER) 32 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 33 | if (size > 1024) { 34 | return 0; 35 | } 36 | gSkFontMgr_DefaultFactory = &ToolUtils::MakePortableFontMgr; 37 | SkReadBuffer buf(data, size); 38 | FuzzTextBlobDeserialize(buf); 39 | return 0; 40 | } 41 | #endif 42 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzTriangulation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 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 "fuzz/Fuzz.h" 9 | 10 | void fuzz_Triangulation(Fuzz* f); 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 13 | if (size > 4000) { 14 | return 0; 15 | } 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_Triangulation(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/patch/fuzz/oss_fuzz/FuzzWEBPEncoder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 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 "fuzz/Fuzz.h" 9 | 10 | void fuzz_WEBPEncoder(Fuzz* f); 11 | 12 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 13 | if (size > 262150) { 14 | return 0; 15 | } 16 | auto fuzz = Fuzz(SkData::MakeWithoutCopy(data, size)); 17 | fuzz_WEBPEncoder(&fuzz); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /experiments/skia/scripts/llvm-gcov.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | exec llvm-cov-6.0 gcov "$@" 3 | -------------------------------------------------------------------------------- /experiments/sqlite3/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM graphfuzz_base 2 | 3 | RUN apt-get -y update && apt-get -y install clang++-10 4 | 5 | COPY in /harness/in 6 | WORKDIR /harness/in 7 | 8 | env ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-6.0/bin/llvm-symbolizer 9 | env ASAN_OPTIONS=detect_leaks=0 10 | CMD /bin/zsh 11 | -------------------------------------------------------------------------------- /experiments/sqlite3/in/bug.sh: -------------------------------------------------------------------------------- 1 | 2 | clang -g \ 3 | $1 \ 4 | sqlite3.c \ 5 | -I. -ldl -lpthread -fsanitize=address \ 6 | -o out 7 | -------------------------------------------------------------------------------- /experiments/sqlite3/in/bugs/bug1.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "sqlite3.h" 4 | 5 | int main() { 6 | sqlite3 *db; 7 | sqlite3_open(":memory:", &db); 8 | sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 0); 9 | 10 | sqlite3_stmt *stmt; 11 | sqlite3_prepare_v2(db, "SELECT foo", 11, &stmt, 0); 12 | 13 | sqlite3_finalize(stmt); 14 | sqlite3_close(db); 15 | } 16 | -------------------------------------------------------------------------------- /experiments/sqlite3/in/bugs/bug2.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "sqlite3.h" 4 | 5 | int main() { 6 | sqlite3 *d1; 7 | sqlite3 *d2; 8 | sqlite3 *d3; 9 | sqlite3_open(":memory:", &d1); 10 | sqlite3_open(":memory:", &d2); 11 | sqlite3_open(":memory:", &d3); 12 | sqlite3_backup *b1 = sqlite3_backup_init(d3, "main", d2, "main"); 13 | sqlite3_backup *b2 = sqlite3_backup_init(d1, "main", d3, "main"); 14 | sqlite3_backup *b3 = sqlite3_backup_init(d1, "main", d2, "main"); 15 | sqlite3_backup_step(b1, 8388608); 16 | sqlite3_backup_finish(b1); 17 | sqlite3_backup_step(b2, 0); 18 | sqlite3_backup_finish(b3); 19 | sqlite3_backup_step(b2, 8421376); // SEGV 20 | sqlite3_backup_finish(b2); 21 | sqlite3_close(d1); 22 | sqlite3_close(d2); 23 | sqlite3_close(d3); 24 | } 25 | -------------------------------------------------------------------------------- /experiments/sqlite3/in/build.sh: -------------------------------------------------------------------------------- 1 | # Usage: ./build.sh 2 | 3 | echo "Building $1 exec..." 4 | clang++-10 -g \ 5 | $1/fuzz_exec.cpp \ 6 | -x c sqlite3.c \ 7 | -I. \ 8 | -fsanitize=fuzzer,address \ 9 | -ldl -lpthread -lgraphfuzz -lprotobuf \ 10 | -o $1/fuzz_exec 11 | 12 | echo "Building $1 write..." 13 | clang++-10 \ 14 | $1/fuzz_write.cpp \ 15 | -x c sqlite3.c \ 16 | -I. \ 17 | -fsanitize=fuzzer,address \ 18 | -ldl -lpthread -lgraphfuzz -lprotobuf \ 19 | -o $1/fuzz_write 20 | -------------------------------------------------------------------------------- /experiments/sqlite3/in/c_api.yaml: -------------------------------------------------------------------------------- 1 | headers: 2 | - sqlite3.h 3 | methods: 4 | - int sqlite3_open(const char *filename, OUT(sqlite3 *) db) 5 | - int sqlite3_open(VAL(":memory:"), OUT(sqlite3 *) db) 6 | - int sqlite3_close(DEL(sqlite3 *)) 7 | - int sqlite3_prepare_v2(sqlite3 *db, const char *zSql, int nByte, OUT(sqlite3_stmt *), VAL(0)) 8 | - int sqlite3_step(sqlite3_stmt *) 9 | - int sqlite3_finalize(DEL(sqlite3_stmt *)) 10 | -------------------------------------------------------------------------------- /experiments/sqlite3/in/db_tracker.h: -------------------------------------------------------------------------------- 1 | 2 | extern "C" { 3 | #include "sqlite3.h" 4 | } 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | static vector open_dbs = vector(); 11 | 12 | sqlite3 *new_database() { 13 | sqlite3 *db; 14 | sqlite3_open(":memory:", &db); 15 | 16 | open_dbs.push_back(db); 17 | return db; 18 | } 19 | 20 | void close_all() { 21 | for (int i = 0; i < open_dbs.size(); ++i) { 22 | sqlite3 *db = open_dbs[i]; 23 | sqlite3_close(db); 24 | } 25 | 26 | open_dbs.clear(); 27 | } 28 | -------------------------------------------------------------------------------- /experiments/sqlite3/in/extra.h: -------------------------------------------------------------------------------- 1 | 2 | #include "sqlite3.h" 3 | 4 | typedef sqlite3_value unprotected_sqlite3_value; 5 | 6 | -------------------------------------------------------------------------------- /experiments/sqlite3/in/test.sh: -------------------------------------------------------------------------------- 1 | 2 | ./build.sh f1 3 | 4 | cd f1 && \ 5 | mkdir corpus && \ 6 | ./fuzz_exec --graphfuzz_init_corpus ./corpus && \ 7 | ./fuzz_exec ./corpus -fork=32 -dict=../sql.dict -ignore_crashes=1 8 | --------------------------------------------------------------------------------