├── .github
└── workflows
│ └── swift.yml
├── .gitignore
├── CONTRIBUTING.md
├── Cloud
├── Docker
│ ├── Dockerfile
│ ├── DuktapeBuilder
│ │ ├── .gitignore
│ │ ├── Dockerfile
│ │ └── build.sh
│ ├── FuzzilliBuilder
│ │ ├── .gitignore
│ │ ├── Dockerfile
│ │ └── build.sh
│ ├── JSCBuilder
│ │ ├── .gitignore
│ │ ├── Dockerfile
│ │ └── build.sh
│ ├── JerryScriptBuilder
│ │ ├── .gitignore
│ │ ├── Dockerfile
│ │ └── build.sh
│ ├── README.md
│ ├── SpidermonkeyBuilder
│ │ ├── .gitignore
│ │ ├── Dockerfile
│ │ └── build.sh
│ ├── V8Builder
│ │ ├── .gitignore
│ │ ├── Dockerfile
│ │ └── build.sh
│ └── build.sh
├── GCE
│ ├── README.md
│ ├── config-template.sh
│ ├── push.sh
│ ├── start.sh
│ └── stop.sh
├── README.md
└── Triage
│ ├── README.md
│ └── check.sh
├── Compiler
├── .gitignore
├── Dockerfile
├── README.md
├── bin
│ ├── dune
│ └── fuzzilli_compiler.ml
├── build-pbs.sh
├── dune-project
├── fuzzilli_compiler.opam
├── package.json
├── src
│ ├── ProgramBuilder.ml
│ ├── ProgramBuilder.mli
│ ├── VariableScope.ml
│ ├── VariableScope.mli
│ ├── compiler.ml
│ ├── dune
│ ├── proto
│ │ ├── dune
│ │ ├── operations_pb.ml
│ │ ├── operations_pb.mli
│ │ ├── operations_pp.ml
│ │ ├── operations_pp.mli
│ │ ├── operations_types.ml
│ │ ├── operations_types.mli
│ │ ├── program_pb.ml
│ │ ├── program_pb.mli
│ │ ├── program_pp.ml
│ │ ├── program_pp.mli
│ │ ├── program_types.ml
│ │ ├── program_types.mli
│ │ ├── typesystem_pb.ml
│ │ ├── typesystem_pb.mli
│ │ ├── typesystem_pp.ml
│ │ ├── typesystem_pp.mli
│ │ ├── typesystem_types.ml
│ │ └── typesystem_types.mli
│ ├── translate.ml
│ ├── translate.mli
│ ├── util.ml
│ └── util.mli
├── supportedBuiltins.txt
└── test
│ ├── array_assign.ml
│ ├── array_assign_sugared.ml
│ ├── array_decl.ml
│ ├── array_hole.ml
│ ├── array_spread.ml
│ ├── basic_break.ml
│ ├── basic_compare_test.ml
│ ├── basic_continue.ml
│ ├── basic_for.ml
│ ├── basic_func_call.ml
│ ├── basic_func_ret.ml
│ ├── basic_while.ml
│ ├── binary_ops.ml
│ ├── bitwise_ops.ml
│ ├── create_array.ml
│ ├── del_test.ml
│ ├── do_while.ml
│ ├── dune
│ ├── empty_assignment_scope.ml
│ ├── exp_statement.ml
│ ├── for_in.ml
│ ├── for_in_scope2.ml
│ ├── for_in_scoping.ml
│ ├── for_of.ml
│ ├── func_call_with_spread.ml
│ ├── func_dec_order.ml
│ ├── func_exp_test.ml
│ ├── func_param_scoping.ml
│ ├── if_else.ml
│ ├── in_test.ml
│ ├── instance_of.ml
│ ├── load_array_index.ml
│ ├── load_bigint.ml
│ ├── load_bool.ml
│ ├── load_float.ml
│ ├── load_infinity.ml
│ ├── load_null.ml
│ ├── load_property.ml
│ ├── load_regex.ml
│ ├── logical_ops.ml
│ ├── lone_if.ml
│ ├── new.ml
│ ├── object_creation.ml
│ ├── prog_10.ml
│ ├── prog_1007.ml
│ ├── prop_name_assignment.ml
│ ├── single_constant.ml
│ ├── single_let.ml
│ ├── single_string_literal.ml
│ ├── spread_object.ml
│ ├── store_property_sugared.ml
│ ├── sugared_assignment.ml
│ ├── ternary.ml
│ ├── test.ml
│ ├── this.ml
│ ├── throw.ml
│ ├── typeof.ml
│ ├── unary_minus.ml
│ ├── unary_ops.ml
│ ├── undefined.ml
│ ├── update.ml
│ ├── util.ml
│ ├── v8_natives.ml
│ ├── var_hoisting_1.ml
│ ├── var_hoisting_2.ml
│ ├── var_hoisting_3.ml
│ ├── var_hoisting_shadow.ml
│ ├── varied_func_types.ml
│ ├── void.ml
│ ├── with.ml
│ └── with_load_scope.ml
├── Docs
├── HowFuzzilliWorks.md
├── ProcessingModel.md
├── TypeDetermination.md
└── images
│ ├── fuzzing_with_fuzzil.png
│ ├── generative_engine.png
│ ├── hybrid_engine.png
│ └── mutation_engine.png
├── LICENSE
├── Package.swift
├── README.md
├── Sources
├── Benchmarks
│ └── main.swift
├── FuzzILTool
│ └── main.swift
├── Fuzzilli
│ ├── Configuration.swift
│ ├── Core
│ │ ├── CodeGenerator.swift
│ │ ├── CodeGenerators.swift
│ │ ├── Component.swift
│ │ ├── Environment.swift
│ │ ├── Events.swift
│ │ ├── FuzzEngine.swift
│ │ ├── HybridEngine.swift
│ │ ├── JavaScriptEnvironment.swift
│ │ ├── Logging.swift
│ │ ├── MultiEngine.swift
│ │ ├── MutationEngine.swift
│ │ ├── ProgramBuilder.swift
│ │ ├── ProgramGeneratorStats.swift
│ │ ├── ProgramOrigin.swift
│ │ ├── ProgramTemplate.swift
│ │ ├── ProgramTemplates.swift
│ │ └── Timers.swift
│ ├── Corpus
│ │ ├── BasicCorpus.swift
│ │ ├── Corpus.swift
│ │ └── MarkovCorpus.swift
│ ├── Evaluation
│ │ ├── ProgramAspects.swift
│ │ ├── ProgramCoverageEvaluator.swift
│ │ └── ProgramEvaluator.swift
│ ├── Execution
│ │ ├── Execution.swift
│ │ ├── REPRL.swift
│ │ └── ScriptRunner.swift
│ ├── FuzzIL
│ │ ├── AbstractInterpreter.swift
│ │ ├── Analyzer.swift
│ │ ├── Blocks.swift
│ │ ├── ClassUtils.swift
│ │ ├── Code.swift
│ │ ├── Context.swift
│ │ ├── Instruction.swift
│ │ ├── Operations.swift
│ │ ├── Program.swift
│ │ ├── ProgramComments.swift
│ │ ├── ProgramTypes.swift
│ │ ├── Semantics.swift
│ │ ├── TypeCollectionStatus.swift
│ │ ├── TypeInfo.swift
│ │ ├── TypeSystem.swift
│ │ └── Variable.swift
│ ├── Fuzzer.swift
│ ├── Lifting
│ │ ├── Expression.swift
│ │ ├── FuzzILLifter.swift
│ │ ├── InliningPolicy.swift
│ │ ├── JSExpressions.swift
│ │ ├── JavaScriptLifter.swift
│ │ ├── Lifter.swift
│ │ ├── ScriptWriter.swift
│ │ └── TypeCollectionAnalyzer.swift
│ ├── Minimization
│ │ ├── BlockReducer.swift
│ │ ├── CallArgumentReducer.swift
│ │ ├── GenericInstructionReducer.swift
│ │ ├── InliningReducer.swift
│ │ ├── Minimizer.swift
│ │ ├── ReplaceReducer.swift
│ │ └── Verifier.swift
│ ├── Modules
│ │ ├── Module.swift
│ │ ├── NetworkSync.swift
│ │ ├── Statistics.swift
│ │ ├── Storage.swift
│ │ └── ThreadSync.swift
│ ├── Mutators
│ │ ├── BaseInstructionMutator.swift
│ │ ├── CodeGenMutator.swift
│ │ ├── CombineMutator.swift
│ │ ├── ConcatMutator.swift
│ │ ├── InputMutator.swift
│ │ ├── JITStressMutator.swift
│ │ ├── Mutator.swift
│ │ ├── MutatorSettings.swift
│ │ └── OperationMutator.swift
│ ├── Protobuf
│ │ ├── ProtoUtils.swift
│ │ ├── README.md
│ │ ├── operations.pb.swift
│ │ ├── operations.proto
│ │ ├── program.pb.swift
│ │ ├── program.proto
│ │ ├── sync.pb.swift
│ │ ├── sync.proto
│ │ ├── typesystem.pb.swift
│ │ └── typesystem.proto
│ └── Util
│ │ ├── Arguments.swift
│ │ ├── CInterop.swift
│ │ ├── Error.swift
│ │ ├── Misc.swift
│ │ ├── MockFuzzer.swift
│ │ ├── MovingAverage.swift
│ │ ├── Random.swift
│ │ ├── RingBuffer.swift
│ │ ├── VariableMap.swift
│ │ ├── VariableSet.swift
│ │ └── WeightedList.swift
├── FuzzilliCli
│ ├── CodeGeneratorWeights.swift
│ ├── Profiles
│ │ ├── DuktapeProfile.swift
│ │ ├── JSCProfile.swift
│ │ ├── JerryscriptProfile.swift
│ │ ├── Profile.swift
│ │ ├── QjsProfile.swift
│ │ ├── SpidermonkeyProfile.swift
│ │ └── V8Profile.swift
│ ├── ProgramTemplateWeights.swift
│ ├── TerminalUI.swift
│ └── main.swift
├── JS
│ ├── LICENSE
│ ├── README.md
│ ├── generateSwift.sh
│ ├── helpers.js
│ ├── helpers.swift
│ ├── initTypeCollection.js
│ ├── initTypeCollection.swift
│ ├── printTypes.js
│ └── printTypes.swift
├── REPRLRun
│ └── main.swift
├── libcoverage
│ ├── coverage.c
│ └── include
│ │ └── libcoverage.h
├── libreprl
│ ├── include
│ │ └── libreprl.h
│ ├── libreprl-posix.c
│ └── libreprl-windows.c
└── libsocket
│ ├── include
│ └── libsocket.h
│ ├── socket-posix.c
│ └── socket-win32.c
├── Targets
├── ChakraCore
│ ├── README.md
│ ├── chakracore.patch
│ └── fuzzbuild.sh
├── JavaScriptCore
│ ├── Patches
│ │ └── webkit.patch
│ ├── README.md
│ ├── REVISION
│ └── fuzzbuild.sh
├── Jerryscript
│ ├── Patches
│ │ └── jerryscript.patch
│ ├── README.md
│ ├── REVISION
│ └── fuzzbuild.sh
├── QJS
│ ├── Patches
│ │ └── Fuzzilli-instrumentation-for-QJS.patch
│ ├── README.md
│ └── REVISION
├── README.md
├── Spidermonkey
│ ├── Patches
│ │ └── .gitkeep
│ ├── README.md
│ ├── REVISION
│ └── fuzzbuild.sh
├── V8
│ ├── Patches
│ │ └── .gitkeep
│ ├── README.md
│ ├── REVISION
│ └── fuzzbuild.sh
├── coverage.c
└── duktape
│ └── README.md
└── Tests
└── FuzzilliTests
├── AnalyzerTest.swift
├── EnvironmentTest.swift
├── InliningTest.swift
├── InterpreterTest.swift
├── LifterTest.swift
├── MutationsTest.swift
├── ProgramBuilderTest.swift
├── ProgramSerializationTest.swift
├── RingBufferTest.swift
├── TestUtils.swift
├── TypeSystemTest.swift
├── VariableMapTest.swift
└── VariableSetTest.swift
/.github/workflows/swift.yml:
--------------------------------------------------------------------------------
1 | name: build
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | macOS:
11 | runs-on: macos-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 | - name: Build
16 | run: swift build -v
17 | - name: Run tests
18 | run: swift test -v
19 |
20 | linux:
21 | runs-on: ubuntu-latest
22 |
23 | steps:
24 | - uses: fwal/setup-swift@v1.8.0
25 | - name: Swift Version
26 | run: swift --version
27 | - uses: actions/checkout@v2
28 | - name: Build
29 | run: swift build -v
30 | - name: Run tests
31 | run: swift test -v
32 |
33 | windows:
34 | runs-on: windows-latest
35 |
36 | steps:
37 | - uses: compnerd/gha-setup-swift@main
38 | with:
39 | branch: swift-5.5-release
40 | tag: 5.5-RELEASE
41 | - uses: actions/checkout@v2
42 | - name: Build
43 | run: swift build -v
44 | - name: Run tests
45 | run: swift test -v
46 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Package.resolved
2 | .DS_Store
3 | /.build
4 | /Packages
5 | /*.xcodeproj
6 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement. You (or your employer) retain the copyright to your contribution;
10 | this simply gives us permission to use and redistribute your contributions as
11 | part of the project. Head over to to see
12 | your current agreements on file or to sign a new one.
13 |
14 | You generally only need to submit a CLA once, so if you've already submitted one
15 | (even if it was for a different project), you probably don't need to do it
16 | again.
17 |
18 | ## Code reviews
19 |
20 | All submissions, including submissions by project members, require review. We
21 | use GitHub pull requests for this purpose. Consult
22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
23 | information on using pull requests.
24 |
25 | ## Community Guidelines
26 |
27 | This project follows [Google's Open Source Community
28 | Guidelines](https://opensource.google.com/conduct/).
29 |
--------------------------------------------------------------------------------
/Cloud/Docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM swift:focal
2 |
3 | ENV DEBIAN_FRONTEND=noninteractive
4 | ENV SHELL=bash
5 |
6 | RUN apt-get -y update
7 | RUN apt-get -y upgrade
8 |
9 | # Required for jsc
10 | RUN apt-get install -y libicu-dev
11 |
12 | RUN mkdir /home/fuzzer
13 | WORKDIR /home/fuzzer
14 |
15 | # Add JavaScriptCore binary
16 | ADD JSCBuilder/out jsc
17 | # Add Spidermonkey binary
18 | ADD SpidermonkeyBuilder/out spidermonkey
19 | # Add v8 binary
20 | ADD V8Builder/out v8
21 | # Add duktape binary
22 | ADD DuktapeBuilder/out duktape
23 | # Add JerryScript binary
24 | ADD JerryScriptBuilder/out jerryscript
25 |
26 | # Add Fuzzilli binaries
27 | ADD FuzzilliBuilder/out/Fuzzilli Fuzzilli
28 | ADD FuzzilliBuilder/out/REPRLRun REPRLRun
29 | ADD FuzzilliBuilder/out/Benchmarks Benchmarks
30 |
31 | RUN mkdir fuzz
32 |
--------------------------------------------------------------------------------
/Cloud/Docker/DuktapeBuilder/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 |
--------------------------------------------------------------------------------
/Cloud/Docker/DuktapeBuilder/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM swift:focal
2 |
3 | ENV DEBIAN_FRONTEND=noninteractive
4 | ENV SHELL=bash
5 |
6 | RUN apt-get -y update && apt-get -y upgrade
7 | RUN apt-get install -y git make clang bc curl python-pip nodejs npm
8 |
9 | # Update NodeJS and NPM to the latest versions
10 | RUN npm install -g n
11 | RUN n latest
12 | RUN npm install -g npm
13 |
14 | # Dependency of the duktape build process
15 | RUN pip install pyyaml
16 |
17 | RUN useradd -m builder
18 |
19 | RUN git clone https://github.com/svaarala/duktape.git /home/builder/duktape
20 | WORKDIR /home/builder/duktape
21 |
22 | # The hash of the most recent commit is passed in from the build script, to ensure proper caching behavior
23 | ARG rev
24 | RUN git pull && git checkout $rev
25 |
26 | # Update system packages first
27 | RUN apt-get -y update && apt-get -y upgrade
28 |
29 | # Make normally to pull down NodeJS deps
30 | RUN make
31 |
32 | # Assume that the current master branch maintains duk-fuzzilli
33 | # No need to patch, as the fuzz target is maintained in the duktape repo
34 | # Start building!
35 | RUN make build/duk-fuzzilli
36 |
--------------------------------------------------------------------------------
/Cloud/Docker/DuktapeBuilder/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | cd $(dirname $0)
6 | FUZZILLI_ROOT=../../..
7 |
8 | # Get the hash of the most recent commit on master. This is to ensure proper caching behavior in docker
9 | REV=$(git ls-remote https://github.com/svaarala/duktape.git | grep refs/heads/master | awk '{print $1;}')
10 |
11 | # Since fuzzilli is integrated as a duktape make target, no need to pull over patches or a build script
12 |
13 | # Fetch the source code, get the current master commit, and compile the engine
14 | docker build --build-arg rev=$REV -t duktape_builder .
15 |
16 | # Copy build products
17 | mkdir -p out
18 | docker create --name temp_container duktape_builder
19 | docker cp temp_container:/home/builder/duktape/build/duk-fuzzilli out/duk-fuzzilli
20 | docker rm temp_container
21 |
22 | # Nothing extra to clean up!
23 |
--------------------------------------------------------------------------------
/Cloud/Docker/FuzzilliBuilder/.gitignore:
--------------------------------------------------------------------------------
1 | fuzzilli
2 | out
3 |
--------------------------------------------------------------------------------
/Cloud/Docker/FuzzilliBuilder/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM swift:focal
2 |
3 | ENV DEBIAN_FRONTEND=noninteractive
4 | ENV SHELL=bash
5 |
6 | RUN apt-get -y update && apt-get -y upgrade
7 |
8 | RUN useradd -m builder
9 | WORKDIR /home/builder
10 |
11 | ADD fuzzilli fuzzilli
12 |
13 | RUN cd fuzzilli && swift test && swift build -c release
14 |
--------------------------------------------------------------------------------
/Cloud/Docker/FuzzilliBuilder/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | cd $(dirname $0)
6 | FUZZILLI_ROOT=../../..
7 |
8 | # Setup build context
9 | rm -rf fuzzilli && mkdir fuzzilli
10 | cp -r $FUZZILLI_ROOT/Sources fuzzilli
11 | cp -r $FUZZILLI_ROOT/Tests fuzzilli
12 | cp -r $FUZZILLI_ROOT/Package.swift fuzzilli
13 |
14 | # Compile Fuzzilli
15 | docker build -t fuzzilli_builder .
16 |
17 | # Copy build products
18 | mkdir -p out
19 | docker create --name temp_container fuzzilli_builder
20 | docker cp temp_container:/home/builder/fuzzilli/.build/release/FuzzilliCli out/Fuzzilli
21 | docker cp temp_container:/home/builder/fuzzilli/.build/release/REPRLRun out/REPRLRun
22 | docker cp temp_container:/home/builder/fuzzilli/.build/release/Benchmarks out/Benchmarks
23 | docker rm temp_container
24 |
25 | # Clean up
26 | rm -rf fuzzilli
27 |
--------------------------------------------------------------------------------
/Cloud/Docker/JSCBuilder/.gitignore:
--------------------------------------------------------------------------------
1 | webkit.patch
2 | fuzzbuild.sh
3 | out
4 |
--------------------------------------------------------------------------------
/Cloud/Docker/JSCBuilder/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM swift:focal
2 |
3 | ENV DEBIAN_FRONTEND=noninteractive
4 | ENV SHELL=bash
5 |
6 | RUN apt-get -y update && apt-get -y upgrade
7 | RUN apt-get install -y git cmake clang-12 ruby libicu-dev python3-dev
8 |
9 | RUN useradd -m builder
10 |
11 | # Fetch WebKit source code
12 | RUN git clone https://github.com/WebKit/WebKit.git /home/builder/webkit
13 | WORKDIR /home/builder/webkit
14 |
15 | # Docker will attempt to cache the output of every step. That's fine (and useful to speed things up, e.g. by avoiding
16 | # the need to download the entire source repository again every time!). However, whenever the following ARG is changed
17 | # (i.e. we are building a new version of the engine), a cache miss occurs (because the build context changed) and all
18 | # steps from here on are rerun. That, however, means we might be operating on an old checkout of the source code from
19 | # the cache, and so we update it again before checking out the requested revision.
20 | ARG rev=master
21 |
22 | # Update system packages first
23 | RUN apt-get -y update && apt-get -y upgrade
24 |
25 | # Fetch latest source code and checkout requested source revision
26 | RUN git pull
27 | RUN git checkout $rev
28 |
29 | # Upload and apply patches
30 | ADD Patches Patches
31 | RUN for i in `ls Patches`; do patch -p1 < Patches/$i; done
32 |
33 | # Start building!
34 | ADD fuzzbuild.sh fuzzbuild.sh
35 | RUN ./fuzzbuild.sh
36 |
--------------------------------------------------------------------------------
/Cloud/Docker/JSCBuilder/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | cd $(dirname $0)
6 | FUZZILLI_ROOT=../../..
7 |
8 | # Setup build context
9 | REV=$(cat $FUZZILLI_ROOT/Targets/JavaScriptCore/REVISION)
10 | cp -R $FUZZILLI_ROOT/Targets/JavaScriptCore/Patches .
11 | cp $FUZZILLI_ROOT/Targets/JavaScriptCore/fuzzbuild.sh .
12 |
13 | # Fetch the source code, apply patches, and compile the engine
14 | docker build --build-arg rev=$REV -t jsc_builder .
15 |
16 | # Copy build products
17 | mkdir -p out
18 | docker create --name temp_container jsc_builder
19 | docker cp temp_container:/home/builder/webkit/FuzzBuild/Debug/bin/jsc out/jsc
20 | docker rm temp_container
21 |
22 | # Clean up
23 | rm -r Patches
24 | rm fuzzbuild.sh
25 |
--------------------------------------------------------------------------------
/Cloud/Docker/JerryScriptBuilder/.gitignore:
--------------------------------------------------------------------------------
1 | jerryscript.patch
2 | fuzzbuild.sh
3 | out
4 | *.swp
5 |
--------------------------------------------------------------------------------
/Cloud/Docker/JerryScriptBuilder/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM swift:focal
2 |
3 | ENV DEBIAN_FRONTEND=noninteractive
4 | ENV SHELL=bash
5 |
6 | RUN apt-get -y update && apt-get -y upgrade
7 | RUN apt-get install -y git python3 python3-virtualenv clang cmake
8 |
9 | RUN useradd -m builder
10 |
11 | # Fetch JerryScript source code
12 | RUN git clone https://github.com/jerryscript-project/jerryscript.git /home/builder/jerryscript
13 | WORKDIR /home/builder/jerryscript
14 |
15 | # Docker will attempt to cache the output of every step. That's fine (and useful to speed things up, e.g. by avoiding
16 | # the need to download the entire source repository again every time!). However, whenever the following ARG is changed
17 | # (i.e. we are building a new version of the engine), a cache miss occurs (because the build context changed) and all
18 | # steps from here on are rerun. That, however, means we might be operating on an old checkout of the source code from
19 | # the cache, and so we update it again before checking out the requested revision.
20 | ARG rev=master
21 |
22 | # Update system packages first
23 | RUN apt-get -y update && apt-get -y upgrade
24 |
25 | # Fetch latest source code and checkout requested source revision
26 | RUN git pull
27 | RUN git checkout $rev
28 |
29 | # Upload and apply patches
30 | ADD Patches Patches
31 | RUN for i in `ls Patches`; do patch -p1 < Patches/$i; done
32 |
33 | # Start building!
34 | ADD fuzzbuild.sh fuzzbuild.sh
35 | RUN ./fuzzbuild.sh
36 |
--------------------------------------------------------------------------------
/Cloud/Docker/JerryScriptBuilder/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | cd $(dirname $0)
6 | FUZZILLI_ROOT=../../..
7 |
8 | # Setup build context
9 | REV=$(cat $FUZZILLI_ROOT/Targets/Jerryscript/REVISION)
10 | cp -R $FUZZILLI_ROOT/Targets/Jerryscript/Patches .
11 | cp $FUZZILLI_ROOT/Targets/Jerryscript/fuzzbuild.sh .
12 |
13 | # Fetch the source code, apply patches, and compile the engine
14 | docker build --build-arg rev=$REV -t jerryscript_builder .
15 |
16 | # Copy build products
17 | mkdir -p out
18 | docker create --name temp_container jerryscript_builder
19 | docker cp temp_container:/home/builder/jerryscript/build/bin/jerry out/jerry
20 | docker rm temp_container
21 |
22 | # Clean up
23 | rm -r Patches
24 | rm fuzzbuild.sh
25 |
--------------------------------------------------------------------------------
/Cloud/Docker/README.md:
--------------------------------------------------------------------------------
1 | # Fuzzilli in Docker
2 |
3 | Scripts and Dockerfiles to create a docker image for fuzzing with Fuzzilli.
4 |
5 | ## Overview
6 |
7 | The container image produced by the main build script ([build.sh](./build.sh)) will contain
8 |
9 | - The Fuzzilli binary at ~/Fuzzilli compiled from the current source code, and
10 | - One or more JavaScript engines compiled as specified in their respective [target directory](../../Targets). The necessary files to run the engine (the binary, possibly various libraries, and any other resource files required by the engine) will be located in a subdirectory of the home directory: ~/jsc, ~/spidermonkey, ~/v8, ~/duktape, ~/jerryscript
11 |
12 | The container image will *not* contain any temporary build artifacts, source code, etc. to reduce its size.
13 |
14 | ## Quickstart
15 |
16 | 1. Make sure docker is installed
17 | 2. Run `./build.sh [jsc|spidermonkey|v8|duktape|jerryscript|major]`
18 |
19 | The build script might have to run as root, depending on how [docker is configured](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user).
20 |
21 | Afterwards, a docker image named "fuzzilli" will be available and can be used to fuzz any of the compiled JS engines (in this example JavaScriptCore) with Fuzzilli: `docker run -ti fuzzilli ./Fuzzilli --profile=jsc ./jsc/jsc`
22 |
23 | It is also possible to only rebuild Fuzzilli and use previously compiled engines by running `./build.sh fuzzilli`
24 |
25 | Under the hood, here is roughly what happens during building:
26 |
27 | - Depending on the arguments, the [root build script](./build.sh) will invoke a number of builders, located in the \*Builder subdirectories. Fuzzilli is always (re-)build (by the FuzzilliBuilder) as well as all of the requested JS engines
28 | - The builders will generally first copy all the necessary files (Fuzzilli soure code, engine patches, target revision, etc.) from the repository root into the builder's directory (this is necessary as they have to be in a subdirectory for docker to be able to access them), then build the docker image, fetching any source code, checking out the requested revision (from the [target's](../../Targets) REVISION file) and building the final product (e.g. Fuzzilli or a JS engine). Afterwards, all build products are copied out of the container image into the out/ directory of that builder.
29 | - Finally, the root build script copies all available build products (that may include build products from previous builds if an engine had been built before and not rebuilt this time) into the final fuzzilli docker image.
30 |
--------------------------------------------------------------------------------
/Cloud/Docker/SpidermonkeyBuilder/.gitignore:
--------------------------------------------------------------------------------
1 | firefox.patch
2 | fuzzbuild.sh
3 | out
4 |
--------------------------------------------------------------------------------
/Cloud/Docker/SpidermonkeyBuilder/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM swift:focal
2 |
3 | ENV DEBIAN_FRONTEND=noninteractive
4 | ENV SHELL=bash
5 |
6 | RUN apt-get -y update && apt-get -y upgrade
7 | RUN apt-get install -y git python3 python3-pip python3-virtualenv clang-10
8 |
9 | RUN useradd -m builder
10 |
11 | # Fetch Firefox source code
12 | RUN git clone https://github.com/mozilla/gecko-dev.git /home/builder/firefox
13 | WORKDIR /home/builder/firefox
14 |
15 | # Docker will attempt to cache the output of every step. That's fine (and useful to speed things up, e.g. by avoiding
16 | # the need to download the entire source repository again every time!). However, whenever the following ARG is changed
17 | # (i.e. we are building a new version of the engine), a cache miss occurs (because the build context changed) and all
18 | # steps from here on are rerun. That, however, means we might be operating on an old checkout of the source code from
19 | # the cache, and so we update it again before checking out the requested revision.
20 | ARG rev=master
21 |
22 | # Update system packages first
23 | RUN apt-get -y update && apt-get -y upgrade
24 |
25 | # Fetch latest source code and checkout requested source revision
26 | RUN git pull
27 | RUN git checkout $rev
28 |
29 | # Prepare for building
30 | RUN ./mach bootstrap --application-choice=js
31 |
32 | # Upload and apply patches
33 | ADD Patches Patches
34 | RUN for i in `ls Patches`; do patch -p1 < Patches/$i; done
35 |
36 | # Start building!
37 | ADD fuzzbuild.sh js/src/fuzzbuild.sh
38 | RUN cd js/src && ./fuzzbuild.sh
39 |
--------------------------------------------------------------------------------
/Cloud/Docker/SpidermonkeyBuilder/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | cd $(dirname $0)
6 | FUZZILLI_ROOT=../../..
7 |
8 | # Setup build context
9 | REV=$(cat $FUZZILLI_ROOT/Targets/Spidermonkey/REVISION)
10 | cp -R $FUZZILLI_ROOT/Targets/Spidermonkey/Patches .
11 | cp $FUZZILLI_ROOT/Targets/Spidermonkey/fuzzbuild.sh .
12 |
13 | # Fetch the source code, apply patches, and compile the engine
14 | docker build --build-arg rev=$REV -t spidermonkey_builder .
15 |
16 | # Copy build products
17 | mkdir -p out
18 | docker create --name temp_container spidermonkey_builder
19 | docker cp temp_container:/home/builder/firefox/js/src/fuzzbuild_OPT.OBJ/dist/bin/js out/js
20 | docker rm temp_container
21 |
22 | # Clean up
23 | rm -r Patches
24 | rm fuzzbuild.sh
25 |
--------------------------------------------------------------------------------
/Cloud/Docker/V8Builder/.gitignore:
--------------------------------------------------------------------------------
1 | v8.patch
2 | fuzzbuild.sh
3 | out
4 |
--------------------------------------------------------------------------------
/Cloud/Docker/V8Builder/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM swift:focal
2 |
3 | ENV DEBIAN_FRONTEND=noninteractive
4 | ENV SHELL=bash
5 |
6 | RUN apt-get -y update && apt-get -y upgrade
7 | RUN apt-get install -y python python3 git curl
8 |
9 | RUN useradd -m builder
10 |
11 | # Fetch v8 source code
12 | WORKDIR /home/builder
13 | RUN git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
14 | ENV PATH="${PATH}:/home/builder/depot_tools"
15 | RUN gclient
16 | RUN gclient metrics --opt-out
17 | RUN mkdir v8 && cd v8 && fetch v8
18 | WORKDIR /home/builder/v8/v8
19 | RUN git checkout master
20 |
21 | # Docker will attempt to cache the output of every step. That's fine (and useful to speed things up, e.g. by avoiding
22 | # the need to download the entire source repository again every time!). However, whenever the following ARG is changed
23 | # (i.e. we are building a new version of the engine), a cache miss occurs (because the build context changed) and all
24 | # steps from here on are rerun. That, however, means we might be operating on an old checkout of the source code from
25 | # the cache, and so we update it again before checking out the requested revision.
26 | ARG rev=master
27 |
28 | # Update system packages first
29 | RUN apt-get -y update && apt-get -y upgrade
30 |
31 | # Fetch latest source code and checkout requested source revision
32 | RUN git pull
33 | RUN git checkout $rev
34 | RUN gclient sync
35 |
36 | # Upload and apply patches
37 | ADD Patches Patches
38 | RUN for i in `ls Patches`; do patch -p1 < Patches/$i; done
39 |
40 | # Start building!
41 | ADD fuzzbuild.sh fuzzbuild.sh
42 | RUN ./fuzzbuild.sh
43 |
--------------------------------------------------------------------------------
/Cloud/Docker/V8Builder/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | cd $(dirname $0)
6 | FUZZILLI_ROOT=../../..
7 |
8 | # Setup build context
9 | REV=$(cat $FUZZILLI_ROOT/Targets/V8/REVISION)
10 | cp -R $FUZZILLI_ROOT/Targets/V8/Patches .
11 | cp $FUZZILLI_ROOT/Targets/V8/fuzzbuild.sh .
12 |
13 | # Fetch the source code, apply patches, and compile the engine
14 | docker build --build-arg rev=$REV -t v8_builder .
15 |
16 | # Copy build products
17 | mkdir -p out
18 | docker create --name temp_container v8_builder
19 | docker cp temp_container:/home/builder/v8/v8/out/fuzzbuild/d8 out/d8
20 | docker cp temp_container:/home/builder/v8/v8/out/fuzzbuild/snapshot_blob.bin out/snapshot_blob.bin
21 | docker cp temp_container:/home/builder/v8/v8/out/fuzzbuild/icudtl.dat out/icudtl.dat
22 | docker rm temp_container
23 |
24 | # Clean up
25 | rm -r Patches
26 | rm fuzzbuild.sh
27 |
--------------------------------------------------------------------------------
/Cloud/Docker/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | CONTAINER_NAME=fuzzilli
6 |
7 | if [ $# -eq 0 ]; then
8 | echo "Usage: $0 [fuzzilli|jsc|spidermonkey|v8|duktape|jerryscript|major]"
9 | exit 1
10 | fi
11 |
12 | BUILD_JSC=false
13 | BUILD_SPIDERMONKEY=false
14 | BUILD_V8=false
15 | BUILD_DUKTAPE=false
16 | BUILD_JERRYSCRIPT=false
17 |
18 | while test $# -gt 0
19 | do
20 | case "$1" in
21 | fuzzilli)
22 | # We'll build fuzzilli anyway :)
23 | ;;
24 | jsc)
25 | BUILD_JSC=true
26 | ;;
27 | spidermonkey)
28 | BUILD_SPIDERMONKEY=true
29 | ;;
30 | v8)
31 | BUILD_V8=true
32 | ;;
33 | duktape)
34 | BUILD_DUKTAPE=true
35 | ;;
36 | jerryscript)
37 | BUILD_JERRYSCRIPT=true
38 | ;;
39 | major)
40 | BUILD_JSC=true
41 | BUILD_SPIDERMONKEY=true
42 | BUILD_V8=true
43 | ;;
44 | *)
45 | echo "Usage: $0 [fuzzilli|jsc|spidermonkey|v8|duktape|jerryscript|major]"
46 | exit 1
47 | ;;
48 | esac
49 | shift
50 | done
51 |
52 | #
53 | # Always build Fuzzilli
54 | #
55 | echo "[*] Building Fuzzilli"
56 | ./FuzzilliBuilder/build.sh
57 |
58 | #
59 | # Selectively (re)build the JavaScript engines
60 | #
61 |
62 | # Ensure output directories are always present as they will be copied into the final container
63 | mkdir -p JSCBuilder/out
64 | mkdir -p SpidermonkeyBuilder/out
65 | mkdir -p V8Builder/out
66 | mkdir -p DuktapeBuilder/out
67 | mkdir -p JerryScriptBuilder/out
68 |
69 | if [ "$BUILD_JSC" = true ]; then
70 | echo "[*] Building JavaScriptCore"
71 | ./JSCBuilder/build.sh
72 | fi
73 |
74 | if [ "$BUILD_SPIDERMONKEY" = true ]; then
75 | echo "[*] Building Spidermonkey"
76 | ./SpidermonkeyBuilder/build.sh
77 | fi
78 |
79 | if [ "$BUILD_V8" = true ]; then
80 | echo "[*] Building V8"
81 | ./V8Builder/build.sh
82 | fi
83 |
84 | if [ "$BUILD_DUKTAPE" = true ]; then
85 | echo "[*] Building Duktape"
86 | ./DuktapeBuilder/build.sh
87 | fi
88 |
89 | if [ "$BUILD_JERRYSCRIPT" = true ]; then
90 | echo "[*] Building JerryScript"
91 | ./JerryScriptBuilder/build.sh
92 | fi
93 |
94 | #
95 | # Build the final container image which only contains the binaries (no intermediate build artifacts, source code, etc.).
96 | #
97 | echo "[*] Packing Fuzzilli container image"
98 | docker build -t $CONTAINER_NAME .
99 |
--------------------------------------------------------------------------------
/Cloud/GCE/config-template.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # GCE configuration.
4 | #
5 | # Generally, only the PROJECT_ID and PROJECT_NUMBER as well as the Fuzzilli options and NUM_WORKERS need to be changed.
6 | #
7 |
8 | # The GCP project to use. See https://cloud.google.com/resource-manager/docs/creating-managing-projects#identifying_projects
9 | PROJECT_ID=YOUR_PROJECT_ID
10 | PROJECT_NUMBER=YOUR_PROJECT_NUMBER
11 |
12 | # The name of the session, can be an arbitrary string.
13 | # This also serves as the prefix for instance names. For example, the root instance will be named $SESSION-root.
14 | SESSION="fuzzilli"
15 |
16 | # The path to the JavaScript engine binary in the container
17 | BINARY=./v8/d8
18 | # Common arguments to pass to every Fuzzilli instance. See ./Fuzzilli --help
19 | FUZZILLI_ARGS="--profile=v8"
20 | # Arguments for the root instance. See ./Fuzzilli --help
21 | FUZZILLI_ROOT_ARGS="--exportStatistics"
22 |
23 | # Region and zone where compute instances are created. See https://cloud.google.com/compute/docs/regions-zones
24 | REGION=us-east1
25 | ZONE=$REGION-b
26 |
27 | # By default, the default service account: https://cloud.google.com/iam/docs/service-accounts#default
28 | SERVICE_ACCOUNT=$PROJECT_NUMBER-compute@developer.gserviceaccount.com
29 |
30 | # The docker container and OS image to use.
31 | CONTAINER_NAME=fuzzilli
32 | CONTAINER_IMAGE=gcr.io/$PROJECT_ID/$CONTAINER_NAME:latest
33 | # By default, use the latest stable OS image
34 | OS_IMAGE=$(gcloud compute --project=$PROJECT_ID images list --filter="family=cos-stable" --format="value(NAME)")
35 |
36 | # Total number of worker instances. Adjust this as desired
37 | NUM_WORKERS=128
38 |
39 | # How many workers to run per machine, using --jobs=N.
40 | # NUM_WORKERS / NUM_WORKERS_PER_MACHINE worker machines will be started.
41 | # This number should roughly equal the number of cores on the worker machines.
42 | NUM_WORKERS_PER_MACHINE=8
43 |
44 | # How many workers a single master instance can handle at most.
45 | # This will determine the depth of the instace hierarchy.
46 | # There is usually no need to change this number.
47 | MAX_WORKERS_PER_MASTER=32
48 |
49 | # 2 cores, 8 GB
50 | ROOT_MACHINE_TYPE=e2-standard-2
51 | MASTER_MACHINE_TYPE=e2-standard-2
52 | # 8 cores, 8 GB
53 | WORKER_MACHINE_TYPE=e2-highcpu-8
54 |
--------------------------------------------------------------------------------
/Cloud/GCE/push.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Push the current fuzzilli image (built from the Docker/ directory) to the GCE docker registry.
4 | #
5 |
6 | set -e
7 |
8 | source config.sh
9 |
10 | docker tag fuzzilli gcr.io/$PROJECT_ID/$CONTAINER_NAME
11 | docker push gcr.io/$PROJECT_ID/$CONTAINER_NAME
12 |
--------------------------------------------------------------------------------
/Cloud/GCE/stop.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Terminates all worker instances.
4 | #
5 |
6 | set -e
7 |
8 | source config.sh
9 |
10 | if [ $# -eq 0 ]; then
11 | echo "Usage: $0 [root|masters|workers|all]"
12 | exit 1
13 | fi
14 |
15 | STOP_ROOT=false
16 | STOP_MASTERS=false
17 | STOP_WORKERS=false
18 |
19 | while test $# -gt 0
20 | do
21 | case "$1" in
22 | root)
23 | STOP_ROOT=true
24 | ;;
25 | masters)
26 | STOP_MASTERS=true
27 | ;;
28 | workers)
29 | STOP_WORKERS=true
30 | ;;
31 | all)
32 | STOP_ROOT=true
33 | STOP_MASTERS=true
34 | STOP_WORKERS=true
35 | ;;
36 | *)
37 | echo "Usage: $0 [root|masters|workers|all]"
38 | exit 1
39 | ;;
40 | esac
41 | shift
42 | done
43 |
44 | if [ "$STOP_WORKERS" = true ]; then
45 | echo "[*] Deleting worker instances"
46 | WORKERS=$(gcloud compute --project=$PROJECT_ID instances list --filter="labels.role=worker && labels.session=$SESSION" --format="value(name)")
47 |
48 | if [ ! -z "$WORKERS" ]; then
49 | while read -r instance; do
50 | gcloud compute --project=$PROJECT_ID instances delete $instance --quiet --zone $ZONE &
51 | done <<< "$WORKERS"
52 | else
53 | echo "Nothing to delete"
54 | fi
55 |
56 | wait
57 | fi
58 |
59 | if [ "$STOP_MASTERS" = true ]; then
60 | echo "[*] Deleting master instances"
61 | MASTERS=$(gcloud compute --project=$PROJECT_ID instances list --filter="labels.role=master && labels.session=$SESSION" --format="value(name)")
62 |
63 | if [ ! -z "$MASTERS" ]; then
64 | while read -r instance; do
65 | gcloud compute --project=$PROJECT_ID instances delete $instance --quiet --zone $ZONE &
66 | done <<< "$MASTERS"
67 | else
68 | echo "Nothing to delete"
69 | fi
70 |
71 | wait
72 | fi
73 |
74 | if [ "$STOP_ROOT" = true ]; then
75 | echo "[*] Deleting root instance"
76 | ROOT=$(gcloud compute --project=$PROJECT_ID instances list --filter="labels.role=root && labels.session=$SESSION" --format="value(name)")
77 | if [ ! -z "$ROOT" ]; then
78 | gcloud compute --project=$PROJECT_ID instances delete $ROOT --quiet --zone $ZONE
79 | else
80 | echo "Nothing to delete"
81 | fi
82 | fi
83 |
--------------------------------------------------------------------------------
/Cloud/README.md:
--------------------------------------------------------------------------------
1 | # Fuzzilli in the Cloud
2 |
3 | Easy distributed fuzzing with Fuzzilli.
4 |
5 | # Docker/
6 |
7 | Scripts and Dockerfiles to build Fuzzilli as well as any of the supported engines. The fuzzilli docker image can then be used for fuzzing locally or be uploaded to a docker registry for distributed fuzzing, see below.
8 |
9 | # GCE/
10 |
11 | Scripts to setup and tear down distributed fuzzing with Fuzzilli on Google Compute Engine.
12 |
13 | # Triage/
14 |
15 | Rudimentary crash triaging.
16 |
--------------------------------------------------------------------------------
/Cloud/Triage/README.md:
--------------------------------------------------------------------------------
1 | # Triage
2 |
3 | Small script to help with crash triaging.
4 |
5 | ## Usage
6 |
7 | The script requires a local build of the target JS engine. For JavaScriptCore and Spidermonkey an ASAN build is recommended. Once the build is complete, simply run the script, providing it with the path to the JS shell, the path to the crashes/ directory that fuzzilli produced, and the commandline arguments for the JS shell (get those from the [respective profile](../../Sources/FuzzilliCli/Profiles)):
8 |
9 | ./check.sh ./crashes ~/WebKit/AsanBuild/Debug/bin/jsc --validateOptions=true --useConcurrentJIT=false --useConcurrentGC=false --thresholdForJITSoon=10 --thresholdForJITAfterWarmUp=10 --thresholdForOptimizeAfterWarmUp=100 --thresholdForOptimizeAfterLongWarmUp=100 --thresholdForOptimizeAfterLongWarmUp=100 --thresholdForFTLOptimizeAfterWarmUp=1000 --thresholdForFTLOptimizeSoon=1000 --gcAtEnd=true
10 |
11 | The file will produce a log with all output from stdout and stderr (which includes Asan crash reports). Afterwards, you can grep (and uniquify) the log for certain keywords such as
12 | - for JSC: "trap", "assert", "segv", "Sanitizer"
13 | - for Spidernmonkey: "trap", "assert", "segv", "Sanitizer"
14 | - for V8: "Debug check failed", "Check failed", "assert", "fatal", "received"
15 |
--------------------------------------------------------------------------------
/Cloud/Triage/check.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | if [ $# -lt 2 ]; then
6 | echo "Usage: $0 path/to/js/shell path/to/crashes [arguments, ...]"
7 | exit 1
8 | fi
9 |
10 | CRASHES_DIR=$1
11 | shift
12 | JS_SHELL=$1
13 | shift
14 |
15 | for f in $(find $1 -maxdepth 1 -name '*js'); do
16 | echo $f
17 | ASAN_OPTIONS=detect_leaks=0 timeout 5s $JS_SHELL $@ $f
18 | done &> log
19 |
--------------------------------------------------------------------------------
/Compiler/.gitignore:
--------------------------------------------------------------------------------
1 | _build
2 | _esy
3 | *.merlin
4 | esy.lock
5 | node_modules
6 | fuzzilli_compiler.install
--------------------------------------------------------------------------------
/Compiler/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:latest
2 |
3 | ENV DEBIAN_FRONTEND=noninteractive
4 | ENV SHELL=bash
5 |
6 | RUN apt-get -y update && apt-get -y upgrade
7 | RUN apt-get install -y curl opam npm
8 | RUN npm install -g --unsafe-perm esy
9 |
10 | RUN useradd -m builder
11 | WORKDIR /home/builder
12 | USER builder
13 |
14 | ADD --chown=builder:builder ./ Compiler
15 | WORKDIR Compiler
16 |
17 | # Set up Opam & Ocaml properly, for OCaml v 4.10.0
18 | # Pin flow, and setup the package.json
19 | RUN opam init -a --disable-sandboxing
20 | RUN opam switch create 4.10.0 && \
21 | eval $(opam env) && \
22 | opam pin add -y flow_parser https://github.com/facebook/flow.git && \
23 | sed -i 's/.*REPLACE ME.*/ "flow_parser": "link:\/home\/builder\/.opam\/4.10.0\/.opam-switch\/sources\/flow_parser\/flow_parser.opam"/' package.json
24 |
25 | # Install dependencies
26 | RUN esy install
27 |
28 | # And build!
29 | RUN esy build
30 |
31 | # Run the tests to verify that the compiler works correctly
32 | RUN esy x test
33 |
34 | # Finally, copy the compiler binary into the current directory for easy access
35 | RUN cp _esy/default/build/default/bin/fuzzilli_compiler.exe .
--------------------------------------------------------------------------------
/Compiler/bin/dune:
--------------------------------------------------------------------------------
1 | (executable
2 | (name fuzzilli_compiler)
3 | (public_name fuzzilli_compiler)
4 | (libraries compiler core flow_parser ocaml-protoc proto str)
5 | (preprocess (pps ppx_jane ppx_deriving ppx_deriving.show)))
--------------------------------------------------------------------------------
/Compiler/bin/fuzzilli_compiler.ml:
--------------------------------------------------------------------------------
1 | let do_compile infile outfile ~(emit_ast : bool) ~(emit_builtins: bool) ~(v8_natives: bool) ~(use_placeholder: bool)=
2 | try
3 | let file_string = Core.In_channel.read_all infile in
4 | let (prog, err) = Compiler.string_to_flow_ast file_string in
5 | let (loc_type, a) = prog in
6 | let prog_string = Compiler.print_ast_statement_list a.statements in
7 | if emit_ast then
8 | print_endline ("Provided AST: \n" ^ prog_string ^ "\n")
9 | else ();
10 | let inst_list = Compiler.flow_ast_to_inst_list prog emit_builtins v8_natives use_placeholder in
11 | let prog = Compiler.inst_list_to_prog inst_list in
12 | Compiler.write_proto_obj_to_file prog outfile
13 | with
14 | Invalid_argument x -> print_endline ("Invalid arg: " ^ x)
15 | | Parse_error.Error y ->
16 | let _, err_list = List.split y in
17 | Printf.printf "Compiler Error %s\n" (Parse_error.PP.error (List.hd err_list))
18 | | y -> print_endline ("Other compiler error" ^ (Core.Exn.to_string y))
19 |
20 | let command =
21 | let open Core in
22 | Command.basic
23 | ~summary:"Compile a JS source file to Fuzzil"
24 | Command.Let_syntax.(
25 | let%map_open
26 | infile = (anon ("infile" %: Filename.arg_type))
27 | and outfile = (anon ("outfile" %: string))
28 | and emit_ast = flag "-ast" no_arg ~doc: "Print the Flow_ast"
29 | and emit_builtins = flag "-builtins" no_arg ~doc: "Print all builtins encountered"
30 | and v8_natives = flag "-v8-natives" no_arg ~doc: "Include v8 natives, as funtions without the leading %. Requires the builtins be included in the fuzzilli profile for v8. Currently only uses a hardcoded list in util.ml"
31 | and use_placeholder = flag "-use-placeholder" no_arg ~doc: "Replaces each unknown builtin with 'placeholder'."
32 | in
33 | fun () -> do_compile infile outfile ~emit_ast ~emit_builtins ~v8_natives ~use_placeholder)
34 |
35 | let () =
36 | Core.Command.run command
37 |
--------------------------------------------------------------------------------
/Compiler/build-pbs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | ocaml-protoc -I ../Sources/Fuzzilli/Protobuf/ ../Sources/Fuzzilli/Protobuf/operations.proto -ml_out ./src/proto
3 | ocaml-protoc -I ../Sources/Fuzzilli/Protobuf/ ../Sources/Fuzzilli/Protobuf/program.proto -ml_out ./src/proto
4 | ocaml-protoc -I ../Sources/Fuzzilli/Protobuf/ ../Sources/Fuzzilli/Protobuf/typesystem.proto -ml_out ./src/proto
5 |
--------------------------------------------------------------------------------
/Compiler/dune-project:
--------------------------------------------------------------------------------
1 | (lang dune 1.2)
2 |
--------------------------------------------------------------------------------
/Compiler/fuzzilli_compiler.opam:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/P1umer/fuzzilli4wasm/5ecdc393366f9c4920eeda2c0bd934d0919a02f5/Compiler/fuzzilli_compiler.opam
--------------------------------------------------------------------------------
/Compiler/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fuzzilli_compiler",
3 | "version": "0.1",
4 | "esy": {
5 | "build": "dune build -p #{self.name}"
6 | },
7 | "dependencies": {
8 | "@opam/core": "*",
9 | "@opam/ocaml-lsp-server": "*",
10 | "@opam/ocaml-protoc": "*",
11 | "flow_parser": "*",
12 | "ocaml": "~4.10",
13 | "@opam/alcotest": "*",
14 | "@opam/uuidm": "*"
15 | },
16 | "resolutions": {
17 | "flow_parser": "link:{REPLACE ME PATH HERE}/.opam/4.10.0/.opam-switch/sources/flow_parser/flow_parser.opam"
18 | },
19 | "scripts": {
20 | "build-pbs": "./build-pbs.sh"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Compiler/src/VariableScope.mli:
--------------------------------------------------------------------------------
1 | val get_vars_to_hoist : (Loc.t, Loc.t) Flow_ast.Statement.t list -> string list * string list
--------------------------------------------------------------------------------
/Compiler/src/compiler.ml:
--------------------------------------------------------------------------------
1 |
2 | (* Translate an ast to a list of instructions *)
3 | let flow_ast_to_inst_list = Translate.flow_ast_to_inst_list
4 |
5 | (* Util Interface *)
6 | let print_ast_statement_list = Util.print_statement_list
7 |
8 | (* Run the flow_ast parser *)
9 | let string_to_flow_ast = Util.string_to_flow_ast
10 |
11 | (* Output a generated Protobuf*)
12 | let write_proto_obj_to_file = Util.write_proto_obj_to_file
13 |
14 | (* Wrap a list of instructions in the program structure *)
15 | let inst_list_to_prog = Util.inst_list_to_prog
16 |
17 | (* Pretty print support *)
18 | let pp_instruction = Program_pp.pp_instruction
19 |
20 | let init_test_builder = ProgramBuilder.init_builder false false false
21 |
22 | (* Give the test interface access to the protobufs *)
23 | module Program_types = Program_types
24 | module Operations_types = Operations_types
25 | module Typesystem_types = Typesystem_types
26 |
27 | (* Make ProgramBuilder available to our test suite*)
28 | module ProgramBuilder = ProgramBuilder
--------------------------------------------------------------------------------
/Compiler/src/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name compiler)
3 | (libraries core flow_parser ocaml-protoc proto str)
4 | (preprocess (pps ppx_jane ppx_deriving ppx_deriving.show)))
--------------------------------------------------------------------------------
/Compiler/src/proto/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name proto)
3 | (wrapped false)
4 | (libraries ocaml-protoc)
5 | (preprocess (pps ppx_gen_rec ppx_deriving.std sedlex.ppx)))
6 |
--------------------------------------------------------------------------------
/Compiler/src/proto/program_pb.mli:
--------------------------------------------------------------------------------
1 | (** program.proto Binary Encoding *)
2 |
3 |
4 | (** {2 Protobuf Encoding} *)
5 |
6 | val encode_instruction_operation : Program_types.instruction_operation -> Pbrt.Encoder.t -> unit
7 | (** [encode_instruction_operation v encoder] encodes [v] with the given [encoder] *)
8 |
9 | val encode_instruction : Program_types.instruction -> Pbrt.Encoder.t -> unit
10 | (** [encode_instruction v encoder] encodes [v] with the given [encoder] *)
11 |
12 | val encode_type_collection_status : Program_types.type_collection_status -> Pbrt.Encoder.t -> unit
13 | (** [encode_type_collection_status v encoder] encodes [v] with the given [encoder] *)
14 |
15 | val encode_type_quality : Program_types.type_quality -> Pbrt.Encoder.t -> unit
16 | (** [encode_type_quality v encoder] encodes [v] with the given [encoder] *)
17 |
18 | val encode_type_info : Program_types.type_info -> Pbrt.Encoder.t -> unit
19 | (** [encode_type_info v encoder] encodes [v] with the given [encoder] *)
20 |
21 | val encode_program : Program_types.program -> Pbrt.Encoder.t -> unit
22 | (** [encode_program v encoder] encodes [v] with the given [encoder] *)
23 |
24 |
25 | (** {2 Protobuf Decoding} *)
26 |
27 | val decode_instruction_operation : Pbrt.Decoder.t -> Program_types.instruction_operation
28 | (** [decode_instruction_operation decoder] decodes a [instruction_operation] value from [decoder] *)
29 |
30 | val decode_instruction : Pbrt.Decoder.t -> Program_types.instruction
31 | (** [decode_instruction decoder] decodes a [instruction] value from [decoder] *)
32 |
33 | val decode_type_collection_status : Pbrt.Decoder.t -> Program_types.type_collection_status
34 | (** [decode_type_collection_status decoder] decodes a [type_collection_status] value from [decoder] *)
35 |
36 | val decode_type_quality : Pbrt.Decoder.t -> Program_types.type_quality
37 | (** [decode_type_quality decoder] decodes a [type_quality] value from [decoder] *)
38 |
39 | val decode_type_info : Pbrt.Decoder.t -> Program_types.type_info
40 | (** [decode_type_info decoder] decodes a [type_info] value from [decoder] *)
41 |
42 | val decode_program : Pbrt.Decoder.t -> Program_types.program
43 | (** [decode_program decoder] decodes a [program] value from [decoder] *)
44 |
--------------------------------------------------------------------------------
/Compiler/src/proto/program_pp.mli:
--------------------------------------------------------------------------------
1 | (** program.proto Pretty Printing *)
2 |
3 |
4 | (** {2 Formatters} *)
5 |
6 | val pp_instruction_operation : Format.formatter -> Program_types.instruction_operation -> unit
7 | (** [pp_instruction_operation v] formats v *)
8 |
9 | val pp_instruction : Format.formatter -> Program_types.instruction -> unit
10 | (** [pp_instruction v] formats v *)
11 |
12 | val pp_type_collection_status : Format.formatter -> Program_types.type_collection_status -> unit
13 | (** [pp_type_collection_status v] formats v *)
14 |
15 | val pp_type_quality : Format.formatter -> Program_types.type_quality -> unit
16 | (** [pp_type_quality v] formats v *)
17 |
18 | val pp_type_info : Format.formatter -> Program_types.type_info -> unit
19 | (** [pp_type_info v] formats v *)
20 |
21 | val pp_program : Format.formatter -> Program_types.program -> unit
22 | (** [pp_program v] formats v *)
23 |
--------------------------------------------------------------------------------
/Compiler/src/proto/typesystem_pb.mli:
--------------------------------------------------------------------------------
1 | (** typesystem.proto Binary Encoding *)
2 |
3 |
4 | (** {2 Protobuf Encoding} *)
5 |
6 | val encode_type_ext : Typesystem_types.type_ext -> Pbrt.Encoder.t -> unit
7 | (** [encode_type_ext v encoder] encodes [v] with the given [encoder] *)
8 |
9 | val encode_type_ : Typesystem_types.type_ -> Pbrt.Encoder.t -> unit
10 | (** [encode_type_ v encoder] encodes [v] with the given [encoder] *)
11 |
12 | val encode_type_extension : Typesystem_types.type_extension -> Pbrt.Encoder.t -> unit
13 | (** [encode_type_extension v encoder] encodes [v] with the given [encoder] *)
14 |
15 | val encode_function_signature : Typesystem_types.function_signature -> Pbrt.Encoder.t -> unit
16 | (** [encode_function_signature v encoder] encodes [v] with the given [encoder] *)
17 |
18 |
19 | (** {2 Protobuf Decoding} *)
20 |
21 | val decode_type_ext : Pbrt.Decoder.t -> Typesystem_types.type_ext
22 | (** [decode_type_ext decoder] decodes a [type_ext] value from [decoder] *)
23 |
24 | val decode_type_ : Pbrt.Decoder.t -> Typesystem_types.type_
25 | (** [decode_type_ decoder] decodes a [type_] value from [decoder] *)
26 |
27 | val decode_type_extension : Pbrt.Decoder.t -> Typesystem_types.type_extension
28 | (** [decode_type_extension decoder] decodes a [type_extension] value from [decoder] *)
29 |
30 | val decode_function_signature : Pbrt.Decoder.t -> Typesystem_types.function_signature
31 | (** [decode_function_signature decoder] decodes a [function_signature] value from [decoder] *)
32 |
--------------------------------------------------------------------------------
/Compiler/src/proto/typesystem_pp.ml:
--------------------------------------------------------------------------------
1 | [@@@ocaml.warning "-27-30-39"]
2 |
3 | let rec pp_type_ext fmt (v:Typesystem_types.type_ext) =
4 | match v with
5 | | Typesystem_types.Extension_idx x -> Format.fprintf fmt "@[Extension_idx(%a)@]" Pbrt.Pp.pp_int32 x
6 | | Typesystem_types.Extension x -> Format.fprintf fmt "@[Extension(%a)@]" pp_type_extension x
7 |
8 | and pp_type_ fmt (v:Typesystem_types.type_) =
9 | let pp_i fmt () =
10 | Format.pp_open_vbox fmt 1;
11 | Pbrt.Pp.pp_record_field "definite_type" Pbrt.Pp.pp_int32 fmt v.Typesystem_types.definite_type;
12 | Pbrt.Pp.pp_record_field "possible_type" Pbrt.Pp.pp_int32 fmt v.Typesystem_types.possible_type;
13 | Pbrt.Pp.pp_record_field "ext" pp_type_ext fmt v.Typesystem_types.ext;
14 | Format.pp_close_box fmt ()
15 | in
16 | Pbrt.Pp.pp_brk pp_i fmt ()
17 |
18 | and pp_type_extension fmt (v:Typesystem_types.type_extension) =
19 | let pp_i fmt () =
20 | Format.pp_open_vbox fmt 1;
21 | Pbrt.Pp.pp_record_field "properties" (Pbrt.Pp.pp_list Pbrt.Pp.pp_string) fmt v.Typesystem_types.properties;
22 | Pbrt.Pp.pp_record_field "methods" (Pbrt.Pp.pp_list Pbrt.Pp.pp_string) fmt v.Typesystem_types.methods;
23 | Pbrt.Pp.pp_record_field "group" Pbrt.Pp.pp_string fmt v.Typesystem_types.group;
24 | Pbrt.Pp.pp_record_field "signature" (Pbrt.Pp.pp_option pp_function_signature) fmt v.Typesystem_types.signature;
25 | Format.pp_close_box fmt ()
26 | in
27 | Pbrt.Pp.pp_brk pp_i fmt ()
28 |
29 | and pp_function_signature fmt (v:Typesystem_types.function_signature) =
30 | let pp_i fmt () =
31 | Format.pp_open_vbox fmt 1;
32 | Pbrt.Pp.pp_record_field "input_types" (Pbrt.Pp.pp_list pp_type_) fmt v.Typesystem_types.input_types;
33 | Pbrt.Pp.pp_record_field "output_type" (Pbrt.Pp.pp_option pp_type_) fmt v.Typesystem_types.output_type;
34 | Format.pp_close_box fmt ()
35 | in
36 | Pbrt.Pp.pp_brk pp_i fmt ()
37 |
--------------------------------------------------------------------------------
/Compiler/src/proto/typesystem_pp.mli:
--------------------------------------------------------------------------------
1 | (** typesystem.proto Pretty Printing *)
2 |
3 |
4 | (** {2 Formatters} *)
5 |
6 | val pp_type_ext : Format.formatter -> Typesystem_types.type_ext -> unit
7 | (** [pp_type_ext v] formats v *)
8 |
9 | val pp_type_ : Format.formatter -> Typesystem_types.type_ -> unit
10 | (** [pp_type_ v] formats v *)
11 |
12 | val pp_type_extension : Format.formatter -> Typesystem_types.type_extension -> unit
13 | (** [pp_type_extension v] formats v *)
14 |
15 | val pp_function_signature : Format.formatter -> Typesystem_types.function_signature -> unit
16 | (** [pp_function_signature v] formats v *)
17 |
--------------------------------------------------------------------------------
/Compiler/src/proto/typesystem_types.ml:
--------------------------------------------------------------------------------
1 | [@@@ocaml.warning "-27-30-39"]
2 |
3 |
4 | type type_ext =
5 | | Extension_idx of int32
6 | | Extension of type_extension
7 |
8 | and type_ = {
9 | definite_type : int32;
10 | possible_type : int32;
11 | ext : type_ext;
12 | }
13 |
14 | and type_extension = {
15 | properties : string list;
16 | methods : string list;
17 | group : string;
18 | signature : function_signature option;
19 | }
20 |
21 | and function_signature = {
22 | input_types : type_ list;
23 | output_type : type_ option;
24 | }
25 |
26 | let rec default_type_ext () : type_ext = Extension_idx (0l)
27 |
28 | and default_type_
29 | ?definite_type:((definite_type:int32) = 0l)
30 | ?possible_type:((possible_type:int32) = 0l)
31 | ?ext:((ext:type_ext) = Extension_idx (0l))
32 | () : type_ = {
33 | definite_type;
34 | possible_type;
35 | ext;
36 | }
37 |
38 | and default_type_extension
39 | ?properties:((properties:string list) = [])
40 | ?methods:((methods:string list) = [])
41 | ?group:((group:string) = "")
42 | ?signature:((signature:function_signature option) = None)
43 | () : type_extension = {
44 | properties;
45 | methods;
46 | group;
47 | signature;
48 | }
49 |
50 | and default_function_signature
51 | ?input_types:((input_types:type_ list) = [])
52 | ?output_type:((output_type:type_ option) = None)
53 | () : function_signature = {
54 | input_types;
55 | output_type;
56 | }
57 |
--------------------------------------------------------------------------------
/Compiler/src/proto/typesystem_types.mli:
--------------------------------------------------------------------------------
1 | (** typesystem.proto Types *)
2 |
3 |
4 |
5 | (** {2 Types} *)
6 |
7 | type type_ext =
8 | | Extension_idx of int32
9 | | Extension of type_extension
10 |
11 | and type_ = {
12 | definite_type : int32;
13 | possible_type : int32;
14 | ext : type_ext;
15 | }
16 |
17 | and type_extension = {
18 | properties : string list;
19 | methods : string list;
20 | group : string;
21 | signature : function_signature option;
22 | }
23 |
24 | and function_signature = {
25 | input_types : type_ list;
26 | output_type : type_ option;
27 | }
28 |
29 |
30 | (** {2 Default values} *)
31 |
32 | val default_type_ext : unit -> type_ext
33 | (** [default_type_ext ()] is the default value for type [type_ext] *)
34 |
35 | val default_type_ :
36 | ?definite_type:int32 ->
37 | ?possible_type:int32 ->
38 | ?ext:type_ext ->
39 | unit ->
40 | type_
41 | (** [default_type_ ()] is the default value for type [type_] *)
42 |
43 | val default_type_extension :
44 | ?properties:string list ->
45 | ?methods:string list ->
46 | ?group:string ->
47 | ?signature:function_signature option ->
48 | unit ->
49 | type_extension
50 | (** [default_type_extension ()] is the default value for type [type_extension] *)
51 |
52 | val default_function_signature :
53 | ?input_types:type_ list ->
54 | ?output_type:type_ option ->
55 | unit ->
56 | function_signature
57 | (** [default_function_signature ()] is the default value for type [function_signature] *)
58 |
--------------------------------------------------------------------------------
/Compiler/src/translate.mli:
--------------------------------------------------------------------------------
1 | (* Converts a Flow AST program to a program taken as input for protobuf generation*)
2 | val flow_ast_to_inst_list : (Loc.t, Loc.t) Flow_ast.Program.t -> bool -> bool -> bool -> Program_types.instruction list
--------------------------------------------------------------------------------
/Compiler/src/util.mli:
--------------------------------------------------------------------------------
1 | val string_to_flow_ast : string -> (Loc.t, Loc.t) Flow_ast.Program.t * (Loc.t * Parse_error.t) list
2 |
3 | val encode_newline : string -> string
4 |
5 | val convert_comp_op : Flow_ast.Expression.Binary.operator -> Operations_types.compare
6 |
7 | val is_compare_op : Flow_ast.Expression.Binary.operator -> bool
8 |
9 | val print_statement : ('M, 'T) Flow_ast.Statement.t -> string
10 |
11 | val print_unary_expression : ('M, 'T) Flow_ast.Expression.Unary.t -> string
12 |
13 | val print_unary_operator : Flow_ast.Expression.Unary.operator -> string
14 |
15 | val print_binary_operator : Flow_ast.Expression.Binary.operator -> string
16 |
17 | val print_logical_operator : Flow_ast.Expression.Logical.operator -> string
18 |
19 | val print_expression : ('M, 'T) Flow_ast.Expression.t -> string
20 |
21 | val print_statement_list: (('M, 'T) Flow_ast.Statement.t) list -> string
22 |
23 | val print_literal: ('T) Flow_ast.Literal.t -> string
24 |
25 | val trim_flow_ast_string : string -> string
26 |
27 | val write_proto_obj_to_file : Program_types.program -> string -> unit
28 |
29 | val inst_list_to_prog : Program_types.instruction list -> Program_types.program
30 |
31 | val regex_flag_str_to_int : string -> int32
32 |
33 | val is_supported_builtin : string -> bool -> bool
--------------------------------------------------------------------------------
/Compiler/supportedBuiltins.txt:
--------------------------------------------------------------------------------
1 | Reflect
2 | PrepareFunctionForOptimization
3 | Promise
4 | Infinity
5 | isNaN
6 | Int16Array
7 | Symbol
8 | Object
9 | Int32Array
10 | Map
11 | WeakMap
12 | isFinite
13 | parseInt
14 | Math
15 | Int8Array
16 | Set
17 | Function
18 | RegExp
19 | OptimizeOsr
20 | GetOptimizationStatus
21 | Uint32Array
22 | JSON
23 | String
24 | parseFloat
25 | WeakSet
26 | Uint8Array
27 | BigInt
28 | undefined
29 | NaN
30 | NeverOptimizeFunction
31 | DeoptimizeNow
32 | ToFastProperties
33 | Number
34 | Proxy
35 | ArrayBuffer
36 | gc
37 | DeoptimizeFunction
38 | OptimizeFunctionOnNextCall
39 | Float32Array
40 | eval
41 | Float64Array
42 | DataView
43 | Uint16Array
44 | Array
45 | this
46 | arguments
47 | Uint8ClampedArray
48 | Boolean
--------------------------------------------------------------------------------
/Compiler/test/array_assign.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 12;
6 | const v1 = [v0,v0,v0];
7 | const v2 = 10;
8 | v1[v2 + 20] = 30;"
9 |
10 | let correct =
11 | let builder = init_builder false false false in
12 | let int12_temp, load_int_12 = build_load_integer 12L builder in
13 | let array_temp, load_array = build_create_array [int12_temp; int12_temp; int12_temp] builder in
14 | let int10_temp, load_int_10 = build_load_integer 10L builder in
15 | let int20_temp, load_int_20 = build_load_integer 20L builder in
16 | let add_res_temp, add_inst = build_binary_op int10_temp int20_temp Plus builder in
17 | let int30_temp, load_int_30 = build_load_integer 30L builder in
18 | let store_comp_inst = build_store_computed_prop array_temp add_res_temp int30_temp builder in
19 | let res = [load_int_12; load_array; load_int_10; load_int_20; add_inst; load_int_30; store_comp_inst] in
20 | List.map inst_to_prog_inst res
21 |
22 | let test () =
23 | let (ast, errors) = Compiler.string_to_flow_ast input in
24 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
25 | Alcotest.(check (list Util.inst_testable)) "array_assign" correct prog
--------------------------------------------------------------------------------
/Compiler/test/array_assign_sugared.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 12;
6 | const v1 = [v0,v0,v0];
7 | const v2 = 10;
8 | v1[v2 + 20] += 30;"
9 |
10 | let correct =
11 | let builder = init_builder false false false in
12 | let int12_temp, load_int_12 = build_load_integer 12L builder in
13 | let array_temp, load_array = build_create_array [int12_temp; int12_temp; int12_temp] builder in
14 | let int10_temp, load_int_10 = build_load_integer 10L builder in
15 | let int20_temp, load_int_20 = build_load_integer 20L builder in
16 | let add_res_temp, add_inst = build_binary_op int10_temp int20_temp Plus builder in
17 | let int30_temp, load_int_30 = build_load_integer 30L builder in
18 | let comp_prop_temp, load_comp_prop_inst = build_load_computed_prop array_temp add_res_temp builder in
19 | let add_res_temp2, add_inst2 = build_binary_op comp_prop_temp int30_temp Plus builder in
20 | let store_comp_inst = build_store_computed_prop array_temp add_res_temp add_res_temp2 builder in
21 | let res = [load_int_12; load_array; load_int_10; load_int_20; add_inst; load_int_30; load_comp_prop_inst; add_inst2; store_comp_inst] in
22 | List.map inst_to_prog_inst res
23 |
24 | let test () =
25 | let (ast, errors) = Compiler.string_to_flow_ast input in
26 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
27 | Alcotest.(check (list Util.inst_testable)) "array_assign_sugared" correct prog
--------------------------------------------------------------------------------
/Compiler/test/array_decl.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "var [r, g, f] = [20, 15, 35];
6 | "
7 |
8 | let correct =
9 | let builder = init_builder false false false in
10 | let _, l0_inst = build_load_integer 20L builder in
11 | let _, l1_inst = build_load_integer 15L builder in
12 | let _, l2_inst = build_load_integer 35L builder in
13 | let res = [l0_inst; l1_inst; l2_inst] in
14 | List.map inst_to_prog_inst res
15 |
16 | let test () =
17 | let (ast, errors) = Compiler.string_to_flow_ast input in
18 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
19 | Alcotest.(check (list Util.inst_testable)) "array_decl" correct prog
20 |
--------------------------------------------------------------------------------
/Compiler/test/array_hole.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "let a = [1,,1];"
6 |
7 | let correct =
8 | let builder = init_builder false false false in
9 | let int_temp, load_int = build_load_integer 1L builder in
10 | let undef_temp, load_undef_inst = build_load_undefined builder in
11 | let int_temp2, load_int_2 = build_load_integer 1L builder in
12 | let _, create_array_inst = build_create_array [int_temp; undef_temp; int_temp2] builder in
13 | let res = [load_int; load_undef_inst; load_int_2; create_array_inst] in
14 | List.map inst_to_prog_inst res
15 | let test () =
16 | let (ast, errors) = Compiler.string_to_flow_ast input in
17 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
18 | Alcotest.(check (list Util.inst_testable)) "array_hole" correct prog
--------------------------------------------------------------------------------
/Compiler/test/array_spread.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 0;
6 | const v1 = [v0,...v0,];"
7 |
8 | let correct =
9 | let builder = init_builder false false false in
10 | let int_temp, load_int = build_load_integer 0L builder in
11 | let _, create_array_inst = build_create_array_with_spread [int_temp; int_temp] [false; true] builder in
12 | let res = [load_int; create_array_inst] in
13 | List.map inst_to_prog_inst res
14 |
15 | let test () =
16 | let (ast, errors) = Compiler.string_to_flow_ast input in
17 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
18 | Alcotest.(check (list Util.inst_testable)) "array_spread" correct prog
--------------------------------------------------------------------------------
/Compiler/test/basic_break.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 | let input =
4 | "const v0 = 1;
5 | while(v0){
6 | break;
7 | }"
8 |
9 | let correct =
10 | let builder = init_builder false false false in
11 | let int_temp, load_int = build_load_integer 1L builder in
12 | let int_temp0, load_int0 = build_load_integer 0L builder in
13 | let begin_while_inst = build_begin_while int_temp int_temp0 NotEqual builder in
14 | let break_inst = build_break_op builder in
15 | let reassign_inst = build_reassign_op int_temp int_temp builder in
16 | let end_while_inst = build_end_while builder in
17 | let res = [load_int; load_int0; begin_while_inst; break_inst; reassign_inst; end_while_inst] in
18 | List.map inst_to_prog_inst res
19 |
20 | let test () =
21 | let (ast, errors) = Compiler.string_to_flow_ast input in
22 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
23 | Alcotest.(check (list Util.inst_testable)) "basic_break" correct prog
--------------------------------------------------------------------------------
/Compiler/test/basic_compare_test.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 1 == 1;
6 | const v1 = 1 === 1;
7 | const v2 = 2 >= 2;
8 | const v3 = 7 < 9;"
9 |
10 | let correct =
11 | let builder = init_builder false false false in
12 | let int_1, load_1 = build_load_integer 1L builder in
13 | let int_1_2, load_1_2 = build_load_integer 1L builder in
14 | let _, equal_inst = build_compare_op int_1 int_1_2 Equal builder in
15 | let int_1_3, load_1_3 = build_load_integer 1L builder in
16 | let int_1_4, load_1_4 = build_load_integer 1L builder in
17 | let _, strict_equal_inst = build_compare_op int_1_3 int_1_4 StrictEqual builder in
18 | let int_2_0, load_2_0 = build_load_integer 2L builder in
19 | let int_2_1, load_2_1 = build_load_integer 2L builder in
20 | let _, greater_eq_inst = build_compare_op int_2_0 int_2_1 GreaterThanEqual builder in
21 | let int_7, load_7 = build_load_integer 7L builder in
22 | let int_9, load_9 = build_load_integer 9L builder in
23 | let _, less_than_inst = build_compare_op int_7 int_9 LessThan builder in
24 | let res = [load_1; load_1_2; equal_inst; load_1_3; load_1_4; strict_equal_inst; load_2_0; load_2_1; greater_eq_inst; load_7; load_9; less_than_inst] in
25 | List.map inst_to_prog_inst res
26 |
27 | let test () =
28 | let (ast, errors) = Compiler.string_to_flow_ast input in
29 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
30 | Alcotest.(check (list Util.inst_testable)) "basic_compare_test" correct prog
--------------------------------------------------------------------------------
/Compiler/test/basic_continue.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "while(1){
6 | continue;
7 | }
8 | "
9 |
10 | let correct =
11 | let builder = init_builder false false false in
12 | let int_temp_1, load_int1 = build_load_integer 1L builder in
13 | let int_temp_0, load_int0 = build_load_integer 0L builder in
14 | let begin_while = build_begin_while int_temp_1 int_temp_0 NotEqual builder in
15 | let continue_inst = build_continue builder in
16 | let int_temp_1_2, load_int2 = build_load_integer 1L builder in
17 | let reassign_inst = build_reassign_op int_temp_1 int_temp_1_2 builder in
18 | let end_while = build_end_while builder in
19 | let res = [load_int1; load_int0; begin_while; continue_inst; load_int2; reassign_inst; end_while] in
20 | List.map inst_to_prog_inst res
21 |
22 | let test () =
23 | let (ast, errors) = Compiler.string_to_flow_ast input in
24 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
25 | Alcotest.(check (list Util.inst_testable)) "basic_continue" correct prog
--------------------------------------------------------------------------------
/Compiler/test/basic_for.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "for(let v0 = 2; v0 < 10; v0 = v0 + 1){
6 | let v2 = v0 + 12;
7 | }"
8 |
9 | let correct =
10 | let builder = init_builder false false false in
11 | let int_2_temp, load_int2 = build_load_integer 2L builder in
12 | let int_10_temp, load_int10 = build_load_integer 10L builder in
13 | let compare_temp, first_compare_inst = build_compare_op int_2_temp int_10_temp LessThan builder in
14 | let int_0_temp, load_int0 = build_load_integer 0L builder in
15 | let begin_while = build_begin_while compare_temp int_0_temp NotEqual builder in
16 | let int_12_temp, load_int12 = build_load_integer 12L builder in
17 | let add_temp, add_inst = build_binary_op int_2_temp int_12_temp Plus builder in
18 | let int_1_temp, load_int1 = build_load_integer 1L builder in
19 | let add_temp2, add_inst2 = build_binary_op int_2_temp int_1_temp Plus builder in
20 | let reassign_op = build_reassign_op int_2_temp add_temp2 builder in
21 | let int_10_temp2, load_int102 = build_load_integer 10L builder in
22 | let compare_temp2, second_compare_inst = build_compare_op int_2_temp int_10_temp2 LessThan builder in
23 | let reassign_op2 = build_reassign_op compare_temp compare_temp2 builder in
24 | let end_while = build_end_while builder in
25 | let res = [load_int2; load_int10; first_compare_inst; load_int0; begin_while; load_int12; add_inst; load_int1; add_inst2; reassign_op; load_int102; second_compare_inst; reassign_op2; end_while] in
26 | List.map inst_to_prog_inst res
27 |
28 | let test () =
29 | let (ast, errors) = Compiler.string_to_flow_ast input in
30 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
31 | Alcotest.(check (list Util.inst_testable)) "basic_for" correct prog
32 |
--------------------------------------------------------------------------------
/Compiler/test/basic_func_call.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = isNaN(0);"
6 |
7 | let correct =
8 | let builder = init_builder false false false in
9 | let builtin_temp, load_builtin = build_load_builtin "isNaN" builder in
10 | let temp_0, load_int = build_load_integer 0L builder in
11 | let _, call_inst = build_call builtin_temp [temp_0] builder in
12 | let res = [load_builtin; load_int; call_inst] in
13 | List.map inst_to_prog_inst res
14 |
15 | let test () =
16 | let (ast, errors) = Compiler.string_to_flow_ast input in
17 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
18 | Alcotest.(check (list Util.inst_testable)) "basic_func_call" correct prog
--------------------------------------------------------------------------------
/Compiler/test/basic_func_ret.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "function v1(v2,v3) {
6 | let v4 = v2 * v3;
7 | return v4;
8 | }
9 | "
10 |
11 | let correct =
12 | let builder = init_builder false false false in
13 | let func_temp = get_new_intermed_temp builder in
14 | let _, begin_func_inst, end_func_inst = build_func_ops func_temp ["v2"; "v3"] None false false false builder in
15 | (* TODO: This needs to be updated along with the function builder interface *)
16 | let v2_temp = match lookup_var_name builder "v2" with
17 | InScope x -> x
18 | | NotFound -> raise (Invalid_argument "improper variable lookup") in
19 | let v3_temp = match lookup_var_name builder "v3" with
20 | InScope x -> x
21 | | NotFound -> raise (Invalid_argument "improper variable lookup") in
22 | let bin_temp, bin_inst = build_binary_op v2_temp v3_temp Mult builder in
23 | let ret_inst = build_return_op bin_temp builder in
24 | let res = [begin_func_inst; bin_inst; ret_inst; end_func_inst] in
25 | List.map inst_to_prog_inst res
26 |
27 | let test () =
28 | let (ast, errors) = Compiler.string_to_flow_ast input in
29 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
30 | Alcotest.(check (list Util.inst_testable)) "basic_func_ret" correct prog
--------------------------------------------------------------------------------
/Compiler/test/basic_while.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "let v0 = 0;
6 | const v1 = 20;
7 | while(v0 <= v1){
8 | v0 += 1;
9 | }"
10 |
11 | let correct =
12 | let builder = init_builder false false false in
13 | let int_0, load_int_0 = build_load_integer 0L builder in
14 | let int_20, load_int_20 = build_load_integer 20L builder in
15 | let compare_temp, compare_inst_0 = build_compare_op int_0 int_20 LessThanEqual builder in
16 | let int_0_2, load_int_0_2 = build_load_integer 0L builder in
17 | let begin_while = build_begin_while compare_temp int_0_2 NotEqual builder in
18 | let int_1, load_int_1 = build_load_integer 1L builder in
19 | let bin_temp, bin_op = build_binary_op int_0 int_1 Plus builder in
20 | let reassign_op = build_reassign_op int_0 bin_temp builder in
21 | let compare_temp2, compare_inst2 = build_compare_op int_0 int_20 LessThanEqual builder in
22 | let reassign_op2 = build_reassign_op compare_temp compare_temp2 builder in
23 | let end_while = build_end_while builder in
24 | let res = [load_int_0; load_int_20; compare_inst_0; load_int_0_2; begin_while; load_int_1; bin_op; reassign_op; compare_inst2; reassign_op2; end_while] in
25 | List.map inst_to_prog_inst res
26 |
27 | let test () =
28 | let (ast, errors) = Compiler.string_to_flow_ast input in
29 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
30 | Alcotest.(check (list Util.inst_testable)) "basic_while" correct prog
--------------------------------------------------------------------------------
/Compiler/test/bitwise_ops.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 1 | 2;
6 | const v1 = 3 & 4;
7 | "
8 |
9 | let correct =
10 | let builder = init_builder false false false in
11 | let temp_1, load_1_temp = build_load_integer 1L builder in
12 | let temp_2, load_2_temp = build_load_integer 2L builder in
13 | let _, or_inst = build_binary_op temp_1 temp_2 BitOr builder in
14 | let temp_3, load_3_temp = build_load_integer 3L builder in
15 | let temp_4, load_4_temp = build_load_integer 4L builder in
16 | let _, and_inst = build_binary_op temp_3 temp_4 BitAnd builder in
17 | let res = [load_1_temp; load_2_temp; or_inst; load_3_temp; load_4_temp; and_inst] in
18 | List.map inst_to_prog_inst res
19 |
20 | let test () =
21 | let (ast, errors) = Compiler.string_to_flow_ast input in
22 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
23 | Alcotest.(check (list Util.inst_testable)) "bitwise_ops" correct prog
--------------------------------------------------------------------------------
/Compiler/test/create_array.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 15;
6 | const v1 = 20;
7 | const v2 = [v1,v0];
8 | "
9 |
10 | let correct =
11 | let builder = init_builder false false false in
12 | let int_15_temp, load_int_15 = build_load_integer 15L builder in
13 | let int_20_temp, load_int_20 = build_load_integer 20L builder in
14 | let _, create_array = build_create_array [int_20_temp; int_15_temp] builder in
15 | let res = [load_int_15; load_int_20; create_array] in
16 | List.map inst_to_prog_inst res
17 |
18 | let test () =
19 | let (ast, errors) = Compiler.string_to_flow_ast input in
20 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
21 | Alcotest.(check (list Util.inst_testable)) "create_array" correct prog
--------------------------------------------------------------------------------
/Compiler/test/del_test.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 |
5 | let input =
6 | "const v0 = 1337;
7 | const v1 = [v0];
8 | delete v1[0];
9 | const v10 = \"function\";
10 | delete v10.length;
11 | "
12 |
13 | let correct =
14 | let builder = init_builder false false false in
15 | let int1337, load_1337 = build_load_integer 1337L builder in
16 | let arr_temp, build_array = build_create_array [int1337] builder in
17 | let zero_temp, load_zero_temp = build_load_integer 0L builder in
18 | let _, del_inst = build_delete_computed_prop arr_temp zero_temp builder in
19 | let string_temp, load_string_temp = build_load_string "function" builder in
20 | let _, del_inst2 = build_delete_prop string_temp "length" builder in
21 | let res = [load_1337; build_array; load_zero_temp; del_inst; load_string_temp; del_inst2] in
22 | List.map inst_to_prog_inst res
23 |
24 | let test () =
25 | let (ast, errors) = Compiler.string_to_flow_ast input in
26 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
27 | Alcotest.(check (list Util.inst_testable)) "del_test" correct prog
--------------------------------------------------------------------------------
/Compiler/test/do_while.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "let v0 = 0;
6 | do{
7 | v0 = v0 + 1;
8 | }while(v0 < 10);
9 | "
10 |
11 | let correct =
12 | let builder = init_builder false false false in
13 |
14 | let int_0, load_int_0 = build_load_integer 0L builder in
15 | let int_0_1, load_int_0_1 = build_load_integer 0L builder in
16 | let dup_var, dup_inst = build_dup_op int_0_1 builder in
17 | let do_while_inst = build_begin_do_while dup_var int_0_1 NotEqual builder in
18 | let int_1, load_int_1 = build_load_integer 1L builder in
19 | let add_temp, add_inst = build_binary_op int_0 int_1 Plus builder in
20 | let reassign_inst = build_reassign_op int_0 add_temp builder in
21 | let int_10, load_int_10 = build_load_integer 10L builder in
22 | let compare_temp, compare_inst = build_compare_op int_0 int_10 LessThan builder in
23 | let reassign_inst_2 = build_reassign_op dup_var compare_temp builder in
24 | let end_do_while_inst = build_end_do_while builder in
25 | let res = [load_int_0; load_int_0_1; dup_inst; do_while_inst; load_int_1; add_inst; reassign_inst; load_int_10;
26 | compare_inst; reassign_inst_2; end_do_while_inst] in
27 | List.map inst_to_prog_inst res
28 |
29 | let test () =
30 | let (ast, errors) = Compiler.string_to_flow_ast input in
31 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
32 | Alcotest.(check (list Util.inst_testable)) "do_while" correct prog
--------------------------------------------------------------------------------
/Compiler/test/dune:
--------------------------------------------------------------------------------
1 | (executable
2 | (name test)
3 | (public_name test)
4 | (libraries alcotest compiler)
5 | (preprocess (pps ppx_deriving.show)))
--------------------------------------------------------------------------------
/Compiler/test/empty_assignment_scope.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "
6 | var x;
7 | while (x != 0) {
8 | x = 1;
9 | }
10 | "
11 |
12 | let correct =
13 | let builder = init_builder false false false in
14 | let undef_temp, undef_inst = build_load_undefined builder in
15 | let dup_temp, dup_inst = build_dup_op undef_temp builder in
16 | let compare_target_temp, build_compare_target = build_load_integer 0L builder in
17 | let compare_res_temp, build_compare = build_compare_op dup_temp compare_target_temp NotEqual builder in
18 | let zero_temp, load_zero_temp = build_load_integer 0L builder in
19 | let begin_while_inst = build_begin_while compare_res_temp zero_temp NotEqual builder in
20 | let one_temp, load_one_temp = build_load_integer 1L builder in
21 | let reassign_inst = build_reassign_op dup_temp one_temp builder in
22 | let second_compare_target_temp, build_second_compare_target_inst = build_load_integer 0L builder in
23 | let second_compare_temp, build_second_compare_inst = build_compare_op dup_temp second_compare_target_temp NotEqual builder in
24 | let second_reassign_inst = build_reassign_op compare_res_temp second_compare_temp builder in
25 | let end_while_inst = build_end_while builder in
26 | let res = [undef_inst; dup_inst; build_compare_target; build_compare; load_zero_temp; begin_while_inst; load_one_temp; reassign_inst;
27 | build_second_compare_target_inst; build_second_compare_inst; second_reassign_inst; end_while_inst ] in
28 | List.map inst_to_prog_inst res
29 |
30 | let test () =
31 | let (ast, errors) = Compiler.string_to_flow_ast input in
32 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
33 | Alcotest.(check (list Util.inst_testable)) "empty_assignment_scope" correct prog
34 |
--------------------------------------------------------------------------------
/Compiler/test/exp_statement.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "let v0 = 0;
6 | const v1 = 5;
7 | v0 = v1 + 1;
8 | "
9 |
10 | let correct =
11 | let builder = init_builder false false false in
12 | let int_0, load_int_0 = build_load_integer 0L builder in
13 | let int_5, load_int_5 = build_load_integer 5L builder in
14 | let int_1, load_int_1 = build_load_integer 1L builder in
15 | let bin_temp, bin_inst = build_binary_op int_5 int_1 Plus builder in
16 | let reassign_inst = build_reassign_op int_0 bin_temp builder in
17 | let res = [load_int_0; load_int_5; load_int_1; bin_inst; reassign_inst] in
18 | List.map inst_to_prog_inst res
19 |
20 | let test () =
21 | let (ast, errors) = Compiler.string_to_flow_ast input in
22 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
23 | Alcotest.(check (list Util.inst_testable)) "exp_statement" correct prog
24 |
--------------------------------------------------------------------------------
/Compiler/test/for_in.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 |
5 | let input =
6 | "const v0 = 12;
7 | const v1 = [v0,v0,v0,v0,v0];
8 | for (const v2 in v1) {
9 | let v3 = v2;
10 | isNaN(v3);
11 | }"
12 |
13 | let correct =
14 | let builder = init_builder false false false in
15 | let int_12, load_int_12 = build_load_integer 12L builder in
16 | let arr_temp, create_arr_inst = build_create_array [int_12; int_12; int_12; int_12; int_12] builder in
17 | let left_temp = get_new_intermed_temp builder in
18 | let _, begin_for_in = build_begin_for_in_op left_temp arr_temp builder in
19 | let builtin_temp, load_builtin = build_load_builtin "isNaN" builder in
20 | let _, call_inst = build_call builtin_temp [left_temp] builder in
21 | let end_for_in = build_end_for_in_op builder in
22 | let res = [load_int_12; create_arr_inst; begin_for_in; load_builtin; call_inst; end_for_in] in
23 | List.map inst_to_prog_inst res
24 |
25 | let test () =
26 | let (ast, errors) = Compiler.string_to_flow_ast input in
27 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
28 | Alcotest.(check (list Util.inst_testable)) "for_in_scoping" correct prog
29 |
--------------------------------------------------------------------------------
/Compiler/test/for_in_scope2.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "for (var x in x) {
6 | function x() {
7 | ;
8 | }
9 | let a = x();
10 | }
11 | "
12 |
13 | let correct =
14 | let builder = init_builder false false false in
15 | let placeholder_temp, load_placeholder = build_load_builtin "placeholder" builder in
16 | let temp = get_new_intermed_temp builder in
17 | let _, begin_for_in = build_begin_for_in_op temp placeholder_temp builder in
18 | let func_temp = get_new_intermed_temp builder in
19 | let func_temp2, begin_func_inst, end_func_inst = build_func_ops func_temp [] None false false false builder in
20 | let _, call_inst = build_call func_temp2 [] builder in
21 | let end_for_in = build_end_for_in_op builder in
22 | let res = [load_placeholder; begin_for_in; begin_func_inst; end_func_inst; call_inst; end_for_in] in
23 | List.map inst_to_prog_inst res
24 |
25 | let test () =
26 | let (ast, errors) = Compiler.string_to_flow_ast input in
27 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
28 | Alcotest.(check (list Util.inst_testable)) "for_in_scope2" correct prog
29 |
--------------------------------------------------------------------------------
/Compiler/test/for_in_scoping.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "let i = \"ABC\"
6 | for (i in [0]) {
7 | }
8 | let b = i + \"D\";"
9 |
10 | (* Note: Fuzzilli does not support using an existing var *)
11 | let correct =
12 | let builder = init_builder false false false in
13 | let string_temp, load_string_inst = build_load_string "ABC" builder in
14 | let int_temp, load_int_inst = build_load_integer 0L builder in
15 | let arr_temp, load_array_inst = build_create_array [int_temp] builder in
16 | let left_for_in = get_new_intermed_temp builder in
17 | let _, begin_for_in_inst = build_begin_for_in_op left_for_in arr_temp builder in
18 | let reassign_inst = build_reassign_op string_temp left_for_in builder in
19 | let end_for_in_inst = build_end_for_in_op builder in
20 | let string_temp2, load_string_inst2 = build_load_string "D" builder in
21 | let add_temp, add_inst = build_binary_op string_temp string_temp2 Plus builder in
22 | let res = [load_string_inst; load_int_inst; load_array_inst; begin_for_in_inst; reassign_inst; end_for_in_inst; load_string_inst2; add_inst] in
23 | List.map inst_to_prog_inst res
24 |
25 | let test () =
26 | let (ast, errors) = Compiler.string_to_flow_ast input in
27 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
28 | Alcotest.(check (list Util.inst_testable)) "for_in_scoping" correct prog
29 |
--------------------------------------------------------------------------------
/Compiler/test/for_of.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 20;
6 | const v1 = [v0,v0,v0,v0,v0];
7 | for (const v2 of v1){
8 | isNaN(v2);
9 | }"
10 |
11 | let correct =
12 | let builder = init_builder false false false in
13 | let int_20, load_int_20 = build_load_integer 20L builder in
14 | let array_temp, create_array_inst = build_create_array [int_20; int_20; int_20; int_20; int_20] builder in
15 | let begin_for_of_temp, begin_for_of_inst = build_begin_for_of_op array_temp builder in
16 | let isNan_temp, load_IsNaN = build_load_builtin "isNaN" builder in
17 | let _, call_inst = build_call isNan_temp [begin_for_of_temp] builder in
18 | let end_for_of = build_end_for_of_op builder in
19 | let res = [load_int_20; create_array_inst; begin_for_of_inst; load_IsNaN; call_inst; end_for_of] in
20 | List.map inst_to_prog_inst res
21 |
22 | let test () =
23 | let (ast, errors) = Compiler.string_to_flow_ast input in
24 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
25 | Alcotest.(check (list Util.inst_testable)) "for_of" correct prog
26 |
--------------------------------------------------------------------------------
/Compiler/test/func_call_with_spread.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "function test(v0, ...v101){
6 | return v0 + v101[0];
7 | }
8 | const v5 = [0,1];
9 | const v17 = test(10,...v5);
10 | "
11 |
12 | let correct =
13 | let builder = init_builder false false false in
14 | let func_temp = get_new_intermed_temp builder in
15 | let _, begin_func_inst, end_func_inst = build_func_ops func_temp ["v0"] (Some "v101") false false false builder in
16 | (* TODO: Update this along with the function interface *)
17 | let v0_temp = match lookup_var_name builder "v0" with
18 | InScope x -> x
19 | | NotFound -> raise (Invalid_argument "improper variable lookup") in
20 | let v101_temp = match lookup_var_name builder "v101" with
21 | InScope x -> x
22 | | NotFound -> raise (Invalid_argument "improper variable lookup") in
23 | let elem_temp, load_elem_inst = build_load_element v101_temp 0 builder in
24 | let bin_temp, bin_inst = build_binary_op v0_temp elem_temp Plus builder in
25 | let ret_inst = build_return_op bin_temp builder in
26 |
27 | let int_0, load_int_0 = build_load_integer 0L builder in
28 | let int_1, load_int_1 = build_load_integer 1L builder in
29 |
30 | let arr_temp, create_arr_temp = build_create_array [int_0; int_1] builder in
31 | let int_10, load_int_10 = build_load_integer 10L builder in
32 | let _, call_inst = build_call_with_spread func_temp [int_10; arr_temp] [false; true] builder in
33 | let res = [begin_func_inst; load_elem_inst; bin_inst; ret_inst; end_func_inst; load_int_0; load_int_1; create_arr_temp; load_int_10; call_inst] in
34 | List.map inst_to_prog_inst res
35 |
36 | let test () =
37 | let (ast, errors) = Compiler.string_to_flow_ast input in
38 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
39 | Alcotest.(check (list Util.inst_testable)) "func_call_with_spread" correct prog
--------------------------------------------------------------------------------
/Compiler/test/func_dec_order.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "function b() {a();}
6 | function a() {
7 | return 7;
8 | }
9 | "
10 |
11 | let correct =
12 | let builder = init_builder false false false in
13 | let undef_temp, load_undef_inst = build_load_undefined builder in
14 | let func_temp = get_new_intermed_temp builder in
15 | let _, begin_func_inst, end_func_inst = build_func_ops func_temp [] None false false false builder in
16 | let _, call_inst = build_call undef_temp [] builder in
17 | let func_temp2 = get_new_intermed_temp builder in
18 | let _, begin_func_inst_2, end_func_inst_2 = build_func_ops func_temp2 [] None false false false builder in
19 | let int_temp, load_int_inst = build_load_integer 7L builder in
20 | let ret_inst = build_return_op int_temp builder in
21 | let reassign_inst = build_reassign_op undef_temp func_temp2 builder in
22 | let res = [load_undef_inst; begin_func_inst; call_inst; end_func_inst; begin_func_inst_2; load_int_inst; ret_inst; end_func_inst_2; reassign_inst ] in
23 | List.map inst_to_prog_inst res
24 |
25 | let test () =
26 | let (ast, errors) = Compiler.string_to_flow_ast input in
27 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
28 | Alcotest.(check (list Util.inst_testable)) "func_dec_order" correct prog
--------------------------------------------------------------------------------
/Compiler/test/func_exp_test.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = function () { const v1 = 12; return v1;}
6 | const v2 = v0();
7 | "
8 |
9 | let correct =
10 | let builder = init_builder false false false in
11 | (* TODO: This needs to be updated along with the function builder interface *)
12 | let func_temp = get_new_intermed_temp builder in
13 | let _, begin_func_inst, end_func_inst = build_func_ops func_temp [] None false false false builder in
14 | let int_12, load_int_12 = build_load_integer 12L builder in
15 | let return_inst = build_return_op int_12 builder in
16 | let _, call_inst = build_call func_temp [] builder in
17 | let res = [begin_func_inst; load_int_12; return_inst; end_func_inst; call_inst] in
18 | List.map inst_to_prog_inst res
19 |
20 | let test () =
21 | let (ast, errors) = Compiler.string_to_flow_ast input in
22 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
23 | Alcotest.(check (list Util.inst_testable)) "func_exp_test" correct prog
--------------------------------------------------------------------------------
/Compiler/test/func_param_scoping.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 |
5 | let input =
6 | "function test(a) {
7 | a[0] = 1.5;
8 | }
9 | a = new Array();"
10 |
11 | let correct =
12 | let builder = init_builder false false false in
13 | let func_temp = get_new_intermed_temp builder in
14 | let _, begin_func_inst, end_func_inst = build_func_ops func_temp ["a"] None false false false builder in
15 | (* TODO: This needs to be updated along with the function builder interface *)
16 | let a_temp = match lookup_var_name builder "a" with
17 | InScope x -> x
18 | | NotFound -> raise (Invalid_argument "improper variable lookup") in
19 |
20 | let int_0, load_int_0 = build_load_integer 0L builder in
21 | let float_15, load_float = build_load_float 1.5 builder in
22 | let store_inst = build_store_computed_prop a_temp int_0 float_15 builder in
23 | let array_builtin, load_builtin_inst = build_load_builtin "Array" builder in
24 | let construct_temp, construct_inst = build_new_object array_builtin [] builder in
25 | let _, dup_op = build_dup_op construct_temp builder in
26 | let res = [begin_func_inst; load_int_0; load_float; store_inst; end_func_inst; load_builtin_inst; construct_inst; dup_op] in
27 | List.map inst_to_prog_inst res
28 |
29 | let test () =
30 | let (ast, errors) = Compiler.string_to_flow_ast input in
31 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
32 | Alcotest.(check (list Util.inst_testable)) "func_param_scoping" correct prog
--------------------------------------------------------------------------------
/Compiler/test/if_else.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "if(1){
6 | const v0 = 3;
7 | } else if(2){
8 | const v1 = 4;
9 | } else {
10 | const v2 = 5;
11 | }
12 | "
13 | let correct =
14 | let builder = init_builder false false false in
15 | let int_1, load_int_1 = build_load_integer 1L builder in
16 | let begin_if_inst_1 = build_begin_if int_1 builder in
17 | let int_3, load_int_3 = build_load_integer 3L builder in
18 | let else_inst = build_begin_else builder in
19 | let int_2, load_int_2 = build_load_integer 2L builder in
20 | let begin_if_inst_2 = build_begin_if int_2 builder in
21 | let int_4, load_int_4 = build_load_integer 4L builder in
22 | let int_5, load_int_5 = build_load_integer 5L builder in
23 | let end_if_inst = build_end_if builder in
24 | let res = [load_int_1; begin_if_inst_1; load_int_3; else_inst; load_int_2; begin_if_inst_2; load_int_4; else_inst;
25 | load_int_5; end_if_inst; end_if_inst] in
26 | List.map inst_to_prog_inst res
27 |
28 | let test () =
29 | let (ast, errors) = Compiler.string_to_flow_ast input in
30 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
31 | Alcotest.(check (list Util.inst_testable)) "if_else" correct prog
32 |
--------------------------------------------------------------------------------
/Compiler/test/in_test.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 10;
6 | const v3 = [15,20];
7 | const v4 = v0 in v3;
8 | "
9 |
10 | let correct =
11 | let builder = init_builder false false false in
12 | let int_10, load_int_10 = build_load_integer 10L builder in
13 | let int_15, load_int_15 = build_load_integer 15L builder in
14 | let int_20, load_int_20 = build_load_integer 20L builder in
15 | let array_temp, create_array_inst = build_create_array [int_15; int_20] builder in
16 | let _, in_inst = build_in_op int_10 array_temp builder in
17 | let res = [load_int_10; load_int_15; load_int_20; create_array_inst; in_inst] in
18 | List.map inst_to_prog_inst res
19 |
20 | let test () =
21 | let (ast, errors) = Compiler.string_to_flow_ast input in
22 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
23 | Alcotest.(check (list Util.inst_testable)) "in_test" correct prog
24 |
--------------------------------------------------------------------------------
/Compiler/test/instance_of.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 1;
6 | const v1 = 2;
7 | const v2 = v1 instanceof v0;
8 | "
9 |
10 | let correct =
11 | let builder = init_builder false false false in
12 | let int_1, load_int_1 = build_load_integer 1L builder in
13 | let int_2, load_int_2 = build_load_integer 2L builder in
14 | let _, instance_inst = build_instanceof_op int_2 int_1 builder in
15 | let res = [load_int_1; load_int_2; instance_inst] in
16 | List.map inst_to_prog_inst res
17 |
18 | let test () =
19 | let (ast, errors) = Compiler.string_to_flow_ast input in
20 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
21 | Alcotest.(check (list Util.inst_testable)) "instance_of" correct prog
22 |
--------------------------------------------------------------------------------
/Compiler/test/load_array_index.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v3 = [0,1,2];
6 | const v5 = v3[0];
7 | const v7 = v3[v5];"
8 |
9 | let correct =
10 | let builder = init_builder false false false in
11 | let int_0, load_int_0 = build_load_integer 0L builder in
12 | let int_1, load_int_1 = build_load_integer 1L builder in
13 | let int_2, load_int_2 = build_load_integer 2L builder in
14 | let arr_temp, create_arr = build_create_array [int_0; int_1; int_2] builder in
15 | let elem_temp, load_elem_inst = build_load_element arr_temp 0 builder in
16 | let _, load_comp_elem_inst = build_load_computed_prop arr_temp elem_temp builder in
17 | let res = [load_int_0; load_int_1; load_int_2; create_arr; load_elem_inst; load_comp_elem_inst] in
18 | List.map inst_to_prog_inst res
19 |
20 | let test () =
21 | let (ast, errors) = Compiler.string_to_flow_ast input in
22 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
23 | Alcotest.(check (list Util.inst_testable)) "load_array_index" correct prog
--------------------------------------------------------------------------------
/Compiler/test/load_bigint.ml:
--------------------------------------------------------------------------------
1 | open Compiler.ProgramBuilder
2 | open Program_types
3 |
4 | let input =
5 | "const v0 = 9007199254740991n;"
6 |
7 | let correct =
8 | let builder = init_builder false false false in
9 | let _, load_big_int_inst = build_load_bigInt 9007199254740991.0 builder in
10 | let res = [load_big_int_inst] in
11 | List.map inst_to_prog_inst res
12 |
13 | let test () =
14 | let (ast, errors) = Compiler.string_to_flow_ast input in
15 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
16 | Alcotest.(check (list Util.inst_testable)) "load_bigint" correct prog
--------------------------------------------------------------------------------
/Compiler/test/load_bool.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = true;
6 | const v1 = false;"
7 |
8 | let correct =
9 | let builder = init_builder false false false in
10 | let _, load_true = build_load_bool true builder in
11 | let _, load_false = build_load_bool false builder in
12 | let res = [load_true; load_false] in
13 | List.map inst_to_prog_inst res
14 |
15 | let test () =
16 | let (ast, errors) = Compiler.string_to_flow_ast input in
17 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
18 | Alcotest.(check (list Util.inst_testable)) "load_bool" correct prog
--------------------------------------------------------------------------------
/Compiler/test/load_float.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 20.15;"
6 |
7 | let correct =
8 | let builder = init_builder false false false in
9 | let _, inst = build_load_float 20.15 builder in
10 | let res = [inst] in
11 | List.map inst_to_prog_inst res
12 |
13 | let test () =
14 | let (ast, errors) = Compiler.string_to_flow_ast input in
15 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
16 | Alcotest.(check (list Util.inst_testable)) "load_float" correct prog
--------------------------------------------------------------------------------
/Compiler/test/load_infinity.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = Infinity;"
6 |
7 | let correct =
8 | let builder = init_builder false false false in
9 | let _, inst = build_load_float infinity builder in
10 | let res = [inst] in
11 | List.map inst_to_prog_inst res
12 |
13 | let test () =
14 | let (ast, errors) = Compiler.string_to_flow_ast input in
15 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
16 | Alcotest.(check (list Util.inst_testable)) "load_infinity" correct prog
--------------------------------------------------------------------------------
/Compiler/test/load_null.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = null;"
6 |
7 | let correct =
8 | let builder = init_builder false false false in
9 | let _, load_null = build_load_null builder in
10 | let res = [load_null] in
11 | List.map inst_to_prog_inst res
12 |
13 | let test () =
14 | let (ast, errors) = Compiler.string_to_flow_ast input in
15 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
16 | Alcotest.(check (list Util.inst_testable)) "load_null" correct prog
--------------------------------------------------------------------------------
/Compiler/test/load_property.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = {};
6 | const v1 = 13.37;
7 | const v2 = v0.__proto__;"
8 | let correct =
9 | let builder = init_builder false false false in
10 | let obj_temp, create_obj = build_create_object [] [] builder in
11 | let float_temp, load_float_inst = build_load_float 13.37 builder in
12 | let _, load_prop_inst = build_load_prop obj_temp "__proto__" builder in
13 | let res = [create_obj; load_float_inst; load_prop_inst] in
14 | List.map inst_to_prog_inst res
15 |
16 | let test () =
17 | let (ast, errors) = Compiler.string_to_flow_ast input in
18 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
19 | Alcotest.(check (list Util.inst_testable)) "load_property" correct prog
--------------------------------------------------------------------------------
/Compiler/test/load_regex.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | (* Note: this produces compiler warnings, but seems to work fine *)
5 | let input =
6 | "const v0 = /\w+\s/i;
7 | const v1 = /\w+\s/g;
8 | const v2 = /\w+\s/m;
9 | const v3 = /\w+\s/s;
10 | const v4 = /\w+\s/u;
11 | const v5 = /\w+\s/y;"
12 |
13 | let correct =
14 | let builder = init_builder false false false in
15 | let _, regexp1 = build_load_regex "\\w+\\s" "i" builder in
16 | let _, regexp2 = build_load_regex "\\w+\\s" "g" builder in
17 | let _, regexp3 = build_load_regex "\\w+\\s" "m" builder in
18 | let _, regexp4 = build_load_regex "\\w+\\s" "s" builder in
19 | let _, regexp5 = build_load_regex "\\w+\\s" "u" builder in
20 | let _, regexp6 = build_load_regex "\\w+\\s" "y" builder in
21 | let res = [regexp1; regexp2; regexp3; regexp4; regexp5; regexp6] in
22 | List.map inst_to_prog_inst res
23 |
24 | let test () =
25 | let (ast, errors) = Compiler.string_to_flow_ast input in
26 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
27 | Alcotest.(check (list Util.inst_testable)) "load_regex" correct prog
--------------------------------------------------------------------------------
/Compiler/test/logical_ops.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 1 || 2;
6 | const v1 = 3 && 4;"
7 |
8 | let correct =
9 | let builder = init_builder false false false in
10 | let int_1, load_int_1 = build_load_integer 1L builder in
11 | let int_2, load_int_2 = build_load_integer 2L builder in
12 | let _, or_inst = build_binary_op int_1 int_2 LogicalOr builder in
13 | let int_3, load_int_3 = build_load_integer 3L builder in
14 | let int_4, load_int_4 = build_load_integer 4L builder in
15 | let _, and_inst = build_binary_op int_3 int_4 LogicalAnd builder in
16 | let res = [load_int_1; load_int_2; or_inst; load_int_3; load_int_4; and_inst] in
17 | List.map inst_to_prog_inst res
18 |
19 | let test () =
20 | let (ast, errors) = Compiler.string_to_flow_ast input in
21 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
22 | Alcotest.(check (list Util.inst_testable)) "Logical_ops" correct prog
--------------------------------------------------------------------------------
/Compiler/test/lone_if.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 12;
6 | if(v0){
7 | let v1 = 12;
8 | }"
9 |
10 | let correct =
11 | let builder = init_builder false false false in
12 | let temp_12, load_int_12 = build_load_integer 12L builder in
13 | let begin_if_inst = build_begin_if temp_12 builder in
14 | let _, load_int_12_2 = build_load_integer 12L builder in
15 | let begin_else = build_begin_else builder in
16 | let end_if = build_end_if builder in
17 | let res = [load_int_12; begin_if_inst; load_int_12_2; begin_else; end_if] in
18 | List.map inst_to_prog_inst res
19 |
20 | let test () =
21 | let (ast, errors) = Compiler.string_to_flow_ast input in
22 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
23 | Alcotest.(check (list Util.inst_testable)) "lone_if" correct prog
--------------------------------------------------------------------------------
/Compiler/test/new.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v1 = new Uint8Array();
6 | const v5 = new Float32Array(12);"
7 |
8 | let correct =
9 | let builder = init_builder false false false in
10 | let uint8Array, load_uint8_builtin = build_load_builtin "Uint8Array" builder in
11 | let _, construct_uin8_inst = build_new_object uint8Array [] builder in
12 | let float32Array, load_float32_builtin = build_load_builtin "Float32Array" builder in
13 | let int_12_temp, load_12 = build_load_integer 12L builder in
14 | let _, construct_float32_inst = build_new_object float32Array [int_12_temp] builder in
15 | let res = [load_uint8_builtin; construct_uin8_inst; load_float32_builtin; load_12; construct_float32_inst] in
16 | List.map inst_to_prog_inst res
17 |
18 | let test () =
19 | let (ast, errors) = Compiler.string_to_flow_ast input in
20 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
21 | Alcotest.(check (list Util.inst_testable)) "new_test" correct prog
--------------------------------------------------------------------------------
/Compiler/test/object_creation.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "let v0 = 1;
6 | const v1 = 2
7 | const v7 = {toString:1+2,e:v0+v1};"
8 |
9 | let correct =
10 | let builder = init_builder false false false in
11 | let int_1, load_int_1 = build_load_integer 1L builder in
12 | let int_2, load_int_2 = build_load_integer 2L builder in
13 | let int_1_2, load_int_1_2 = build_load_integer 1L builder in
14 | let int_2_2, load_int_2_2 = build_load_integer 2L builder in
15 | let second_temp, second_add = build_binary_op int_1_2 int_2_2 Plus builder in
16 | let first_temp, first_add = build_binary_op int_1 int_2 Plus builder in
17 | let _, create_obj_inst = build_create_object ["toString"; "e"] [second_temp; first_temp] builder in
18 | let res = [load_int_1; load_int_2; load_int_1_2; load_int_2_2; second_add; first_add; create_obj_inst] in
19 | List.map inst_to_prog_inst res
20 |
21 | let test () =
22 | let (ast, errors) = Compiler.string_to_flow_ast input in
23 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
24 | Alcotest.(check (list Util.inst_testable)) "object_creation" correct prog
--------------------------------------------------------------------------------
/Compiler/test/prog_10.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 4294967296;
6 | const v1 = isNaN;
7 | const v2 = v0 === v1;
8 | const v3 = v0 == v1;
9 | const v4 = 13.37;
10 | const v5 = [v4,v4];
11 | const v6 = 1337;
12 | const v7 = {toString:v5,e:v6};"
13 |
14 | let correct =
15 | let builder = init_builder false false false in
16 | let large_int, load_large_int = build_load_integer 4294967296L builder in
17 | let isNaN, load_isNaN = build_load_builtin "isNaN" builder in
18 | let _, compare_inst = build_compare_op large_int isNaN StrictEqual builder in
19 | let _, compare_inst_2 = build_compare_op large_int isNaN Equal builder in
20 | let float, load_float = build_load_float 13.37 builder in
21 | let array, create_array = build_create_array [float; float] builder in
22 | let int_1337, load_int_1337 = build_load_integer 1337L builder in
23 | let _, create_object = build_create_object ["toString"; "e"] [array; int_1337] builder in
24 | let res = [load_large_int; load_isNaN; compare_inst; compare_inst_2; load_float; create_array; load_int_1337; create_object] in
25 | List.map inst_to_prog_inst res
26 |
27 | let test () =
28 | let (ast, errors) = Compiler.string_to_flow_ast input in
29 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
30 | Alcotest.(check (list Util.inst_testable)) "prog_10" correct prog
--------------------------------------------------------------------------------
/Compiler/test/prog_1007.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 2147483647;
6 | const v1 = \"function\";
7 | try {
8 | const v2 = v1.repeat(v0);
9 | } catch(v3) {
10 | }"
11 |
12 | let correct =
13 | let builder = init_builder false false false in
14 | let large_int, load_large_int = build_load_integer 2147483647L builder in
15 | let func_string, load_func_string = build_load_string "function" builder in
16 | let begin_try = build_begin_try_op builder in
17 | let _, call_method = build_call_method func_string [large_int] "repeat" builder in
18 | let begin_catch = build_begin_catch_op "foobarbaz" builder in
19 | let end_catch = build_end_try_catch_op builder in
20 | let res = [load_large_int; load_func_string; begin_try; call_method; begin_catch; end_catch] in
21 | List.map inst_to_prog_inst res
22 |
23 | let test () =
24 | let (ast, errors) = Compiler.string_to_flow_ast input in
25 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
26 | Alcotest.(check (list Util.inst_testable)) "prog_1007" correct prog
--------------------------------------------------------------------------------
/Compiler/test/prop_name_assignment.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = \"function\";
6 | const v1 = 13.37;
7 | const v2 = v0.__proto__;
8 | v2.toString = v1;"
9 |
10 | let correct =
11 | let builder = init_builder false false false in
12 | let func_string, load_func_string = build_load_string "function" builder in
13 | let float, load_float = build_load_float 13.37 builder in
14 | let prop_temp, load_prop = build_load_prop func_string "__proto__" builder in
15 | let store_prop = build_store_prop prop_temp float "toString" builder in
16 | let res = [load_func_string; load_float; load_prop; store_prop] in
17 | List.map inst_to_prog_inst res
18 |
19 | let test () =
20 | let (ast, errors) = Compiler.string_to_flow_ast input in
21 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
22 | Alcotest.(check (list Util.inst_testable)) "prop_name_assignment" correct prog
--------------------------------------------------------------------------------
/Compiler/test/single_constant.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 0;"
6 |
7 | let correct =
8 | let builder = init_builder false false false in
9 | let _, inst = build_load_integer 0L builder in
10 | let res = [inst] in
11 | List.map inst_to_prog_inst res
12 |
13 | let test () =
14 | let (ast, errors) = Compiler.string_to_flow_ast input in
15 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
16 | Alcotest.(check (list Util.inst_testable)) "single_constant" correct prog
--------------------------------------------------------------------------------
/Compiler/test/single_let.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "let v0 = 0;
6 | v0 = 12;"
7 |
8 | let correct =
9 | let builder = init_builder false false false in
10 | let int_0_temp, load_0_inst = build_load_integer 0L builder in
11 | let int_12_temp, load_12_inst = build_load_integer 12L builder in
12 | let reassign_inst = build_reassign_op int_0_temp int_12_temp builder in
13 | let res = [load_0_inst; load_12_inst; reassign_inst] in
14 | List.map inst_to_prog_inst res
15 |
16 | let test () =
17 | let (ast, errors) = Compiler.string_to_flow_ast input in
18 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
19 | Alcotest.(check (list Util.inst_testable)) "single_let" correct prog
--------------------------------------------------------------------------------
/Compiler/test/single_string_literal.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = \"foobarbaz\";"
6 |
7 | let correct =
8 | let builder = init_builder false false false in
9 | let _, inst = build_load_string "foobarbaz" builder in
10 | let res = [inst] in
11 | List.map inst_to_prog_inst res
12 |
13 | let test () =
14 | let (ast, errors) = Compiler.string_to_flow_ast input in
15 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
16 | Alcotest.(check (list Util.inst_testable)) "single_string_literal" correct prog
--------------------------------------------------------------------------------
/Compiler/test/spread_object.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "let v0 = 1;
6 | const v1 = 2
7 | const v7 = {toString:1+2,e:v0+v1};
8 | const v11 = {foobar:3+4,...v7};"
9 |
10 | let correct =
11 | let builder = init_builder false false false in
12 | let int_1, load_int_1 = build_load_integer 1L builder in
13 | let int_2, load_int_2 = build_load_integer 2L builder in
14 | let int_1_2, load_int_1_2 = build_load_integer 1L builder in
15 | let int_2_2, load_int_2_2 = build_load_integer 2L builder in
16 | let second_temp, second_add = build_binary_op int_1_2 int_2_2 Plus builder in
17 | let first_temp, first_add = build_binary_op int_1 int_2 Plus builder in
18 | let obj, create_obj_inst = build_create_object ["toString"; "e"] [second_temp; first_temp] builder in
19 |
20 | let int_3, load_int_3 = build_load_integer 3L builder in
21 | let int_4, load_int_4 = build_load_integer 4L builder in
22 | let third_temp, third_add = build_binary_op int_3 int_4 Plus builder in
23 | let _, spread_inst = build_create_object_with_spread ["foobar"] [third_temp; obj] builder in
24 | let res = [load_int_1; load_int_2; load_int_1_2; load_int_2_2; second_add; first_add; create_obj_inst; load_int_3; load_int_4; third_add; spread_inst] in
25 | List.map inst_to_prog_inst res
26 |
27 | let test () =
28 | let (ast, errors) = Compiler.string_to_flow_ast input in
29 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
30 | Alcotest.(check (list Util.inst_testable)) "spread_object" correct prog
--------------------------------------------------------------------------------
/Compiler/test/store_property_sugared.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = {};
6 | const v1 = 13.37;
7 | v0.a = 10;
8 | v0.a += v1;"
9 |
10 | let correct =
11 | let builder = init_builder false false false in
12 | let obj, create_obj = build_create_object [] [] builder in
13 | let float, load_float = build_load_float 13.37 builder in
14 | let int, load_int = build_load_integer 10L builder in
15 | let store_prop = build_store_prop obj int "a" builder in
16 | let temp_prop, load_prop = build_load_prop obj "a" builder in
17 | let add_temp, add_inst = build_binary_op temp_prop float Plus builder in
18 | let store_prop2 = build_store_prop obj add_temp "a" builder in
19 | let res = [create_obj; load_float; load_int; store_prop; load_prop; add_inst; store_prop2] in
20 | List.map inst_to_prog_inst res
21 |
22 | let test () =
23 | let (ast, errors) = Compiler.string_to_flow_ast input in
24 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
25 | Alcotest.(check (list Util.inst_testable)) "store_property_sugared" correct prog
--------------------------------------------------------------------------------
/Compiler/test/sugared_assignment.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "let v0 = 1;
6 | v0 += 10;
7 | let v1 = 2;
8 | v1 -= 20;"
9 |
10 | let correct =
11 | let builder = init_builder false false false in
12 | let int_1, load_int_1 = build_load_integer 1L builder in
13 | let int_10, load_int_10 = build_load_integer 10L builder in
14 | let add_temp, add_inst = build_binary_op int_1 int_10 Plus builder in
15 | let reassign_op = build_reassign_op int_1 add_temp builder in
16 | let int_2, load_int_2 = build_load_integer 2L builder in
17 | let int_20, load_int_20 = build_load_integer 20L builder in
18 | let sub_temp, sub_inst = build_binary_op int_2 int_20 Minus builder in
19 | let reassign_op2 = build_reassign_op int_2 sub_temp builder in
20 | let res = [load_int_1; load_int_10; add_inst; reassign_op; load_int_2; load_int_20; sub_inst; reassign_op2] in
21 | List.map inst_to_prog_inst res
22 |
23 | let test () =
24 | let (ast, errors) = Compiler.string_to_flow_ast input in
25 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
26 | Alcotest.(check (list Util.inst_testable)) "sugared_assignment" correct prog
--------------------------------------------------------------------------------
/Compiler/test/ternary.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "let a = 1 < 0 ? 2 : 3;"
6 |
7 | let correct =
8 | let builder = init_builder false false false in
9 | let int_0, load_int_0 = build_load_integer 0L builder in
10 | let int_1, load_int_1 = build_load_integer 1L builder in
11 | let int_0_2, load_int_0_2 = build_load_integer 0L builder in
12 | let compare_temp, compare_inst = build_compare_op int_1 int_0_2 LessThan builder in
13 | let begin_if_inst = build_begin_if compare_temp builder in
14 | let int_2, load_int_2 = build_load_integer 2L builder in
15 | let reassign_inst = build_reassign_op int_0 int_2 builder in
16 | let begin_else = build_begin_else builder in
17 | let int_3, load_int_3 = build_load_integer 3L builder in
18 | let reassign_inst2 = build_reassign_op int_0 int_3 builder in
19 | let end_if = build_end_if builder in
20 | let res = [load_int_0; load_int_1; load_int_0_2; compare_inst; begin_if_inst; load_int_2; reassign_inst; begin_else; load_int_3; reassign_inst2; end_if] in
21 | List.map inst_to_prog_inst res
22 |
23 | let test () =
24 | let (ast, errors) = Compiler.string_to_flow_ast input in
25 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
26 | Alcotest.(check (list Util.inst_testable)) "ternary_test" correct prog
--------------------------------------------------------------------------------
/Compiler/test/this.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = this"
6 |
7 | let correct =
8 | let builder = init_builder false false false in
9 | let _, inst = build_load_builtin "this" builder in
10 | let res = [inst] in
11 | List.map inst_to_prog_inst res
12 |
13 | let test () =
14 | let (ast, errors) = Compiler.string_to_flow_ast input in
15 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
16 | Alcotest.(check (list Util.inst_testable)) "this" correct prog
--------------------------------------------------------------------------------
/Compiler/test/throw.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 0;
6 | throw v0;"
7 |
8 | let correct =
9 | let builder = init_builder false false false in
10 | let temp_0, load_0 = build_load_integer 0L builder in
11 | let inst = build_throw_op temp_0 builder in
12 | let res = [load_0; inst] in
13 | List.map inst_to_prog_inst res
14 |
15 | let test () =
16 | let (ast, errors) = Compiler.string_to_flow_ast input in
17 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
18 | Alcotest.(check (list Util.inst_testable)) "throw" correct prog
--------------------------------------------------------------------------------
/Compiler/test/typeof.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 12;
6 | const v2 = typeof v0;"
7 |
8 | let correct =
9 | let builder = init_builder false false false in
10 | let int, load_int = build_load_integer 12L builder in
11 | let _, typeof_inst = build_typeof_op int builder in
12 | let res = [load_int; typeof_inst] in
13 | List.map inst_to_prog_inst res
14 |
15 | let test () =
16 | let (ast, errors) = Compiler.string_to_flow_ast input in
17 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
18 | Alcotest.(check (list Util.inst_testable)) "typeof" correct prog
--------------------------------------------------------------------------------
/Compiler/test/unary_minus.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v2 = -256;"
6 |
7 | let correct =
8 | let builder = init_builder false false false in
9 | let pos_temp, load_int = build_load_integer 256L builder in
10 | let _, unary_inst = build_unary_op pos_temp Minus builder in
11 | let res = [load_int; unary_inst] in
12 | List.map inst_to_prog_inst res
13 |
14 | let test () =
15 | let (ast, errors) = Compiler.string_to_flow_ast input in
16 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
17 | Alcotest.(check (list Util.inst_testable)) "unary_minus" correct prog
--------------------------------------------------------------------------------
/Compiler/test/unary_ops.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = !true;
6 | const v1 = !false;
7 | const v2 = !v0;
8 | const v3 = ~5;"
9 |
10 | let correct =
11 | let builder = init_builder false false false in
12 | let true_temp, load_true = build_load_bool true builder in
13 | let not_temp, not_inst_1 = build_unary_op true_temp Not builder in
14 | let false_temp, load_false = build_load_bool false builder in
15 | let _, not_inst_2 = build_unary_op false_temp Not builder in
16 | let _, not_inst_3 = build_unary_op not_temp Not builder in
17 | let int_5, load_int_5 = build_load_integer 5L builder in
18 | let _, bit_not_inst = build_unary_op int_5 BitNot builder in
19 | let res = [load_true; not_inst_1; load_false; not_inst_2; not_inst_3; load_int_5; bit_not_inst] in
20 | List.map inst_to_prog_inst res
21 |
22 | let test () =
23 | let (ast, errors) = Compiler.string_to_flow_ast input in
24 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
25 | Alcotest.(check (list Util.inst_testable)) "unary_ops" correct prog
--------------------------------------------------------------------------------
/Compiler/test/undefined.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "let a = undefined;"
6 |
7 | let correct =
8 | let builder = init_builder false false false in
9 | let _, inst = build_load_undefined builder in
10 | let res = [inst] in
11 | List.map inst_to_prog_inst res
12 |
13 | let test () =
14 | let (ast, errors) = Compiler.string_to_flow_ast input in
15 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
16 | Alcotest.(check (list Util.inst_testable)) "undefined" correct prog
--------------------------------------------------------------------------------
/Compiler/test/update.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = 5;
6 | v0++;
7 | --v0;"
8 |
9 | let correct =
10 | let builder = init_builder false false false in
11 | let int_5, load_int_5 = build_load_integer 5L builder in
12 | let _, post_inc = build_unary_op int_5 PostInc builder in
13 | let _, pre_inc = build_unary_op int_5 PreDec builder in
14 | let res = [load_int_5; post_inc; pre_inc] in
15 | List.map inst_to_prog_inst res
16 |
17 | let test () =
18 | let (ast, errors) = Compiler.string_to_flow_ast input in
19 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
20 | Alcotest.(check (list Util.inst_testable)) "update" correct prog
--------------------------------------------------------------------------------
/Compiler/test/util.ml:
--------------------------------------------------------------------------------
1 | let inst_testable = Alcotest.testable Compiler.pp_instruction (=)
2 |
3 | let type_ext = Typesystem_types.{
4 | properties = [];
5 | methods = [];
6 | group = "";
7 | signature = None;
8 | }
9 |
10 |
11 | let default_input_type = Typesystem_types.{
12 | definite_type = 4095l;
13 | possible_type = 4095l;
14 | ext = Extension type_ext
15 | }
16 |
17 | let spread_input_type = Typesystem_types.{
18 | definite_type = 2147483648l;
19 | possible_type = 2147483648l;
20 | ext = Extension type_ext
21 | }
22 |
23 | let default_output_type = Typesystem_types.{
24 | definite_type = Int32.shift_left 1l 8;
25 | possible_type = Int32.shift_left 1l 8;
26 | ext = Extension type_ext
27 | }
28 |
--------------------------------------------------------------------------------
/Compiler/test/v8_natives.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v0 = function () { const v1 = 12; return v1;}
6 | %PrepareFunctionForOptimization(v0);"
7 |
8 | let correct =
9 | let builder = init_builder false true true in
10 | let func_temp = get_new_intermed_temp builder in
11 | let _, begin_func_inst, end_func_inst = build_func_ops func_temp [] None false false false builder in
12 | let int_12, load_12 = build_load_integer 12L builder in
13 | let ret_inst = build_return_op int_12 builder in
14 | let builtin_temp, load_builtin = build_load_builtin "PrepareFunctionForOptimization" builder in
15 | let _, call_inst = build_call builtin_temp [func_temp] builder in
16 | let res = [begin_func_inst; load_12; ret_inst; end_func_inst; load_builtin; call_inst] in
17 | List.map inst_to_prog_inst res
18 |
19 | let test () =
20 | let (ast, errors) = Compiler.string_to_flow_ast input in
21 | let prog = Compiler.flow_ast_to_inst_list ast false true true in
22 | Alcotest.(check (list Util.inst_testable)) "v8_natives" correct prog
--------------------------------------------------------------------------------
/Compiler/test/var_hoisting_1.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "function foo() {
6 | if(1){
7 | var asdf = 12;
8 | }
9 | isNaN(asdf);
10 | }
11 | foo();
12 | "
13 |
14 | let correct =
15 | let builder = init_builder false false false in
16 | let func_temp = get_new_intermed_temp builder in
17 | let _, begin_func_inst, end_func_inst = build_func_ops func_temp [] None false false false builder in
18 | let undef_temp, load_undef_inst = build_load_undefined builder in
19 | let integer_temp, load_integer_inst = build_load_integer 1L builder in
20 | let begin_if_inst = build_begin_if integer_temp builder in
21 | let load_hoisted_temp, load_hoisted_inst = build_load_integer 12L builder in
22 | let reassign_inst = build_reassign_op undef_temp load_hoisted_temp builder in
23 | let begin_else_inst = build_begin_else builder in
24 | let end_if_inst = build_end_if builder in
25 | let print_temp, load_print_inst = build_load_builtin "isNaN" builder in
26 | let _, call_print_inst = build_call print_temp [undef_temp] builder in
27 | let _, call_foo_inst = build_call func_temp [] builder in
28 | let res = [begin_func_inst; load_undef_inst; load_integer_inst; begin_if_inst; load_hoisted_inst; reassign_inst; begin_else_inst; end_if_inst; load_print_inst; call_print_inst; end_func_inst; call_foo_inst] in
29 | List.map inst_to_prog_inst res
30 |
31 | let test () =
32 | let (ast, errors) = Compiler.string_to_flow_ast input in
33 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
34 | Alcotest.(check (list Util.inst_testable)) "var_hoisting_1" correct prog
35 |
--------------------------------------------------------------------------------
/Compiler/test/var_hoisting_2.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "function foo() {
6 | for(var i = 1; i < 2; i++){
7 | var asdf = i;
8 | }
9 | isNaN(asdf);
10 | }
11 | foo();
12 | "
13 |
14 | let correct =
15 | let builder = init_builder false false false in
16 | let func_temp = get_new_intermed_temp builder in
17 | let _, begin_func_inst, end_func_inst = build_func_ops func_temp [] None false false false builder in
18 | let undef_temp, load_undef_inst = build_load_undefined builder in
19 | let integer_temp, load_integer_inst = build_load_integer 1L builder in
20 | let compare_temp_target, load_compare_temp_inst = build_load_integer 2L builder in
21 | let compare_temp, compare_inst = build_compare_op integer_temp compare_temp_target LessThan builder in
22 | let i_temp, load_i_inital_inst = build_load_integer 0L builder in
23 | let begin_while_inst = build_begin_while compare_temp i_temp NotEqual builder in
24 | let reassign_hoisted_inst = build_reassign_op undef_temp integer_temp builder in
25 | let _, inc_loop_var_inst = build_unary_op integer_temp PostInc builder in
26 | let loop_compare_temp, load_loop_temp_inst = build_load_integer 2L builder in
27 | let recompare_temp, recompare_inst = build_compare_op integer_temp loop_compare_temp LessThan builder in
28 | let reassign_loop_compare = build_reassign_op compare_temp recompare_temp builder in
29 | let end_while__inst = build_end_while builder in
30 | let print_temp, load_print_inst = build_load_builtin "isNaN" builder in
31 | let _, call_print_inst = build_call print_temp [undef_temp] builder in
32 | let _, call_foo_inst = build_call func_temp [] builder in
33 | let res = [begin_func_inst; load_undef_inst; load_integer_inst; load_compare_temp_inst; compare_inst; load_i_inital_inst;
34 | begin_while_inst; reassign_hoisted_inst; inc_loop_var_inst; load_loop_temp_inst; recompare_inst; reassign_loop_compare; end_while__inst;
35 | load_print_inst; call_print_inst; end_func_inst; call_foo_inst] in
36 | List.map inst_to_prog_inst res
37 |
38 | let test () =
39 | let (ast, errors) = Compiler.string_to_flow_ast input in
40 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
41 | Alcotest.(check (list Util.inst_testable)) "var_hoisting_2" correct prog
42 |
--------------------------------------------------------------------------------
/Compiler/test/var_hoisting_3.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "function foo() {
6 | let t = 1;
7 | if(t){
8 | if(t){
9 | var asdf = 12;
10 | }
11 | }
12 | isNaN(asdf);
13 | }
14 | foo();
15 | "
16 |
17 | let correct =
18 | let builder = init_builder false false false in
19 | let func_temp = get_new_intermed_temp builder in
20 | let _, begin_func_inst, end_func_inst = build_func_ops func_temp [] None false false false builder in
21 | let undef_temp, load_undef_inst = build_load_undefined builder in
22 | let integer_temp, load_integer_inst = build_load_integer 1L builder in
23 |
24 | let begin_if_inst = build_begin_if integer_temp builder in
25 | let load_hoisted_temp, load_hoisted_inst = build_load_integer 12L builder in
26 | let reassign_inst = build_reassign_op undef_temp load_hoisted_temp builder in
27 | let begin_else_inst = build_begin_else builder in
28 | let end_if_inst = build_end_if builder in
29 |
30 | let print_temp, load_print_inst = build_load_builtin "isNaN" builder in
31 | let _, call_print_inst = build_call print_temp [undef_temp] builder in
32 | let _, call_foo_inst = build_call func_temp [] builder in
33 | let res = [begin_func_inst; load_undef_inst; load_integer_inst; begin_if_inst; begin_if_inst; load_hoisted_inst; reassign_inst; begin_else_inst; end_if_inst; begin_else_inst; end_if_inst; load_print_inst; call_print_inst; end_func_inst; call_foo_inst] in
34 | List.map inst_to_prog_inst res
35 |
36 | let test () =
37 | let (ast, errors) = Compiler.string_to_flow_ast input in
38 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
39 | Alcotest.(check (list Util.inst_testable)) "var_hoisting_3" correct prog
40 |
--------------------------------------------------------------------------------
/Compiler/test/var_hoisting_shadow.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "for(x in [0]){}
6 | if(1){
7 | var x = 12;
8 | }
9 | isNaN(x);
10 | "
11 |
12 | let correct =
13 | let builder = init_builder false false false in
14 | let undef_temp, load_undef_inst = build_load_undefined builder in
15 | let integer_temp, load_integer_inst = build_load_integer 0L builder in
16 | let array_temp, array_build_inst = build_create_array [integer_temp] builder in
17 | let for_in_temp = get_new_intermed_temp builder in
18 | let _, begin_for_in_inst = build_begin_for_in_op for_in_temp array_temp builder in
19 | let reassign_inst = build_reassign_op undef_temp for_in_temp builder in
20 | let end_for_in_inst = build_end_for_in_op builder in
21 | let if_condition_temp, load_if_condition_inst = build_load_integer 1L builder in
22 | let begin_if_inst = build_begin_if if_condition_temp builder in
23 | let load_hoisted_temp, load_hoisted_inst = build_load_integer 12L builder in
24 | let reassign_inst2 = build_reassign_op undef_temp load_hoisted_temp builder in
25 | let begin_else_inst = build_begin_else builder in
26 | let end_if_inst = build_end_if builder in
27 | let print_temp, load_print_inst = build_load_builtin "isNaN" builder in
28 | let _, call_print_inst = build_call print_temp [undef_temp] builder in
29 | let res = [load_undef_inst; load_integer_inst; array_build_inst; begin_for_in_inst; reassign_inst; end_for_in_inst; load_if_condition_inst; begin_if_inst; load_hoisted_inst; reassign_inst2; begin_else_inst; end_if_inst; load_print_inst; call_print_inst] in
30 | List.map inst_to_prog_inst res
31 |
32 | let test () =
33 | let (ast, errors) = Compiler.string_to_flow_ast input in
34 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
35 | Alcotest.(check (list Util.inst_testable)) "var_hoisting_shadow" correct prog
36 |
--------------------------------------------------------------------------------
/Compiler/test/void.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "let a = void (1 + 2);"
6 |
7 | let correct =
8 | let builder = init_builder false false false in
9 | let int_1, load_int_1 = build_load_integer 1L builder in
10 | let int_2, load_int_2 = build_load_integer 2L builder in
11 | let _, binary_op = build_binary_op int_1 int_2 Plus builder in
12 | let _, load_undef = build_load_undefined builder in
13 | let res = [load_int_1; load_int_2; binary_op; load_undef] in
14 | List.map inst_to_prog_inst res
15 |
16 | let test () =
17 | let (ast, errors) = Compiler.string_to_flow_ast input in
18 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
19 | Alcotest.(check (list Util.inst_testable)) "void" correct prog
--------------------------------------------------------------------------------
/Compiler/test/with.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "let v0 = 10;
6 | let v4 = 13;
7 | const v2 = [12];
8 | with (v2) {
9 | const v3 = 0.0;
10 | const v9 = v0 - v4;
11 | }"
12 |
13 |
14 | (* TODO: This likely is incorrect *)
15 | let correct =
16 | let builder = init_builder false false false in
17 | let int_10, load_int_10 = build_load_integer 10L builder in
18 | let int_13, load_int_13 = build_load_integer 13L builder in
19 | let int_12, load_int_12 = build_load_integer 12L builder in
20 | let arr_temp, create_array_inst = build_create_array [int_12] builder in
21 | let begin_with = build_begin_with_op arr_temp builder in
22 | let float, load_float = build_load_float 0.0 builder in
23 | let _, sub_inst = build_binary_op int_10 int_13 Minus builder in
24 | let end_with = build_end_with_op builder in
25 | let res = [load_int_10; load_int_13; load_int_12; create_array_inst; begin_with; load_float; sub_inst; end_with] in
26 | List.map inst_to_prog_inst res
27 |
28 | let test () =
29 | let (ast, errors) = Compiler.string_to_flow_ast input in
30 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
31 | Alcotest.(check (list Util.inst_testable)) "with" correct prog
--------------------------------------------------------------------------------
/Compiler/test/with_load_scope.ml:
--------------------------------------------------------------------------------
1 | open Program_types
2 | open Compiler.ProgramBuilder
3 |
4 | let input =
5 | "const v9 = {__proto__:0,length:0};
6 | with (v9) {
7 | const v11 = length;
8 | }
9 | "
10 |
11 | (* TODO: This may not be correct, as length should come from v9 *)
12 | let correct =
13 | let builder = init_builder false false false in
14 | let int_0_1, load_int_0_1 = build_load_integer 0L builder in
15 | let int_0_2, load_int_0_2 = build_load_integer 0L builder in
16 | let obj_temp, create_obj = build_create_object ["__proto__"; "length"] [int_0_1; int_0_2] builder in
17 | let begin_with = build_begin_with_op obj_temp builder in
18 | let _, load_builtin = build_load_builtin "placeholder" builder in
19 | let end_with = build_end_with_op builder in
20 | let res = [load_int_0_1; load_int_0_2; create_obj; begin_with; load_builtin; end_with] in
21 | List.map inst_to_prog_inst res
22 |
23 | let test () =
24 | let (ast, errors) = Compiler.string_to_flow_ast input in
25 | let prog = Compiler.flow_ast_to_inst_list ast false false true in
26 | Alcotest.(check (list Util.inst_testable)) "with" correct prog
--------------------------------------------------------------------------------
/Docs/ProcessingModel.md:
--------------------------------------------------------------------------------
1 | # Processing Model
2 |
3 | Fuzzilli's processing and threading model is fairly simple: every Fuzzer
4 | instance has an associated sequential
5 | [DispatchQueue](https://developer.apple.com/documentation/dispatch/dispatchqueue)
6 | on which all interactions with the fuzzer must happen. This architecture avoids
7 | race conditions as work items are processed sequentially. It also makes it
8 | rather straight forward to run multiple Fuzzer instances in one process.
9 | Whenever code wants to interact with a fuzzer instance (i.e. call methods on
10 | it, access properties, etc.) but (potentially) executes on a different
11 | DispatchQueue, it has to first enqueue an operation into the Fuzzer's queue.
12 | For that, the Fuzzer class exposes the `sync` and `async` functions which
13 | essentially just enqueue the given work item into the fuzzer's DispatchQueue
14 | and which can safely be called from a separate thread:
15 |
16 | fuzzer.async {
17 | // Can now interact with the fuzzer
18 | fuzzer.importProgram(someProgram)
19 | }
20 |
21 | Any code that is invoked by Fuzzilli (e.g. Mutators, Module initializers,
22 | CodeGenerators, Event and Timer handlers, etc.) will always execute on the
23 | fuzzer's dispatch queue and thus does not need to worry about enqueuing tasks
24 | first. Only if code uses separate DispatchQueues, threads, etc. must it ensure
25 | that it always interacts with the fuzzer on the correct queue. See e.g. the
26 | ThreadSync or NetworkSync module for examples of this.
27 |
28 | The dispatch queue of a typical Fuzzer instance commonly contains (some of) the
29 | following items:
30 |
31 | * A call to Fuzzer.fuzzOne to perform one iteration of fuzzing. When fuzzOne
32 | finishes, it will schedule the next fuzzing iteration.
33 | * Handler blocks for any timers scheduled via the Fuzzer.timers API that have
34 | recently triggered
35 | * Handlers for incoming network connections and data if the NetworkSync module
36 | is active
37 | * Handlers for messages from other fuzzers if any of the fuzzer synchronization
38 | modules are active
39 | * Program executions scheduled by the minimizer (which runs on a separate queue
40 | since it often takes a long time to complete)
41 |
--------------------------------------------------------------------------------
/Docs/images/fuzzing_with_fuzzil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/P1umer/fuzzilli4wasm/5ecdc393366f9c4920eeda2c0bd934d0919a02f5/Docs/images/fuzzing_with_fuzzil.png
--------------------------------------------------------------------------------
/Docs/images/generative_engine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/P1umer/fuzzilli4wasm/5ecdc393366f9c4920eeda2c0bd934d0919a02f5/Docs/images/generative_engine.png
--------------------------------------------------------------------------------
/Docs/images/hybrid_engine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/P1umer/fuzzilli4wasm/5ecdc393366f9c4920eeda2c0bd934d0919a02f5/Docs/images/hybrid_engine.png
--------------------------------------------------------------------------------
/Docs/images/mutation_engine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/P1umer/fuzzilli4wasm/5ecdc393366f9c4920eeda2c0bd934d0919a02f5/Docs/images/mutation_engine.png
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 | //
3 | // Copyright 2019 Google LLC
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // https://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 |
17 | import PackageDescription
18 |
19 | let package = Package(
20 | name: "Fuzzilli",
21 | platforms: [
22 | .macOS(.v10_13),
23 | ],
24 | products: [
25 | .library(name: "Fuzzilli", targets: ["Fuzzilli"]),
26 | ],
27 | dependencies: [
28 | .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.6.0"),
29 | ],
30 | targets: [
31 | .target(name: "libsocket", dependencies: []),
32 | .target(name: "libreprl", dependencies: []),
33 | // Using '-c release' when building uses '-O2', so '-O3' provides a performance gain
34 | .target(name: "libcoverage", dependencies: [], cSettings: [.unsafeFlags(["-O3"])], linkerSettings: [.linkedLibrary("rt", .when(platforms: [.linux]))]),
35 | .target(name: "Fuzzilli", dependencies: ["SwiftProtobuf", "libsocket", "libreprl", "libcoverage", "JS"]),
36 | .target(name: "REPRLRun", dependencies: ["libreprl"]),
37 | .target(name: "FuzzilliCli", dependencies: ["Fuzzilli"]),
38 | .target(name: "JS", dependencies: []),
39 | .target(name: "Benchmarks", dependencies: ["Fuzzilli"]),
40 | .target(name: "FuzzILTool", dependencies: ["Fuzzilli"]),
41 |
42 | .testTarget(name: "FuzzilliTests", dependencies: ["Fuzzilli"]),
43 | ],
44 | swiftLanguageVersions: [.v5]
45 | )
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Fuzzilli-WASM
2 | A toy fuzzer for wasm fuzzing based on [Fuzzilli](https://github.com/googleprojectzero/fuzzilli), which will generate grammatically and semantically correct javascript code containing wasm features for fuzzing.
3 |
4 | ## WASM Features
5 | - [Global](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Global)
6 |
7 | - [Module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module)
8 |
9 | - [Memory](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory)
10 |
11 | - [Instance](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance)
12 |
13 | - [Table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table)
14 |
15 | - [Method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly#Methods)
16 |
17 | ## Build
18 | Same as [Fuzzilli](https://github.com/googleprojectzero/fuzzilli)
19 |
--------------------------------------------------------------------------------
/Sources/Benchmarks/main.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Foundation
16 | import Fuzzilli
17 |
18 | // Tiny benchmarking suite
19 |
20 | // How often to repeat every benchmark
21 | let repetitions = 10
22 |
23 | // Current timestamp in seconds (with at least millisecond precision)
24 | func now() -> Double {
25 | return Date().timeIntervalSince1970
26 | }
27 |
28 |
29 | func benchmarkCodeGeneration() {
30 | let corpus = BasicCorpus(minSize: 1, maxSize: 1000, minMutationsPerSample: 5)
31 | let fuzzer = makeMockFuzzer(corpus: corpus)
32 | let b = fuzzer.makeBuilder()
33 |
34 | for _ in 0..<1000 {
35 | b.generate(n: 100)
36 | let program = b.finalize()
37 |
38 | // Add to corpus since generate() does splicing as well
39 | fuzzer.corpus.add(program, ProgramAspects(outcome: .succeeded))
40 | }
41 | }
42 |
43 | // TODO add more, e.g. for mutators
44 | var benchmarks: [String: () -> ()] = [
45 | "CodeGenerationBenchmark": benchmarkCodeGeneration
46 | ]
47 |
48 | for (name, benchmark) in benchmarks {
49 | var totalTime = 0.0
50 | for _ in 0..
22 |
23 | /// The current active engine.
24 | private var activeEngine: FuzzEngine
25 |
26 | /// The number of fuzzing iterations to complete per engine.
27 | private let iterationsPerEngine: Int
28 |
29 | /// The number of fuzzing iterations.
30 | private var currentIteration = 0
31 |
32 | public init(engines: WeightedList, initialActive: FuzzEngine? = nil, iterationsPerEngine: Int) {
33 | assert(iterationsPerEngine > 0)
34 | self.iterationsPerEngine = iterationsPerEngine
35 | self.engines = engines
36 | self.activeEngine = initialActive ?? engines.randomElement()
37 | super.init(name: "MultiEngine")
38 | }
39 |
40 | override func initialize() {
41 | for engine in engines {
42 | engine.initialize(with: self.fuzzer)
43 | }
44 | }
45 |
46 | public func fuzzOne(_ group: DispatchGroup) {
47 | activeEngine.fuzzOne(group)
48 | currentIteration += 1
49 | if currentIteration % iterationsPerEngine == 0 {
50 | activeEngine = engines.randomElement()
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Core/ProgramGeneratorStats.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | public struct ProgramGeneratorStats {
16 | private var validSamples = 0
17 | private var invalidSamples = 0
18 |
19 | mutating func producedValidSample() {
20 | validSamples += 1
21 | }
22 |
23 | mutating func producedInvalidSample() {
24 | invalidSamples += 1
25 | }
26 |
27 | var correctnessRate: Double {
28 | let totalSamples = validSamples + invalidSamples
29 | guard totalSamples > 0 else { return 1.0 }
30 | return Double(validSamples) / Double(totalSamples)
31 | }
32 |
33 | // TODO: Maybe also add a counter to track how often it generated new coverage?
34 | }
35 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Core/ProgramOrigin.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Foundation
16 |
17 | // Enum to identify the origin of a Program.
18 | public enum ProgramOrigin: Equatable {
19 | // The program was generated by this instance.
20 | case local
21 |
22 | // The program is part of a corpus that is being imported.
23 | case corpusImport(shouldMinimize: Bool)
24 |
25 | // The program was sent by a worker instance, identified by the UUID
26 | // Note: the UUID identifies the sending instance, which is not
27 | // necessarily the intance that originally generated the program.
28 | case worker(id: UUID)
29 |
30 | // The program was sent by our master instance.
31 | // As above, this does not necessarily mean that the master generated
32 | // this program, just that it was received from it. For example, it is
33 | // possible that another worker generated the program, sent it to the
34 | // master, and the master then sent it to us. In this case, the origin
35 | // would also be .master.
36 | case master
37 |
38 | /// Whether a program with this origin still requires minimization or not.
39 | public func requiresMinimization() -> Bool {
40 | switch self {
41 | case .local:
42 | return true
43 | case .corpusImport(let shouldMinimize):
44 | return shouldMinimize
45 | case .worker, .master:
46 | return false
47 | }
48 | }
49 |
50 | /// Whether the origin is another fuzzer instance.
51 | public func isFromOtherInstance() -> Bool {
52 | switch self {
53 | case .worker, .master:
54 | return true
55 | default:
56 | return false
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Evaluation/ProgramAspects.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// Aspects of a program that make it special.
16 | public class ProgramAspects: CustomStringConvertible {
17 | let outcome: ExecutionOutcome
18 |
19 | public init(outcome: ExecutionOutcome) {
20 | self.outcome = outcome
21 | }
22 |
23 | public var description: String {
24 | return "execution outcome \(outcome)"
25 | }
26 |
27 | // The total number of aspects
28 | public var count: UInt64 {
29 | return 0
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Evaluation/ProgramEvaluator.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Foundation
16 |
17 | public protocol ProgramEvaluator: Component {
18 | /// Evaluates a program.
19 | ///
20 | /// - Parameter execution: An execution of the program to evaluate.
21 | /// - Returns: The programs special aspects if it has any, nil otherwise.
22 | func evaluate(_ execution: Execution) -> ProgramAspects?
23 |
24 | /// Evaluates a crash.
25 | ///
26 | /// - Parameter execution: An execution of the program to evaluate.
27 | /// - Returns: the programs special aspects if it has any, nil otherwise.
28 | func evaluateCrash(_ execution: Execution) -> ProgramAspects?
29 |
30 | /// Checks whether a program has the given aspects.
31 | func hasAspects(_ execution: Execution, _ aspects: ProgramAspects) -> Bool
32 |
33 | /// The current, accumulated score of all seen samples. E.g. total coverage.
34 | var currentScore: Double { get }
35 |
36 | /// Export the current state of this evaluator so it can be replicated.
37 | func exportState() -> Data
38 |
39 | /// Import a previously exported state.
40 | func importState(_ state: Data) throws
41 |
42 | // Resets the provided aspects and executes the program a second time.
43 | // If aspects are successfully collected from the second execution, returns
44 | // the intersection of the initally provided aspects with the aspects from the
45 | // second execution. If it fails at any point, returns nil
46 | func evaluateAndIntersect(_ program: Program, with aspects: ProgramAspects) -> ProgramAspects?
47 |
48 | /// Resets the internal state
49 | func resetState()
50 | }
51 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Execution/Execution.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Foundation
16 |
17 | /// The possible outcome of a program execution.
18 | public enum ExecutionOutcome: CustomStringConvertible, Equatable, Hashable {
19 | case crashed(Int)
20 | case failed(Int)
21 | case succeeded
22 | case timedOut
23 |
24 | public var description: String {
25 | switch self {
26 | case .crashed(let signal):
27 | return "Crashed (signal \(signal))"
28 | case .failed(let exitcode):
29 | return "Failed (exit code \(exitcode))"
30 | case .succeeded:
31 | return "Succeeded"
32 | case .timedOut:
33 | return "TimedOut"
34 | }
35 | }
36 |
37 | public func isCrash() -> Bool {
38 | if case .crashed = self {
39 | return true
40 | } else {
41 | return false
42 | }
43 | }
44 | }
45 |
46 | /// The result of executing a program.
47 | public protocol Execution {
48 | /// The execution outcome
49 | var outcome: ExecutionOutcome { get }
50 |
51 | /// The program's stdout
52 | var stdout: String { get }
53 |
54 | /// The program's stderr
55 | var stderr: String { get }
56 |
57 | /// The program's FuzzIL output
58 | var fuzzout: String { get }
59 |
60 | /// Execution time in microseconds
61 | var execTime: TimeInterval { get }
62 | }
63 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Execution/ScriptRunner.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | public protocol ScriptRunner: Component {
16 | /// Executes a script, waits for it to complete, and returns the result.
17 | func run(_ script: String, withTimeout timeout: UInt32) -> Execution
18 |
19 | /// Sets an environment variable for the child process. Must only be called before initialization.
20 | func setEnvironmentVariable(_ key: String, to value: String)
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/FuzzIL/Context.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// Current context in the program
16 | public struct Context: OptionSet {
17 | public let rawValue: Int
18 |
19 | public init(rawValue: Int) {
20 | self.rawValue = rawValue
21 | }
22 |
23 | // Default script context
24 | public static let script = Context(rawValue: 1 << 0)
25 | // Inside a function definition
26 | public static let function = Context(rawValue: 1 << 1)
27 | // Inside a generator function definition
28 | public static let generatorFunction = Context(rawValue: 1 << 2)
29 | // Inside an async function definition
30 | public static let asyncFunction = Context(rawValue: 1 << 3)
31 | // Inside a loop
32 | public static let loop = Context(rawValue: 1 << 4)
33 | // Inside a with statement
34 | public static let with = Context(rawValue: 1 << 5)
35 | // Inside a class definition
36 | public static let classDefinition = Context(rawValue: 1 << 6)
37 | // Inside a switch block
38 | public static let switchCase = Context(rawValue: 1 << 7)
39 |
40 | public static let empty = Context([])
41 | }
--------------------------------------------------------------------------------
/Sources/Fuzzilli/FuzzIL/ProgramComments.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Foundation
16 |
17 | /// Comments that can be attached to a Program.
18 | public struct ProgramComments {
19 | private static let headerIndex = Int32(-1)
20 | private static let footerIndex = Int32(-2)
21 |
22 | public enum CommentPosition {
23 | case header
24 | case footer
25 | case instruction(Int)
26 |
27 | fileprivate func toKey() -> Int32 {
28 | switch self {
29 | case .header:
30 | return ProgramComments.headerIndex
31 | case .footer:
32 | return ProgramComments.footerIndex
33 | case .instruction(let index):
34 | assert(index >= 0 && index <= UInt16.max)
35 | return Int32(index + 2)
36 | }
37 | }
38 | }
39 |
40 | private var comments: [Int32:String] = [:]
41 |
42 | public init() {}
43 |
44 | public var isEmpty: Bool {
45 | return comments.isEmpty
46 | }
47 |
48 | public func at(_ position: CommentPosition) -> String? {
49 | let key = position.toKey()
50 | return comments[key]
51 | }
52 |
53 | public mutating func add(_ content: String, at position: CommentPosition) {
54 | let key = position.toKey()
55 |
56 | var comment = ""
57 | if let currentContent = comments[key] {
58 | comment += currentContent + "\n"
59 | }
60 | comment += content
61 |
62 | comments[key] = comment
63 | }
64 |
65 | public mutating func removeAll() {
66 | comments.removeAll()
67 | }
68 | }
69 |
70 | extension ProgramComments: ProtobufConvertible {
71 | public typealias ProtobufType = [Int32: String]
72 |
73 | public func asProtobuf() -> ProtobufType {
74 | return comments
75 | }
76 |
77 | public init(from protobuf: ProtobufType) {
78 | self.comments = protobuf
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/FuzzIL/TypeCollectionStatus.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | public enum TypeCollectionStatus: UInt8 {
15 | case success
16 | case error
17 | case timeout
18 | case notAttempted
19 |
20 | public init(from typeCollectionOutcome: ExecutionOutcome){
21 | switch typeCollectionOutcome {
22 | case .crashed: self = .error
23 | case .failed: self = .error
24 | case .succeeded: self = .success
25 | case .timedOut: self = .timeout
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/FuzzIL/TypeInfo.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | public enum TypeQuality: UInt8 {
15 | case inferred
16 | case runtime
17 | }
18 |
19 | // Store known types for program variables at specific instructions
20 | public struct TypeInfo: Equatable {
21 | private let _index: UInt16
22 | public let type: Type
23 | public let quality: TypeQuality
24 | public var index: Int {
25 | return Int(_index)
26 | }
27 |
28 | public init(index: Int, type: Type, quality: TypeQuality) {
29 | self._index = UInt16(index)
30 | self.type = type
31 | self.quality = quality
32 | }
33 |
34 | public static func == (lhs: TypeInfo, rhs: TypeInfo) -> Bool {
35 | return lhs._index == rhs._index && lhs.type == rhs.type && lhs.quality == rhs.quality
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/FuzzIL/Variable.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// A variable in the FuzzIL language.
16 | ///
17 | /// Variables names (numbers) are local to a program. Different programs
18 | /// will have the same variable names referring to different things.
19 | public struct Variable: Hashable, CustomStringConvertible {
20 | // We assume that programs will always have less than 64k variables
21 | private let num: UInt16
22 |
23 | public init(number: Int) {
24 | self.num = UInt16(number)
25 | }
26 |
27 | public var number: Int {
28 | return Int(num)
29 | }
30 |
31 | public var identifier: String {
32 | return "v\(number)"
33 | }
34 |
35 | public var description: String {
36 | return identifier
37 | }
38 |
39 | public static func ==(lhs: Variable, rhs: Variable) -> Bool {
40 | return lhs.number == rhs.number
41 | }
42 |
43 | public static func isValidVariableNumber(_ number: Int) -> Bool {
44 | return UInt16(exactly: number) != nil
45 | }
46 | }
47 |
48 | extension Variable: Comparable {
49 | public static func <(lhs: Variable, rhs: Variable) -> Bool {
50 | return lhs.number < rhs.number
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Lifting/InliningPolicy.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | public protocol InliningPolicy {
16 | func shouldInline(_ expr: Expression) -> Bool
17 | }
18 |
19 | public struct AlwaysInline: InliningPolicy {
20 | public init() {}
21 | public func shouldInline(_ expr: Expression) -> Bool {
22 | return true
23 | }
24 | }
25 |
26 | public struct NeverInline: InliningPolicy {
27 | public init() {}
28 | public func shouldInline(_ expr: Expression) -> Bool {
29 | return false
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Lifting/Lifter.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// Lifts a FuzzIL program to the target language.
16 | public protocol Lifter {
17 | func lift(_ program: Program, withOptions options: LiftingOptions) -> String
18 | }
19 |
20 | extension Lifter {
21 | public func lift(_ program: Program) -> String {
22 | return lift(program, withOptions: [])
23 | }
24 | }
25 |
26 | public struct LiftingOptions: OptionSet {
27 | public let rawValue: Int
28 | public init(rawValue: Int) {
29 | self.rawValue = rawValue
30 | }
31 |
32 | public static let dumpTypes = LiftingOptions(rawValue: 1 << 0)
33 | public static let minify = LiftingOptions(rawValue: 1 << 1)
34 | public static let collectTypes = LiftingOptions(rawValue: 1 << 2)
35 | public static let includeComments = LiftingOptions(rawValue: 1 << 3)
36 | }
37 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Lifting/TypeCollectionAnalyzer.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Determine what variable types we should collect given instruction
16 | struct TypeCollectionAnalyzer {
17 | // Special properties which significantly change variable type
18 | // We should recollect type if we change them
19 | let specialProperties = ["__proto__"]
20 |
21 | func analyze(_ instr: Instruction) -> [Variable] {
22 | switch instr.op {
23 | case is LoadInteger, is LoadBigInt, is LoadFloat, is LoadBoolean, is LoadNull, is LoadUndefined,
24 | is TypeOf, is InstanceOf, is In, is Dup, is Reassign, is ReassignWithBinop, is Compare, is BeginForIn:
25 | // No need to collect types for instructions interpreter can handle
26 | return []
27 | case is BeginAnyFunctionDefinition:
28 | // No type collection on function definitions for now
29 | return []
30 | case let op as StoreProperty where specialProperties.contains(op.propertyName):
31 | // Recollect type of this variable, because major change happened
32 | return [instr.input(0)]
33 | default:
34 | // By default, collect types for all outputs of an instruction
35 | return Array(instr.allOutputs)
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Minimization/GenericInstructionReducer.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// Removes simple instructions from a program if they are not required.
16 | struct GenericInstructionReducer: Reducer {
17 | func reduce(_ code: inout Code, with verifier: ReductionVerifier) {
18 | for instr in code.reversed() {
19 | if !instr.isSimple || instr.op is Nop {
20 | continue
21 | }
22 |
23 | verifier.tryNopping(instructionAt: instr.index, in: &code)
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Minimization/ReplaceReducer.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // Attemplts to replace code snippets with other, potentially shorter snippets.
16 | struct ReplaceReducer: Reducer {
17 | func reduce(_ code: inout Code, with verifier: ReductionVerifier) {
18 | for instr in code {
19 | switch instr.op {
20 | case let op as Construct:
21 | // Try replacing with a simple call
22 | let newOp = CallFunction(numArguments: op.numArguments, spreads: [Bool](repeating: false, count: op.numArguments))
23 | verifier.tryReplacing(instructionAt: instr.index, with: Instruction(newOp, inouts: instr.inouts), in: &code)
24 | default:
25 | break
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Modules/Module.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // A module interacts with the fuzzer in some way but does not provide services
16 | // to the rest of the fuzzer and is not required for basic functionality.
17 | public protocol Module {
18 | // Will be called after the fuzzer is fully initialized and able to execute programs.
19 | // At this point, all other modules will have been instantiated but might not be initialized yet.
20 | // Useful if a module makes use of another module.
21 | func initialize(with fuzzer: Fuzzer)
22 | }
23 |
24 | extension Module {
25 | public func initialize(with fuzzer: Fuzzer) {}
26 |
27 | public var name: String {
28 | return String(describing: type(of: self))
29 | }
30 |
31 | public static var name: String {
32 | return String(describing: self)
33 | }
34 |
35 | /// Returns the instance of this module on the provided fuzzer instance if it exists, nil otherwise.
36 | public static func instance(for fuzzer: Fuzzer) -> Self? {
37 | if let instance = fuzzer.modules[self.name] {
38 | return instance as? Self
39 | } else {
40 | return nil
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Mutators/CodeGenMutator.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// A mutator that generates new code at random positions in a program.
16 | public class CodeGenMutator: BaseInstructionMutator {
17 | var analyzer = DeadCodeAnalyzer()
18 |
19 | public init() {
20 | super.init(maxSimultaneousMutations: defaultMaxSimultaneousMutations)
21 | }
22 |
23 | public override func beginMutation(of program: Program) {
24 | analyzer = DeadCodeAnalyzer()
25 | }
26 |
27 | public override func canMutate(_ instr: Instruction) -> Bool {
28 | analyzer.analyze(instr)
29 | return !analyzer.currentlyInDeadCode
30 | }
31 |
32 | public override func mutate(_ instr: Instruction, _ b: ProgramBuilder) {
33 | b.adopt(instr, keepTypes: true)
34 | b.generate(n: Int.random(in: 1...defaultMaxCodeGenerationAmount))
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Mutators/CombineMutator.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// A mutator that inserts a program in full into another one.
16 | public class CombineMutator: BaseInstructionMutator {
17 | var analyzer = DeadCodeAnalyzer()
18 |
19 | public init() {}
20 |
21 | public override func beginMutation(of program: Program) {
22 | analyzer = DeadCodeAnalyzer()
23 | }
24 |
25 | public override func canMutate(_ instr: Instruction) -> Bool {
26 | analyzer.analyze(instr)
27 | return !analyzer.currentlyInDeadCode
28 | }
29 |
30 | public override func mutate(_ instr: Instruction, _ b: ProgramBuilder) {
31 | b.adopt(instr, keepTypes: true)
32 | let other = b.fuzzer.corpus.randomElementForSplicing()
33 | b.trace("Inserting program \(other.id)")
34 | b.append(other)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Mutators/ConcatMutator.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// A mutator that concatenates two programs together.
16 | public class ConcatMutator: Mutator {
17 | override func mutate(_ program: Program, using b: ProgramBuilder) -> Program? {
18 | let suffix = b.fuzzer.corpus.randomElementForSplicing()
19 |
20 | b.append(program)
21 | b.trace("Appending program \(suffix.id)")
22 | b.append(suffix)
23 |
24 | return b.finalize()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Mutators/JITStressMutator.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// A mutator designed to call already JITed functions with different arguments or environment.
16 | ///
17 | /// In a way, this is a workaround for the fact that we don't have coverage feedback from JIT code.
18 | public class JITStressMutator: Mutator {
19 | public override init() {}
20 |
21 | override func mutate(_ program: Program, using b: ProgramBuilder) -> Program? {
22 | b.append(program)
23 |
24 | // Possibly change the environment
25 | b.generate(n: Int.random(in: 1...defaultMaxCodeGenerationAmount))
26 |
27 | // Call an existing (and hopefully JIT compiled) function again
28 | guard let f = b.randVar(ofConservativeType: .function()) else { return nil }
29 | guard let arguments = b.randCallArguments(for: f) else { return nil }
30 | b.callFunction(f, withArgs: arguments)
31 | return b.finalize()
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Mutators/Mutator.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// A mutator takes an existing program and mutates it in some way, thus producing a new program.
16 | public class Mutator {
17 | public var stats = ProgramGeneratorStats()
18 |
19 | /// Mutates the given program.
20 | ///
21 | /// - Parameters:
22 | /// - program: The program to mutate.
23 | /// - fuzzer: The fuzzer context for the mutation.
24 | /// - Returns: The mutated program or nil if the given program could not be mutated.
25 | public func mutate(_ program: Program, for fuzzer: Fuzzer) -> Program? {
26 | let b = fuzzer.makeBuilder(forMutating: program)
27 | b.traceHeader("Mutating \(program.id) with \(name)")
28 | return mutate(program, using: b)
29 | }
30 |
31 | func mutate(_ program: Program, using b: ProgramBuilder) -> Program? {
32 | fatalError("This method must be overridden")
33 | }
34 |
35 | /// The name of this mutator.
36 | public var name: String {
37 | return String(describing: type(of: self))
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Mutators/MutatorSettings.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 |
16 | // The settings here strive to achieve a correctness rate of around 75%. Empirically, this appears to be roughly optimal:
17 | // higher than that, and samples are too similar to each other, lower than that, and too many samples are invalid.
18 | // TODO evaluate this independently for every mutator.
19 |
20 | let defaultMaxSimultaneousMutations = 7
21 | let defaultMaxCodeGenerationAmount = 5
22 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Protobuf/README.md:
--------------------------------------------------------------------------------
1 | # Fuzzilli Protobuf Definitons
2 |
3 | Install the protoc compiler and the swift plugin:
4 |
5 | brew install swift-protobuf
6 |
7 | Then generate the swift files:
8 |
9 | protoc --swift_opt=Visibility=Public --swift_out=. program.proto operations.proto typesystem.proto sync.proto
10 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Protobuf/typesystem.proto:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | syntax = "proto3";
16 | package fuzzilli.protobuf;
17 |
18 | message Type {
19 | uint32 definiteType = 1;
20 | uint32 possibleType = 2;
21 | // The extension can be encoded as an index, referring to the
22 | // nth TypeExtension in the whole message. That way, it becomes
23 | // possible to encode duplicate extensions only once.
24 | oneof ext {
25 | uint32 extensionIdx = 3;
26 | TypeExtension extension = 4;
27 | }
28 | }
29 |
30 | message TypeExtension {
31 | repeated string properties = 1;
32 | repeated string methods = 2;
33 | string group = 3;
34 | FunctionSignature signature = 4;
35 | }
36 |
37 | message FunctionSignature {
38 | repeated Parameter parameters = 1;
39 | Type outputType = 2;
40 | }
41 |
42 | message Parameter {
43 | oneof param {
44 | PlainParameter plainParameter = 1;
45 | OptionalParameter optionalParameter = 2;
46 | RestParameter restParameter = 3;
47 | }
48 | }
49 |
50 | message PlainParameter {
51 | Type inputType = 1;
52 | }
53 |
54 | message OptionalParameter {
55 | Type inputType = 2;
56 | }
57 |
58 | message RestParameter {
59 | Type inputType = 2;
60 | }
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Util/CInterop.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Foundation
16 |
17 | func convertToCArray(_ array: [String]) -> UnsafeMutablePointer?> {
18 | let buffer = UnsafeMutablePointer?>.allocate(capacity: array.count + 1)
19 | for (i, str) in array.enumerated() {
20 | #if os(Windows)
21 | buffer[i] = UnsafePointer(str.withCString(_strdup))
22 | #else
23 | buffer[i] = UnsafePointer(str.withCString(strdup))
24 | #endif
25 | }
26 | buffer[array.count] = nil
27 | return buffer
28 | }
29 |
30 | func freeCArray(_ array: UnsafeMutablePointer?>, numElems: Int) {
31 | for arg in array ..< array + numElems {
32 | free(UnsafeMutablePointer(mutating: arg.pointee!))
33 | }
34 | array.deallocate()
35 | }
36 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Util/Error.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Foundation
16 |
17 | // Simple error enum for errors that only need to be displayed to the user.
18 | public enum FuzzilliError: Error {
19 | case instructionDecodingError(String)
20 | case typeDecodingError(String)
21 | case programDecodingError(String)
22 | case corpusImportError(String)
23 | case evaluatorStateImportError(String)
24 | case codeVerificationError(String)
25 | }
26 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Util/Misc.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Foundation
16 |
17 | func currentMillis() -> UInt64 {
18 | return UInt64(Date().timeIntervalSince1970 * 1000)
19 | }
20 |
21 | func uniqueElements(of list: [E]) -> [E] where E: Hashable {
22 | return Array(Set(list))
23 | }
24 |
25 | func align(_ v: Int, to desiredAlignment: Int) -> Int {
26 | let remainder = v % desiredAlignment
27 | return remainder != 0 ? desiredAlignment - remainder : 0
28 | }
29 |
30 | func measureTime(_ operation: () -> R) -> (R, Double) {
31 | let start = Date()
32 | let r = operation()
33 | let end = Date()
34 | return (r, end.timeIntervalSince(start))
35 | }
36 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Util/MovingAverage.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// Computes the average of some value over the last N samples.
16 | struct MovingAverage {
17 | private let n: Int
18 | private var lastN: [Double]
19 | private var sum = 0.0
20 | private var oldest = 0
21 | private var seen = 0
22 |
23 | var currentValue: Double {
24 | return sum / Double(min(seen, n))
25 | }
26 |
27 | init(n: Int) {
28 | self.n = n
29 | lastN = [Double](repeating: 0, count: n)
30 | }
31 |
32 | mutating func add(_ value: Double) {
33 | seen += 1
34 |
35 | sum -= lastN[oldest]
36 | lastN[oldest] = value
37 | sum += value
38 |
39 | oldest = (oldest + 1) % n
40 | }
41 |
42 | mutating func add(_ value: Int) {
43 | add(Double(value))
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Sources/Fuzzilli/Util/WeightedList.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /// Hacky implementation of a weighted list of elements.
16 | ///
17 | /// An element with weight 2 is 2x more likely to be selected by randomElement() than an element with weight 1. And so on.
18 | public struct WeightedList: Sequence {
19 | fileprivate var array = [Element]()
20 | fileprivate var elems = [Element]()
21 |
22 | public init(_ values: [(Element, Int)]) {
23 | for (e, w) in values {
24 | append(e, withWeight: w)
25 | }
26 | }
27 |
28 | fileprivate init(_ array: [Element], _ elems: [Element]) {
29 | self.array = array
30 | self.elems = elems
31 | }
32 |
33 | public mutating func append(_ elem: Element, withWeight weight: Int) {
34 | for _ in 0.. Element {
41 | return chooseUniform(from: array)
42 | }
43 |
44 | public func makeIterator() -> Array.Iterator {
45 | return elems.makeIterator()
46 | }
47 |
48 | public var count: Int {
49 | return elems.count
50 | }
51 |
52 | public mutating func append(_ rhs: WeightedList) {
53 | array += rhs.array
54 | elems += rhs.elems
55 | }
56 | }
57 |
58 | public func +(lhs: WeightedList, rhs: WeightedList) -> WeightedList {
59 | return WeightedList(lhs.array + rhs.array, lhs.elems + rhs.elems)
60 | }
61 |
--------------------------------------------------------------------------------
/Sources/FuzzilliCli/Profiles/DuktapeProfile.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Fuzzilli
16 |
17 | let duktapeProfile = Profile(
18 | processArguments: ["--reprl"],
19 |
20 | processEnv: ["UBSAN_OPTIONS": "handle_segv=0"],
21 |
22 | codePrefix: """
23 | function placeholder(){}
24 | function main() {
25 | """,
26 |
27 | codeSuffix: """
28 | }
29 | main();
30 | """,
31 |
32 | ecmaVersion: ECMAScriptVersion.es5,
33 |
34 | crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", "fuzzilli('FUZZILLI_CRASH', 1)"],
35 |
36 | additionalCodeGenerators: WeightedList([]),
37 |
38 | additionalProgramTemplates: WeightedList([]),
39 |
40 | disabledCodeGenerators: [],
41 |
42 | additionalBuiltins: [
43 | "CBOR.encode" : .function([.plain(.anything)] => .object()),
44 | "CBOR.decode" : .function([.plain(.object())] => .object()),
45 | "Duktape.fin" : .function([.plain(.object()), .opt(.function())] => .undefined),
46 | "Duktape.act" : .function([.plain(.number)] => .object()),
47 | "Duktape.gc" : .function([] => .undefined),
48 | "Duktape.compact" : .function([.plain(.object())] => .undefined),
49 | "placeholder" : .function([] => .undefined),
50 |
51 | ]
52 | )
53 |
--------------------------------------------------------------------------------
/Sources/FuzzilliCli/Profiles/JerryscriptProfile.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Fuzzilli
16 |
17 | let jerryscriptProfile = Profile(
18 | processArguments: ["-r","-s"],
19 |
20 | // processEnv: [:],
21 | processEnv: ["UBSAN_OPTIONS":"handle_segv=0"],
22 |
23 | codePrefix: """
24 | function placeholder(){}
25 | function main() {
26 | """,
27 |
28 | codeSuffix: """
29 | }
30 | main();
31 | """,
32 |
33 | ecmaVersion: ECMAScriptVersion.es5,
34 |
35 | crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", "fuzzilli('FUZZILLI_CRASH', 1)"],
36 |
37 | additionalCodeGenerators: WeightedList([]),
38 |
39 | additionalProgramTemplates: WeightedList([]),
40 |
41 | disabledCodeGenerators: [],
42 |
43 | additionalBuiltins: [:
44 | // "gc" : .function([] => .undefined),
45 | // "print" : .function([] => .undefined),
46 | // "resourceName" : .function([] => .undefined),
47 | // "placeholder" : .function([] => .undefined),
48 | ]
49 | )
50 |
--------------------------------------------------------------------------------
/Sources/FuzzilliCli/Profiles/Profile.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Fuzzilli
16 |
17 | struct Profile {
18 | let processArguments: [String]
19 | let processEnv: [String : String]
20 | let codePrefix: String
21 | let codeSuffix: String
22 | let ecmaVersion: ECMAScriptVersion
23 |
24 | // JavaScript code snippets that cause a crash in the target engine.
25 | // Used to verify that crashes can be detected.
26 | let crashTests: [String]
27 |
28 | let additionalCodeGenerators: WeightedList
29 | let additionalProgramTemplates: WeightedList
30 |
31 | let disabledCodeGenerators: [String]
32 |
33 | let additionalBuiltins: [String: Type]
34 | }
35 |
36 | let profiles = [
37 | "qjs": qjsProfile,
38 | "jsc": jscProfile,
39 | "spidermonkey": spidermonkeyProfile,
40 | "v8": v8Profile,
41 | "duktape": duktapeProfile,
42 | "jerryscript": jerryscriptProfile,
43 | ]
44 |
--------------------------------------------------------------------------------
/Sources/FuzzilliCli/Profiles/QjsProfile.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Fuzzilli
16 |
17 | let qjsProfile = Profile(
18 | processArguments: ["--reprl"],
19 |
20 | processEnv: ["UBSAN_OPTIONS": "handle_segv=0"],
21 |
22 | codePrefix: """
23 | function placeholder(){}
24 | function main() {
25 | """,
26 |
27 | codeSuffix: """
28 | }
29 | main();
30 | """,
31 |
32 | ecmaVersion: ECMAScriptVersion.es6,
33 |
34 | crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", "fuzzilli('FUZZILLI_CRASH', 1)", "fuzzilli('FUZZILLI_CRASH', 2)"],
35 |
36 | additionalCodeGenerators: WeightedList([]),
37 |
38 | additionalProgramTemplates: WeightedList([]),
39 |
40 | disabledCodeGenerators: [],
41 |
42 | additionalBuiltins: [
43 | "placeholder" : .function([] => .undefined)
44 | ]
45 | )
46 |
--------------------------------------------------------------------------------
/Sources/FuzzilliCli/Profiles/SpidermonkeyProfile.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Fuzzilli
16 |
17 | fileprivate let ForceSpidermonkeyIonGenerator = CodeGenerator("ForceSpidermonkeyIonGenerator", input: .function()) { b, f in
18 | guard let arguments = b.randCallArguments(for: f) else { return }
19 |
20 | let start = b.loadInt(0)
21 | let end = b.loadInt(100)
22 | let step = b.loadInt(1)
23 | b.forLoop(start, .lessThan, end, .Add, step) { _ in
24 | b.callFunction(f, withArgs: arguments)
25 | }
26 | }
27 |
28 | let spidermonkeyProfile = Profile(
29 | processArguments: [
30 | "--baseline-warmup-threshold=10",
31 | "--ion-warmup-threshold=100",
32 | "--ion-check-range-analysis",
33 | "--ion-extra-checks",
34 | "--fuzzing-safe",
35 | "--reprl",
36 | ],
37 |
38 | processEnv: ["UBSAN_OPTIONS": "handle_segv=0"],
39 |
40 | codePrefix: """
41 | function placeholder(){}
42 | function main() {
43 | """,
44 |
45 | codeSuffix: """
46 | gc();
47 | }
48 | main();
49 | """,
50 |
51 | ecmaVersion: ECMAScriptVersion.es6,
52 |
53 | crashTests: ["fuzzilli('FUZZILLI_CRASH', 0)", "fuzzilli('FUZZILLI_CRASH', 1)", "fuzzilli('FUZZILLI_CRASH', 2)"],
54 |
55 | additionalCodeGenerators: WeightedList([
56 | (ForceSpidermonkeyIonGenerator, 10),
57 | ]),
58 |
59 | additionalProgramTemplates: WeightedList([]),
60 |
61 | disabledCodeGenerators: [],
62 |
63 | additionalBuiltins: [
64 | "gc" : .function([] => .undefined),
65 | "enqueueJob" : .function([.plain(.function())] => .undefined),
66 | "drainJobQueue" : .function([] => .undefined),
67 | "bailout" : .function([] => .undefined),
68 | "placeholder" : .function([] => .undefined),
69 |
70 | ]
71 | )
72 |
--------------------------------------------------------------------------------
/Sources/FuzzilliCli/ProgramTemplateWeights.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Fuzzilli
16 |
17 | /// Assigned weights for the builtin program templates.
18 | let programTemplateWeights = [
19 | "JIT1Function": 2,
20 | "JIT2Functions": 2,
21 | "TypeConfusionTemplate": 1,
22 | ]
23 |
--------------------------------------------------------------------------------
/Sources/JS/LICENSE:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
--------------------------------------------------------------------------------
/Sources/JS/README.md:
--------------------------------------------------------------------------------
1 | # Javascript code
2 |
3 | We want to use these JS snippets when creating programs which collect runtime types.
4 | To make them avaibale to the Lifter, we need to save them as strings in swift files.
5 | These files will be included in Swift package.
6 | To do so run:
7 |
8 | ./generateSwift.sh
9 |
10 | However this is not optimal nor nice. Refactor me if you can.
11 |
--------------------------------------------------------------------------------
/Sources/JS/generateSwift.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | cd $(dirname $0)
3 | for filename in *.js; do
4 | newFilename="${filename/.js/.swift}"
5 | echo "Converting $filename to $newFilename"
6 | echo -e "// DO NOT EDIT!\n// Generated by $(basename -- "$0")" > $newFilename
7 | cat LICENSE >> $newFilename
8 | echo -e "public let ${filename/.js/}Script = \"\"\"\n$(grep -v '^//' $filename)\n\"\"\"" >> $newFilename
9 | done
10 |
--------------------------------------------------------------------------------
/Sources/JS/printTypes.js:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | var varNumbers = getObjectKeys(types)
15 | // Do not use for in to avoid iterating over prototype properties
16 | for (var i=0;i
19 | #include
20 | #if defined(_WIN32)
21 | #include
22 | #endif
23 |
24 | #if defined(_WIN32)
25 | typedef SOCKET socket_t;
26 |
27 | // We need C11 or newer due to the use of `_Generic`. Windows does not have a
28 | // signed size type, so we construct the equivalent type by inspecting the type
29 | // of `size_t` and mapping from the signed to the unsigned version.
30 | #if __STDC_VERSION__-0 >= 201112l
31 | typedef __typeof__(_Generic((size_t)0, \
32 | unsigned long long int : (long long int)0, \
33 | unsigned long int : (long int)0, \
34 | unsigned int : (int)0, \
35 | unsigned short : (short)0, \
36 | unsigned char : (char)0)) ssize_t;
37 | #endif
38 | #else
39 | typedef int socket_t;
40 | #define INVALID_SOCKET (-1)
41 | #endif
42 |
43 | socket_t socket_listen(const char* address, uint16_t port);
44 | socket_t socket_accept(socket_t socket);
45 | socket_t socket_connect(const char* address, uint16_t port);
46 |
47 | ssize_t socket_send(socket_t socket, const uint8_t* data, size_t length);
48 | ssize_t socket_recv(socket_t socket, uint8_t* buffer, size_t length);
49 |
50 | int socket_shutdown(socket_t socket);
51 | int socket_close(socket_t socket);
52 |
53 | #endif
54 |
--------------------------------------------------------------------------------
/Targets/ChakraCore/README.md:
--------------------------------------------------------------------------------
1 | # [TODO] Target: ChakraCore
2 |
3 | To build ChakraCore (ch) for fuzzing:
4 |
5 | 1. Clone the ChakraCore from https://github.com/microsoft/ChakraCore
6 | 2. Apply chakracore.patch. The patch should apply cleanly to git commit 41ad58a9eebf8d52a83424c8fccfaacdb14105ec
7 | 3. Run the fuzzbuild.sh script in the ChakraCore root directory
8 | 4. FuzzBuild/Debug/ch will be the JavaScript shell for the fuzzer
9 |
10 |
--------------------------------------------------------------------------------
/Targets/ChakraCore/fuzzbuild.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Copyright 2019 Google LLC
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https:#www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | ./build.sh --target-path=FuzzBuild --debug --static -j --cc=/usr/bin/clang-8 --cxx=/usr/bin/clang++-8
--------------------------------------------------------------------------------
/Targets/JavaScriptCore/README.md:
--------------------------------------------------------------------------------
1 | # Target: JavaScriptCore
2 |
3 | To build JavaScriptCore (jsc) for fuzzing:
4 |
5 | 1. Clone the WebKit mirror from https://github.com/WebKit/webkit
6 | 2. Apply Patches/\*. The patches should apply cleanly to the git revision specified in [./REVISION](./REVISION)
7 | (_Note_: If you clone WebKit from `git.webkit.org`, the commit hash will differ)
8 | 3. Run the fuzzbuild.sh script in the webkit root directory
9 | 4. FuzzBuild/Debug/bin/jsc will be the JavaScript shell for the fuzzer
10 |
--------------------------------------------------------------------------------
/Targets/JavaScriptCore/REVISION:
--------------------------------------------------------------------------------
1 | a93223d586d16a983e11df71869382de5b450a5e
2 |
--------------------------------------------------------------------------------
/Targets/JavaScriptCore/fuzzbuild.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Copyright 2019 Google LLC
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https:#www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | export WEBKIT_OUTPUTDIR=FuzzBuild
18 |
19 | if [ "$(uname)" == "Darwin" ]; then
20 | ./Tools/Scripts/build-jsc --jsc-only --debug --cmakeargs="-DENABLE_STATIC_JSC=ON -DCMAKE_CXX_FLAGS='-fsanitize-coverage=trace-pc-guard -O3'"
21 | elif [ "$(uname)" == "Linux" ]; then
22 | ./Tools/Scripts/build-jsc --jsc-only --debug --cmakeargs="-DENABLE_STATIC_JSC=ON -DCMAKE_C_COMPILER='/usr/bin/clang-12' -DCMAKE_CXX_COMPILER='/usr/bin/clang++-12' -DCMAKE_CXX_FLAGS='-fsanitize-coverage=trace-pc-guard -O3 -lrt'"
23 | else
24 | echo "Unsupported operating system"
25 | fi
26 |
--------------------------------------------------------------------------------
/Targets/Jerryscript/README.md:
--------------------------------------------------------------------------------
1 | # Target: JerryScript
2 |
3 | To build JerryScript for fuzzing:
4 |
5 | 1. Clone the JerryScript repository from https://github.com/jerryscript-project/jerryscript
6 | 2. Apply Patches/\*. The patches should apply cleanly to the git revision specified in [./REVISION](./REVISION)
7 | 3. Run the fuzzbuild.sh script in the jerryscript directory
8 | 4. ./build/bin/jerry will be the JavaScript shell for the fuzzer
9 |
--------------------------------------------------------------------------------
/Targets/Jerryscript/REVISION:
--------------------------------------------------------------------------------
1 | 0f0041d720adfd83012e59435c2f1b555c1234d5
2 |
--------------------------------------------------------------------------------
/Targets/Jerryscript/fuzzbuild.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export CC=clang
4 | python tools/build.py --compile-flag=-fsanitize-coverage=trace-pc-guard --profile=es2015-subset --lto=off --compile-flag=-D_POSIX_C_SOURCE=200809 --compile-flag=-Wno-strict-prototypes --stack-limit=15
5 |
--------------------------------------------------------------------------------
/Targets/QJS/README.md:
--------------------------------------------------------------------------------
1 | # Target: QuickJS
2 |
3 | To build QuickJS for fuzzing:
4 |
5 | 1. Clone the QuickJS mirror from https://github.com/horhof/quickjs
6 | 2. Apply Patches/\*. The patches should apply cleanly to the git revision specified in [./REVISION](./REVISION)
7 | 3. Build QuickJS with `make qjs`
8 | 4. The `qjs` binary will be the JavaScript shell for the fuzzer
9 |
--------------------------------------------------------------------------------
/Targets/QJS/REVISION:
--------------------------------------------------------------------------------
1 | c389f9594e83776ffb86410016959a7676728bf9
2 |
--------------------------------------------------------------------------------
/Targets/Spidermonkey/Patches/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/P1umer/fuzzilli4wasm/5ecdc393366f9c4920eeda2c0bd934d0919a02f5/Targets/Spidermonkey/Patches/.gitkeep
--------------------------------------------------------------------------------
/Targets/Spidermonkey/README.md:
--------------------------------------------------------------------------------
1 | # Target: Spidermonkey
2 |
3 | To build Spidermonkey for fuzzing:
4 |
5 | 1. Clone the Firefox mirror from https://github.com/mozilla/gecko-dev
6 | 2. Run the fuzzbuild.sh script in the js/src directory of the firefox checkout
7 | 3. fuzzbuild_OPT.OBJ/dist/bin/js will be the JavaScript shell for the fuzzer
8 |
--------------------------------------------------------------------------------
/Targets/Spidermonkey/REVISION:
--------------------------------------------------------------------------------
1 | 73330bf7355c0aef844c41d0d7eed2848e53c82f
2 |
--------------------------------------------------------------------------------
/Targets/Spidermonkey/fuzzbuild.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Copyright 2019 Google LLC
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https:#www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | FLAGS="-fsanitize-coverage=trace-pc-guard -g -DJS_MORE_DETERMINISTIC"
18 |
19 | export CXXFLAGS=$FLAGS
20 | export CC=clang-10
21 | export CXX=clang++-10
22 |
23 | mkdir fuzzbuild_OPT.OBJ
24 | cd fuzzbuild_OPT.OBJ
25 | /bin/sh ../configure.in --enable-debug --enable-optimize --disable-shared-js --enable-js-fuzzilli
26 |
27 | make -j$(getconf _NPROCESSORS_ONLN)
28 |
--------------------------------------------------------------------------------
/Targets/V8/Patches/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/P1umer/fuzzilli4wasm/5ecdc393366f9c4920eeda2c0bd934d0919a02f5/Targets/V8/Patches/.gitkeep
--------------------------------------------------------------------------------
/Targets/V8/README.md:
--------------------------------------------------------------------------------
1 | # Target: v8
2 |
3 | To build v8 for fuzzing:
4 |
5 | 1. Follow the instructions at https://v8.dev/docs/build
6 | 2. Run the fuzzbuild.sh script in the v8 root directory
7 | 3. out/fuzzbuild/d8 will be the JavaScript shell for the fuzzer
8 |
9 | Note that sanitizer coverage for v8 is currently not supported on macOS as it is missing from v8's custom clang toolchain.
10 |
--------------------------------------------------------------------------------
/Targets/V8/REVISION:
--------------------------------------------------------------------------------
1 | 8393133d6d6bb56923cce39a52884c264d8ded3d
2 |
--------------------------------------------------------------------------------
/Targets/V8/fuzzbuild.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Copyright 2019 Google LLC
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https:#www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | if [ "$(uname)" == "Darwin" ]; then
18 | # Sanitizer coverage doesn't work on macOS as it's not supported by the custom clang toolchain...
19 | gn gen out/fuzzbuild --args='is_debug=false dcheck_always_on=true v8_static_library=true v8_enable_slow_dchecks=true v8_enable_v8_checks=true v8_enable_verify_heap=true v8_enable_verify_csa=true target_cpu="x64"'
20 | elif [ "$(uname)" == "Linux" ]; then
21 | gn gen out/fuzzbuild --args='is_debug=false dcheck_always_on=true v8_static_library=true v8_enable_slow_dchecks=true v8_enable_v8_checks=true v8_enable_verify_heap=true v8_enable_verify_csa=true v8_fuzzilli=true sanitizer_coverage_flags="trace-pc-guard" target_cpu="x64"'
22 | else
23 | echo "Unsupported operating system"
24 | fi
25 | ninja -C ./out/fuzzbuild d8
26 |
--------------------------------------------------------------------------------
/Targets/duktape/README.md:
--------------------------------------------------------------------------------
1 | # Target: duktape
2 |
3 | To build duktape for fuzzing:
4 |
5 | 1. Download the master branch of https://github.com/svaarala/duktape
6 | 2. Run `make duk-fuzzilli`
7 |
8 | The executable will be named `duk-fuzzilli`, in the duktape directory.
--------------------------------------------------------------------------------
/Tests/FuzzilliTests/EnvironmentTest.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import XCTest
16 | @testable import Fuzzilli
17 |
18 | class EnvironmentTests: XCTestCase {
19 |
20 | func testJSEnvironmentConsistency() {
21 | // The constructor will already perform various consistency checks, so we don't repeat them here.
22 | let _ = JavaScriptEnvironment(additionalBuiltins: [:], additionalObjectGroups: [])
23 | }
24 | }
25 |
26 | extension EnvironmentTests {
27 | static var allTests : [(String, (EnvironmentTests) -> () throws -> Void)] {
28 | return [
29 | ("testJSEnvironmentConsistency", testJSEnvironmentConsistency),
30 | ]
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Tests/FuzzilliTests/InliningTest.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import XCTest
16 | @testable import Fuzzilli
17 |
18 | class InliningTests: XCTestCase {
19 | func testBasicInlining() {
20 | let fuzzer = makeMockFuzzer()
21 | let b = fuzzer.makeBuilder()
22 |
23 | let f = b.definePlainFunction(withSignature: FunctionSignature(withParameterCount: 3)) { args in
24 | b.beginIf(args[0]) {
25 | b.doReturn(value: args[1])
26 | }
27 | b.beginElse() {
28 | b.doReturn(value: args[2])
29 | }
30 | b.endIf()
31 | }
32 | var a1 = b.loadBool(true)
33 | var a2 = b.loadInt(1337)
34 | var r = b.callFunction(f, withArgs: [a1, a2])
35 | b.unary(.BitwiseNot, r)
36 |
37 | let program = b.finalize()
38 |
39 | let reducer = InliningReducer()
40 | var inlinedCode = reducer.inline(f, in: program.code)
41 |
42 | // Must normalize the code after inlining.
43 | inlinedCode.normalize()
44 |
45 | XCTAssert(inlinedCode.isStaticallyValid())
46 |
47 | let inlinedProgram = Program(with: inlinedCode)
48 |
49 | let u: Variable
50 |
51 | // Resulting program should be:
52 | a1 = b.loadBool(true)
53 | a2 = b.loadInt(1337)
54 | u = b.loadUndefined()
55 | r = b.loadUndefined()
56 | b.beginIf(a1) {
57 | b.reassign(r, to: a2)
58 | }
59 | b.beginElse {
60 | b.reassign(r, to: u)
61 | }
62 | b.endIf()
63 | b.unary(.BitwiseNot, r)
64 |
65 | let referenceProgram = b.finalize()
66 |
67 | XCTAssertEqual(inlinedProgram, referenceProgram)
68 | }
69 | }
70 |
71 | extension InliningTests {
72 | static var allTests : [(String, (InliningTests) -> () throws -> Void)] {
73 | return [
74 | ("testBasicInlining", testBasicInlining),
75 | ]
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Tests/FuzzilliTests/TestUtils.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | import Foundation
16 | @testable import Fuzzilli
17 |
18 | extension Program: Equatable {
19 | // Fairly expensive equality testing, but it's only needed for testing anyway... :)
20 | public static func == (lhs: Program, rhs: Program) -> Bool {
21 | // We consider two programs to be equal if their code is equal
22 | let code1 = lhs.code.map({ $0.asProtobuf() })
23 | let code2 = rhs.code.map({ $0.asProtobuf() })
24 | return code1 == code2
25 | }
26 | }
27 |
28 | // Convenience variable constructor
29 | func v(_ n: Int) -> Variable {
30 | return Variable(number: n)
31 | }
32 |
--------------------------------------------------------------------------------