├── LICENSE ├── README.md ├── compile.sh ├── engines ├── .gitignore ├── README.md ├── build-ch-cov.sh ├── build-ch.sh ├── build-jsc-cov.sh ├── build-jsc.sh ├── build-sm-cov.sh ├── build-sm.sh ├── build-v8-cov.sh ├── build-v8.sh ├── compiler │ ├── .gitignore │ ├── clang │ ├── clang++ │ └── proxy.py ├── download-engine.sh └── utils │ ├── .gitignore │ ├── args_debug.gn │ ├── args_release.gn │ ├── chakra.patch │ └── new-chakra.patch └── fuzz ├── .gitignore ├── TS ├── .gitignore ├── base │ ├── const │ │ ├── number.ts │ │ ├── regexp.ts │ │ └── string.ts │ ├── engine │ │ ├── ast.ts │ │ ├── builtin.ts │ │ ├── context.ts │ │ ├── esbuild.ts │ │ ├── exp.ts │ │ ├── function.ts │ │ ├── literal.ts │ │ ├── statement.ts │ │ ├── type.ts │ │ └── var.ts │ ├── esgenerator.ts │ ├── esinfer.ts │ ├── esmutator.ts │ ├── esparse.ts │ ├── espreference.ts │ ├── esspecs.ts │ ├── estestcase.ts │ ├── estypes.ts │ ├── esverifier.ts │ ├── esweight.ts │ └── utils.ts ├── config.ts ├── esfuzz.ts ├── package.json ├── redis_ctrl.ts ├── tsconfig.json └── typer │ ├── .gitignore │ ├── jslib │ ├── chakra.js │ ├── ffx.js │ ├── jsc.js │ └── v8.js │ ├── resolve.py │ ├── typer.py │ └── typer.ts ├── afl ├── .gitignore ├── Makefile ├── QuickStartGuide.txt ├── README ├── README-JS.md ├── afl-analyze.c ├── afl-as.c ├── afl-as.h ├── afl-fuzz.c ├── afl-gcc.c ├── afl-gotcpu.c ├── afl-showmap.c ├── afl-tmin.c ├── alloc-inl.h ├── config.h ├── debug.h ├── dictionaries │ ├── README.dictionaries │ ├── gif.dict │ ├── html_tags.dict │ ├── jpeg.dict │ ├── js.dict │ ├── json.dict │ ├── pdf.dict │ ├── png.dict │ ├── sql.dict │ ├── tiff.dict │ ├── webp.dict │ └── xml.dict ├── docs │ ├── COPYING │ ├── ChangeLog │ ├── INSTALL │ ├── QuickStartGuide.txt │ ├── README │ ├── env_variables.txt │ ├── historical_notes.txt │ ├── life_pro_tips.txt │ ├── notes_for_asan.txt │ ├── parallel_fuzzing.txt │ ├── perf_tips.txt │ ├── sister_projects.txt │ ├── status_screen.txt │ ├── technical_details.txt │ ├── visualization │ │ └── afl_gzip.png │ └── vuln_samples │ │ ├── bash-cmd-exec.var │ │ ├── bash-uninit-mem.var │ │ ├── ffmpeg-h264-bad-ptr-800m.mp4 │ │ ├── ffmpeg-h264-bad-read.mp4 │ │ ├── ffmpeg-h264-call-stack-overflow.mp4 │ │ ├── file-fpu-exception.elf │ │ ├── firefox-bmp-leak.bmp │ │ ├── firefox-chrome-leak.jpg │ │ ├── firefox-gif-leak.gif │ │ ├── firefox-gif-leak2.gif │ │ ├── jxrlib-crash.jxr │ │ ├── jxrlib-crash2.jxr │ │ ├── jxrlib-crash3.jxr │ │ ├── jxrlib-crash4.jxr │ │ ├── lesspipe-cpio-bad-write.cpio │ │ ├── libjpeg-sos-leak.jpg │ │ ├── libjpeg-turbo-dht-leak.jpg │ │ ├── libtiff-bad-write.tif │ │ ├── libtiff-uninit-mem.tif │ │ ├── libtiff-uninit-mem2.tif │ │ ├── libtiff-uninit-mem3.tif │ │ ├── libtiff-uninit-mem4.tif │ │ ├── libxml2-bad-read.xml │ │ ├── msie-dht-leak.jpg │ │ ├── msie-jxr-mem-leak.jxr │ │ ├── msie-png-mem-leak.png │ │ ├── msie-tiff-mem-leak.tif │ │ ├── msie-zlib-dos.png │ │ ├── openssl-null-ptr.der │ │ ├── openssl-null-ptr2.der │ │ ├── photoshop-mem-leak.jpg │ │ ├── sqlite-bad-free.sql │ │ ├── sqlite-bad-ptr.sql │ │ ├── sqlite-bad-ptr2.sql │ │ ├── sqlite-bad-ptr3.sql │ │ ├── sqlite-heap-overflow.sql │ │ ├── sqlite-heap-overwrite.sql │ │ ├── sqlite-negative-memset.sql │ │ ├── sqlite-null-ptr1.sql │ │ ├── sqlite-null-ptr10.sql │ │ ├── sqlite-null-ptr11.sql │ │ ├── sqlite-null-ptr12.sql │ │ ├── sqlite-null-ptr13.sql │ │ ├── sqlite-null-ptr14.sql │ │ ├── sqlite-null-ptr15.sql │ │ ├── sqlite-null-ptr2.sql │ │ ├── sqlite-null-ptr3.sql │ │ ├── sqlite-null-ptr4.sql │ │ ├── sqlite-null-ptr5.sql │ │ ├── sqlite-null-ptr6.sql │ │ ├── sqlite-null-ptr7.sql │ │ ├── sqlite-null-ptr8.sql │ │ ├── sqlite-null-ptr9.sql │ │ ├── sqlite-oob-read.sql │ │ ├── sqlite-oob-write.sql │ │ ├── sqlite-stack-buf-overflow.sql │ │ ├── sqlite-stack-exhaustion.sql │ │ ├── sqlite-unint-mem.sql │ │ ├── sqlite-use-after-free.sql │ │ ├── strings-bfd-badptr.elf │ │ ├── strings-bfd-badptr2.elf │ │ ├── strings-stack-overflow │ │ ├── strings-unchecked-ctr.elf │ │ ├── tcpdump-arp-crash.pcap │ │ ├── tcpdump-ppp-crash.pcap │ │ ├── unrtf-arbitrary-read.rtf │ │ └── unzip-t-mem-corruption.zip ├── experimental │ ├── README.experiments │ ├── argv_fuzzing │ │ └── argv-fuzz-inl.h │ ├── asan_cgroups │ │ └── limit_memory.sh │ ├── bash_shellshock │ │ └── shellshock-fuzz.diff │ ├── canvas_harness │ │ └── canvas_harness.html │ ├── clang_asm_normalize │ │ └── as │ ├── crash_triage │ │ └── triage_crashes.sh │ ├── distributed_fuzzing │ │ └── sync_script.sh │ ├── libpng_no_checksum │ │ └── libpng-nocrc.patch │ ├── persistent_demo │ │ └── persistent_demo.c │ └── post_library │ │ ├── post_library.so.c │ │ └── post_library_png.so.c ├── hash.h ├── init │ ├── ch.sh │ └── jsc.sh ├── libdislocator │ ├── Makefile │ ├── README.dislocator │ └── libdislocator.so.c ├── libtokencap │ ├── Makefile │ ├── README.tokencap │ └── libtokencap.so.c ├── llvm_mode │ ├── Makefile │ ├── README.llvm │ ├── afl-clang-fast.c │ ├── afl-llvm-pass.so.cc │ └── afl-llvm-rt.o.c ├── qemu_mode │ ├── README.qemu │ ├── build_qemu_support.sh │ └── patches │ │ ├── afl-qemu-cpu-inl.h │ │ ├── cpu-exec.diff │ │ ├── elfload.diff │ │ └── syscall.diff ├── run │ ├── ch.sh │ └── jsc.sh ├── test-instr.c └── types.h └── scripts ├── .gitignore ├── kill.sh ├── make_initial_corpus.py ├── populate.sh ├── prepare.sh ├── redis.py ├── run-all.py └── run.sh /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 gts3.org (SSLab@Gatech) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DIE 2 | 3 | Repository for "Fuzzing JavaScript Engines with Aspect-preserving Mutation" (in S&P'20). You can check the [paper](https://gts3.org/assets/papers/2020/park:die.pdf) for technical details. 4 | 5 | 6 | ## Environment 7 | 8 | Tested on Ubuntu 18.04 with following environment. 9 | * Python v3.6.10 10 | * npm v6.14.6 11 | * n v6.7.0 12 | 13 | ## General Setup 14 | 15 | For nodejs and npm, 16 | ``` 17 | $ sudo apt-get -y install npm 18 | $ sudo npm install -g n 19 | $ sudo n stable 20 | ``` 21 | For redis-server, 22 | ``` 23 | $ sudo apt install redis-server 24 | ``` 25 | we choose clang-6.0 to compile afl and browsers smoothly. 26 | ``` 27 | $ sudo apt-get -y install clang-6.0 28 | ``` 29 | 30 | ## DIE Setup 31 | 32 | To setup environment for AFL, 33 | ``` 34 | $ cd fuzz/scripts 35 | $ sudo ./prepare.sh 36 | ``` 37 | 38 | To compile whole project, 39 | ``` 40 | $ ./compile.sh 41 | ``` 42 | 43 | ### Server Setup 44 | * Make Corpus Directory 45 | (We used [Die-corpus](https://github.com/sslab-gatech/DIE-corpus.git) as corpus) 46 | ``` 47 | $ git clone https://github.com/sslab-gatech/DIE-corpus.git 48 | $ python3 ./fuzz/scripts/make_initial_corpus.py ./DIE-corpus ./corpus 49 | ``` 50 | * Make ssh-tunnel for connection with redis-server 51 | ``` 52 | $ ./fuzz/scripts/redis.py 53 | ``` 54 | * Dry run with corpus 55 | ``` 56 | $ ./fuzz/scripts/populate.sh [target binary path] [path of DIE-corpus dir] [target js engine (ch/jsc/v8/ffx)] 57 | # Example 58 | $ ./fuzz/scripts/populate.sh ~/ch ./DIE-corpus ch 59 | ``` 60 | It's done! Your corpus is well executed and the data should be located on redis-server. 61 | 62 | #### Tips 63 | To check the redis-data, 64 | ``` 65 | $ redis-cli -p 9000 66 | 127.0.0.1:9000> keys * 67 | ``` 68 | If the result contains "crashBitmap", "crashQueue", "pathBitmap", "newPathsQueue" keys, the fuzzer was well registered and executed. 69 | 70 | 71 | ### Client Setup 72 | * Make ssh-tunnel for connection with redis-server 73 | ``` 74 | $ ./fuzz/scripts/redis.py 75 | ``` 76 | 77 | * Usage 78 | ``` 79 | $ ./fuzz/scripts/run.sh [target binary path] [path of DIE-corpus dir] [target js engine (ch/jsc/v8/ffx)] 80 | # Example 81 | $ ./fuzz/scripts/run.sh ~/ch ./DIE-corpus ch 82 | ``` 83 | 84 | * Check if it's running 85 | ``` 86 | $ tmux ls 87 | ``` 88 | You can find a session named `fuzzer` if it's running. 89 | 90 | ### Typer 91 | 92 | We used d8 to profile type information. So, please change 93 | d8_path in fuzz/TS/typer/typer.py before execution. 94 | 95 | ``` 96 | cd fuzz/TS/typer 97 | python3 typer.py [corpus directory] 98 | ``` 99 | *.jsi file will be created if instrumentation works well. 100 | *.t file will be created if profiling works well. 101 | 102 | ## CVEs 103 | If you find bugs and get CVEs by running DIE, please let us know. 104 | 105 | * ChakraCore: CVE-2019-0609, CVE-2019-1023, CVE-2019-1300, CVE-2019-0990, CVE-2019-1092 106 | * JavaScriptCore: CVE-2019-8676, CVE-2019-8673, CVE-2019-8811, CVE-2019-8816 107 | * V8: CVE-2019-13730, CVE-2019-13764, CVE-2020-6382 108 | 109 | ## Contacts 110 | 111 | * Soyeon Park 112 | * Wen Xu 113 | * Insu Yun 114 | * Daehee Jang 115 | * Taesoo Kim 116 | 117 | ## Citation 118 | 119 | ``` 120 | @inproceedings{park:die, 121 | title = {{Fuzzing JavaScript Engines with Aspect-preserving Mutation}}, 122 | author = {Soyeon Park and Wen Xu and Insu Yun and Daehee Jang and Taesoo Kim}, 123 | booktitle = {Proceedings of the 41st IEEE Symposium on Security and Privacy (Oakland)}, 124 | month = may, 125 | year = 2020, 126 | address = {San Francisco, CA}, 127 | } 128 | ``` 129 | -------------------------------------------------------------------------------- /compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | pushd fuzz/TS 4 | npm i 5 | node_modules/.bin/tsc 6 | popd 7 | 8 | pushd fuzz/afl 9 | make clean 10 | make CC=clang-6.0 11 | #pushd llvm_mode 12 | #make clean 13 | #make CC=clang-6.0 CXX=g++ 14 | #popd 15 | popd 16 | -------------------------------------------------------------------------------- /engines/.gitignore: -------------------------------------------------------------------------------- 1 | v8/ 2 | v8-*/ 3 | gecko-dev/ 4 | webkit*/ 5 | chakracore-*/ 6 | -------------------------------------------------------------------------------- /engines/README.md: -------------------------------------------------------------------------------- 1 | ### Usage 2 | 3 | ./download-engine.sh ch 1.11.5 4 | ./download-engine.sh jsc 2.23.3 5 | 6 | ./build-ch.sh 1.11.5 7 | ./build-jsc.sh 2.23.3 8 | 9 | -------------------------------------------------------------------------------- /engines/build-ch-cov.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export CC="$PWD/compiler/clang" 4 | export CXX="$PWD/compiler/clang++" 5 | 6 | if [ -z $1 ] ; then 7 | echo "usage: $0 " 8 | exit 1 9 | fi 10 | 11 | pushd chakracore-$1 12 | patch -p0 < ../utils/new-chakra.patch 13 | 14 | export CXXFLAGS="-O1 -fno-omit-frame-pointer" 15 | export CFLAGS="-O1 -fno-omit-frame-pointer" 16 | 17 | ./build.sh --static -j $(nproc) -d --cc=$CC --cxx=$CXX 18 | -------------------------------------------------------------------------------- /engines/build-ch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z $1 ] ; then 4 | echo "usage: $0 " 5 | exit 1 6 | fi 7 | 8 | LLVM_ROOT="/usr/bin" 9 | 10 | # old version (1.5) needs clang-3.8.0 11 | version=${1%.*} 12 | version=$(echo $version | cut -f2 -d.) 13 | if (( $(echo "$version > 6" | bc -l) )); then 14 | CLANG="$LLVM_ROOT/clang-6.0" 15 | CLANGXX="$LLVM_ROOT/clang++-6.0" 16 | echo "Clang version is 6.0" 17 | else 18 | CLANG="$LLVM_ROOT/clang-3.8" 19 | CLANGXX="$LLVM_ROOT/clang++-3.8" 20 | echo "Clang version is 3.8" 21 | fi 22 | 23 | 24 | CLANG="$LLVM_ROOT/clang-6.0" 25 | CLANGXX="$LLVM_ROOT/clang++-6.0" 26 | pushd chakracore-$1 27 | patch -p0 < ../utils/new-chakra.patch 28 | 29 | #debug mode 30 | # it seems ASAN affects some bugs, so we turn off 31 | #./build.sh --sanitize=address --static -j $(nproc) -d --cc=$CLANG --cxx=$CLANGXX 32 | ./build.sh --static -j $(nproc) -d --cc=$CLANG --cxx=$CLANGXX 33 | 34 | #release mode 35 | # it seems ASAN affects some bugs, so we turn off 36 | #./build.sh --sanitize=address --static -j $(nproc) --cc=$CLANG --cxx=$CLANGXX 37 | ./build.sh --static -j $(nproc) --cc=$CLANG --cxx=$CLANGXX 38 | 39 | -------------------------------------------------------------------------------- /engines/build-jsc-cov.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export CC="$PWD/compiler/clang" 4 | export CXX="$PWD/compiler/clang++" 5 | 6 | if [ -z $1 ] ; then 7 | echo "usage: $0 " 8 | exit 1 9 | fi 10 | pushd webkit-$1 11 | 12 | ./Tools/Scripts/build-jsc --jsc-only --debug --cmakeargs="-DENABLE_STATIC_JSC=ON" 13 | -------------------------------------------------------------------------------- /engines/build-jsc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # old version doesn't support clang ? 5 | export LLVM_ROOT="/usr/bin" 6 | export CC="gcc-7" 7 | # "$LLVM_ROOT/clang-6.0" 8 | export CXX="g++-7" 9 | # "$LLVM_ROOT/clang++-6.0" 10 | 11 | if [ -z $1 ] ; then 12 | echo "usage: $0 " 13 | exit 1 14 | fi 15 | pushd webkit-$1 16 | 17 | # debug mode 18 | #CFLAGS=-g ./Tools/Scripts/build-jsc --jsc-only --makeargs="-j$(nproc)" --debug --system-malloc --cmakeargs=-DCMAKE_CXX_FLAGS="-fsanitize=address -fno-omit-frame-pointer -g" 19 | CFLAGS=-g ./Tools/Scripts/build-jsc --jsc-only --makeargs="-j$(nproc)" --debug --system-malloc --cmakeargs=-DCMAKE_CXX_FLAGS="-g" 20 | # release mode 21 | #CFLAGS=-g ./Tools/Scripts/build-jsc --jsc-only --makeargs="-j$(nproc)" --cmakeargs=-DCMAKE_CXX_FLAGS="-fsanitize=address -fno-omit-frame-pointer -g" 22 | CFLAGS=-g ./Tools/Scripts/build-jsc --jsc-only --makeargs="-j$(nproc)" --cmakeargs=-DCMAKE_CXX_FLAGS="-g" 23 | 24 | # The symbol information can take quite some time to parse by the debugger. We can reduce the load time of the debugger significantly by running gdb-add-index on both jsc and libJavaScriptCore.so. 25 | # how to run engine with dumping bytecodes 26 | # JSC_dumpBytecodeAtDFGTime=true JSC_useConcurrentJIT=false JSC_dumpDFGDisassembly=true ../../Release/bin/jsc ~/jsfuzz/js-static/my_test/WebKit/optimization/redundancy/cve-2018-4233.js 2>out 27 | -------------------------------------------------------------------------------- /engines/build-sm-cov.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | pushd gecko-dev/js/src 4 | 5 | HASH=`git rev-parse HEAD` 6 | 7 | 8 | echo $BUILD 9 | autoconf2.13 10 | 11 | LLVM_ROOT="/usr/local/bin" 12 | export CC="$PWD/compiler/clang" 13 | export CXX="$PWD/compiler/clang++" 14 | 15 | export CXXFLAGS="-O1 -fno-omit-frame-pointer" 16 | export CFLAGS="-O1 -fno-omit-frame-pointer" 17 | mkdir $HASH 18 | pushd $HASH 19 | 20 | BUILD="Debug" 21 | mkdir $BUILD 22 | pushd $BUILD 23 | 24 | #../../configure --enable-debug --disable-optimize --enable-address-sanitizer --disable-jemalloc 25 | ../../configure --enable-debug --enable-optimize 26 | make -j 8 27 | 28 | popd 29 | 30 | #BUILD="Release" 31 | #mkdir $BUILD 32 | #pushd $BUILD 33 | #../../configure --enable-optimize 34 | #make -j 8 35 | -------------------------------------------------------------------------------- /engines/build-sm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | pushd gecko-dev/js/src 4 | 5 | HASH=`git rev-parse HEAD` 6 | 7 | 8 | echo $BUILD 9 | autoconf2.13 10 | 11 | LLVM_ROOT="/usr/local/bin" 12 | CC="$LLVM_ROOT/clang" \ 13 | CXX="$LLVM_ROOT/clang++" \ 14 | 15 | CFLAGS="-fsanitize=address" \ 16 | CXXFLAGS="-fsanitize=address" \ 17 | LDFLAGS="-fsanitize=address" \ 18 | mkdir $HASH 19 | pushd $HASH 20 | 21 | BUILD="Debug" 22 | mkdir $BUILD 23 | pushd $BUILD 24 | 25 | #../../configure --enable-debug --disable-optimize --enable-address-sanitizer --disable-jemalloc 26 | ../../configure --enable-debug --enable-optimize 27 | make -j 8 28 | 29 | popd 30 | 31 | BUILD="Release" 32 | mkdir $BUILD 33 | pushd $BUILD 34 | #../../configure --enable-optimize --enable-address-sanitizer --disable-jemalloc 35 | ../../configure --enable-optimize 36 | make -j 8 37 | -------------------------------------------------------------------------------- /engines/build-v8-cov.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z $1 ] ; then 4 | echo "usage: $0 " 5 | exit 1 6 | fi 7 | 8 | if [ ! -d "utils/depot_tools" ]; then 9 | git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git utils/depot_tools 10 | fi 11 | 12 | export PATH=$PATH:$PWD/utils/depot_tools 13 | export CC="$PWD/compiler/clang" 14 | export CXX="$PWD/compiler/clang++" 15 | 16 | pushd v8-$1/v8 17 | 18 | # only for mindwipe.. 19 | export PYTHONHTTPSVERIFY=0 20 | gclient sync 21 | 22 | ./build/install-build-deps.sh 23 | 24 | #tools/dev/gm.py x64.debug 25 | rm -rf out/Debug 26 | gn args out/Debug 27 | cp ../../utils/args_debug.gn out/Debug/args.gn 28 | gn args out/Debug 29 | mv third_party/llvm-build/Release+Asserts/bin/clang third_party/llvm-build/Release+Asserts/bin/clang.bak 30 | #rm third_party/llvm-build/Release+Asserts/bin/clang++ third_party/llvm-build/Release+Asserts/bin/clang-cl 31 | ln -s $PWD/../../compiler/proxy.py third_party/llvm-build/Release+Asserts/bin/clang 32 | #ln -s $PWD/../../compiler/proxy.py third_party/llvm-build/Release+Asserts/bin/clang++ 33 | #ln -s $PWD/../../compiler/proxy.py third_party/llvm-build/Release+Asserts/bin/clang-cl 34 | ninja -C out/Debug 35 | 36 | 37 | #gn args out/Release 38 | #cp ../../utils/args_release.gn out/Release/args.gn 39 | #gn args out/Release 40 | #ninja -C out/Release 41 | -------------------------------------------------------------------------------- /engines/build-v8.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z $1 ] ; then 4 | echo "usage: $0 " 5 | exit 1 6 | fi 7 | 8 | if [ ! -d "utils/depot_tools" ]; then 9 | git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git utils/depot_tools 10 | fi 11 | 12 | export PATH=$PATH:$PWD/utils/depot_tools 13 | 14 | pushd v8-$1/v8 15 | 16 | export PYTHONHTTPSVERIFY=0 17 | gclient sync 18 | 19 | ./build/install-build-deps.sh 20 | 21 | #tools/dev/gm.py x64.debug 22 | gn args out/Debug 23 | cp ../../utils/args_debug.gn out/Debug/args.gn 24 | gn args out/Debug 25 | ninja -C out/Debug 26 | 27 | 28 | gn args out/Release 29 | cp ../../utils/args_release.gn out/Release/args.gn 30 | gn args out/Release 31 | ninja -C out/Release 32 | -------------------------------------------------------------------------------- /engines/compiler/.gitignore: -------------------------------------------------------------------------------- 1 | /proxy.log 2 | -------------------------------------------------------------------------------- /engines/compiler/clang: -------------------------------------------------------------------------------- 1 | proxy.py -------------------------------------------------------------------------------- /engines/compiler/clang++: -------------------------------------------------------------------------------- 1 | proxy.py -------------------------------------------------------------------------------- /engines/compiler/proxy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import os 5 | 6 | ROOT = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) 7 | AFL_ROOT = os.path.join(ROOT, "../../fuzz/afl") 8 | this_is_chakra = False 9 | this_is_v8 = True 10 | 11 | def find_engine(cmdline): 12 | #global this_is_chakra 13 | if this_is_chakra : 14 | return "CH" 15 | if this_is_v8 : 16 | return "V8" 17 | for arg in cmdline: 18 | if "JavaScriptCore" in arg: 19 | return "JSC" 20 | if "chakracore" in arg : 21 | return "CH" 22 | if "third_party" in arg: 23 | return "V8" 24 | 25 | return None 26 | 27 | def is_target_jsc(cmdline): 28 | SIGNATURES = ["b3", "dfg", "jit", "domjit", "ftl", "bytecode", "bytecompiler", "llint"] 29 | 30 | # JSC unified multiple sources into one and compile them together. 31 | # Therfore, currently, we see the unified source's contents 32 | # and check if it is JIT-related. 33 | for i in range(len(cmdline) - 1): 34 | if cmdline[i] != '-c': 35 | continue 36 | 37 | source_path = cmdline[i + 1] 38 | try: 39 | data = open(source_path, "r").read() 40 | return any([sig in data for sig in SIGNATURES]) 41 | except ValueError: 42 | # It is possible that we cannot access the source file 43 | return False 44 | 45 | # If we compile a binary 46 | return True 47 | 48 | def is_target_ch(cmdline) : 49 | for i in range(len(cmdline) - 1): 50 | if cmdline[i] != '-c': 51 | continue 52 | 53 | source_path = cmdline[i + 1] 54 | if "Runtime/Base/ThreadContext.cpp" in source_path : 55 | return False 56 | return True 57 | 58 | 59 | def is_target(cmdline): 60 | engine = find_engine(cmdline) 61 | 62 | if engine is None: 63 | return False 64 | elif engine == "JSC": 65 | return is_target_jsc(cmdline) 66 | elif engine == "CH" : 67 | return is_target_ch(cmdline) 68 | elif engine == "V8" : 69 | return True 70 | def remove(l, e): 71 | try: 72 | l.remove(e) 73 | except ValueError: 74 | pass 75 | 76 | def rewrite(cmdline): 77 | new_cmdline = [] 78 | engine = find_engine(cmdline) 79 | if engine == "V8": 80 | remove(cmdline, "-fcomplete-member-pointers") 81 | remove(cmdline, "-fcrash-diagnostics-dir=../../tools/clang/crashreports") 82 | remove(cmdline, "-Werror") 83 | for arg in cmdline: 84 | if "--color-diagnostics" in arg: 85 | # cmdline[cmdline.index(arg)] = arg.replace("--color-diagnostics", "") 86 | continue 87 | if "-fuse-ld=lld" in arg: 88 | # cmdline[cmdline.index(arg)] = arg.replace("-fuse-ld=lld", "") 89 | continue 90 | if "-Wa,-fdebug-compilation-dir,." in arg: 91 | # cmdline[cmdline.index(arg)] = arg.replace("-Wa,-fdebug-compilation-dir,.", "") 92 | continue 93 | if "--no-call-graph-profile-sort" in arg: 94 | continue 95 | new_cmdline.append(arg) 96 | print(new_cmdline) 97 | 98 | 99 | return new_cmdline 100 | 101 | if __name__ == '__main__': 102 | new_cmdline = sys.argv[:] 103 | compiler = os.path.basename(sys.argv[0]) 104 | 105 | if is_target(new_cmdline): 106 | if compiler == "clang": 107 | new_cmdline[0] = os.path.join(AFL_ROOT, "afl-clang-fast") 108 | else: 109 | assert(compiler == "clang++") 110 | new_cmdline[0] = os.path.join(AFL_ROOT, "afl-clang-fast++") 111 | else: 112 | new_cmdline[0] = compiler 113 | 114 | new_cmdline = rewrite(new_cmdline) 115 | with open(os.path.join(ROOT, "proxy.log"), "a") as f: 116 | f.write(' '.join(new_cmdline) + "\n") 117 | 118 | os.execlp(new_cmdline[0], *new_cmdline) 119 | -------------------------------------------------------------------------------- /engines/download-engine.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # check webkit latest here: https://webkitgtk.org/releases/ 4 | 5 | if [ -z $1 ] || [ -z $2 ] ; then 6 | echo "usage: $0 (engines : ch, jsc, v8, sm)" 7 | fi 8 | 9 | if [ "$1" = "jsc" ] && [ ! -d "webkit-$2" ] ; then 10 | svn co https://svn.webkit.org/repository/webkit/releases/WebKitGTK/webkit-$2 11 | elif [ "$1" = "ch" ] && [ ! -d "chakracore-$2" ] ; then 12 | if [ "$2" = "m" ]; then 13 | git clone --single-branch --branch master https://github.com/Microsoft/ChakraCore.git chakracore-$2 14 | else 15 | git clone --single-branch --branch v$2 https://github.com/Microsoft/ChakraCore.git chakracore-$2 16 | fi 17 | elif [ "$1" = "v8" ] && [ ! -d "v8-$2" ]; then 18 | PATH=$PATH:$PWD/utils/depot_tools 19 | mkdir v8-$2 20 | pushd v8-$2 21 | export PYTHONHTTPSVERIFY=0 22 | fetch v8 23 | pushd v8 24 | git checkout origin/$2 25 | elif [ "$1" = "sm" ] && [ ! -d "gecko-dev" ] ; then 26 | git clone https://github.com/mozilla/gecko-dev.git 27 | elif [ "$1" = "sm" ] && [ "$2" = "latest" ] ; then 28 | pushd gecko-dev/ 29 | git pull 30 | fi 31 | -------------------------------------------------------------------------------- /engines/utils/.gitignore: -------------------------------------------------------------------------------- 1 | depot_tools/ 2 | -------------------------------------------------------------------------------- /engines/utils/args_debug.gn: -------------------------------------------------------------------------------- 1 | is_debug = true 2 | dcheck_always_on=true 3 | v8_static_library=true 4 | v8_enable_slow_dchecks = true 5 | v8_enable_v8_checks = true 6 | v8_enable_verify_heap = true 7 | v8_enable_verify_csa = true 8 | v8_enable_verify_predictable = true 9 | v8_enable_backtrace = true 10 | v8_enable_fast_mksnapshot = true 11 | v8_optimized_debug = false 12 | is_asan = true 13 | is_component_build = false 14 | target_cpu = "x64" 15 | -------------------------------------------------------------------------------- /engines/utils/args_release.gn: -------------------------------------------------------------------------------- 1 | is_debug = false 2 | dcheck_always_on=false 3 | v8_static_library=true 4 | v8_enable_slow_dchecks = true 5 | v8_enable_v8_checks = true 6 | v8_enable_verify_heap = true 7 | v8_enable_verify_csa = true 8 | v8_enable_verify_predictable = true 9 | v8_enable_backtrace = true 10 | v8_enable_fast_mksnapshot = true 11 | v8_optimized_debug = false 12 | is_asan = true 13 | is_component_build = false 14 | target_cpu = "x64" 15 | -------------------------------------------------------------------------------- /engines/utils/chakra.patch: -------------------------------------------------------------------------------- 1 | diff --git bin/ch/ch.cpp bin/ch/ch.cpp 2 | index c78cad6..9442614 100644 3 | --- bin/ch/ch.cpp 4 | +++ bin/ch/ch.cpp 5 | @@ -14,6 +14,7 @@ 6 | 7 | #ifdef __linux__ 8 | #include 9 | +#include 10 | #elif defined(__APPLE__) 11 | #include 12 | #endif 13 | @@ -1112,6 +1113,56 @@ unsigned int WINAPI StaticThreadProc(void *lpParam) 14 | return ExecuteTestWithMemoryCheck(argInfo->filename); 15 | } 16 | 17 | +bool insertLoadScriptFile(std::vector &filenames, LPSTR mainjs) 18 | +{ 19 | + FILE * file = NULL; 20 | + size_t lengthBytes = 0; 21 | + size_t len = filenames.size(); 22 | + BYTE * buffer = nullptr; 23 | + bool ret = true; 24 | + 25 | + if (len > 0) { 26 | + if (fopen_s(&file, mainjs, "rb") != 0) { 27 | + fprintf(stderr, "Error in opening file '%s' ", mainjs); 28 | + exit(1); 29 | + } else { 30 | + fseek(file, 0, SEEK_END); 31 | + lengthBytes = ftell(file); 32 | + fseek(file, 0, SEEK_SET); 33 | + buffer = (LPBYTE)malloc(lengthBytes); 34 | + size_t readBytes = fread(buffer, sizeof(BYTE), lengthBytes, file); 35 | + if (readBytes != lengthBytes) { 36 | + fprintf(stderr, "Error in reading file '%s' ", mainjs); 37 | + ret = false; 38 | + fclose(file); 39 | + goto free_buffer; 40 | + } 41 | + fclose(file); 42 | + if (fopen_s(&file, mainjs, "wb") != 0) { 43 | + fprintf(stderr, "Error in writing file '%s' ", mainjs); 44 | + ret = false; 45 | + goto free_buffer; 46 | + } 47 | + for (size_t i = 0; i < len; i++) 48 | + fprintf(file, "WScript.LoadScriptFile(\"%s\");\n", filenames[i]); 49 | + size_t writeBytes = fwrite(buffer, sizeof(BYTE), lengthBytes, file); 50 | + if (writeBytes != lengthBytes) { 51 | + fprintf(stderr, "Error in writing file '%s' ", mainjs); 52 | + ret = false; 53 | + fclose(file); 54 | + goto free_buffer; 55 | + } 56 | + fclose(file); 57 | + } 58 | + } 59 | + 60 | +free_buffer: 61 | + if (buffer != nullptr) 62 | + free(buffer); 63 | + 64 | + return ret; 65 | +} 66 | + 67 | #ifndef _WIN32 68 | static char16** argv = nullptr; 69 | int main(int argc, char** c_argv) 70 | @@ -1122,6 +1173,7 @@ int main(int argc, char** c_argv) 71 | #endif 72 | int origargc = argc; // store for clean-up later 73 | argv = new char16*[argc]; 74 | + std::vector filenames; 75 | for (int i = 0; i < argc; i++) 76 | { 77 | NarrowStringToWideDynamic(c_argv[i], &argv[i]); 78 | @@ -1244,6 +1296,13 @@ int _cdecl wmain(int argc, __in_ecount(argc) LPWSTR argv[]) 79 | LPCWSTR startEventStr = argv[i] + wcslen(_u("-TTDStartEvent=")); 80 | startEventCount = (UINT32)_wtoi(startEventStr); 81 | } 82 | + else if(wcsstr(argv[i], _u("-lib=")) == argv[i]) 83 | + { 84 | + LPCWSTR file_str = argv[i] + wcslen(_u("-lib=")); 85 | + char *filename; 86 | + WideStringToNarrowDynamic(file_str, &filename); 87 | + filenames.push_back(filename); 88 | + } 89 | else 90 | { 91 | wchar *temp = argv[cpos]; 92 | @@ -1271,7 +1330,7 @@ int _cdecl wmain(int argc, __in_ecount(argc) LPWSTR argv[]) 93 | #endif // _WIN32 94 | 95 | HostConfigFlags::HandleArgsFlag(argc, argv); 96 | - 97 | + 98 | argInfo = { argc, argv, PrintUsage, nullptr }; 99 | success = ChakraRTInterface::LoadChakraDll(&argInfo, &chakraLibrary); 100 | 101 | @@ -1285,6 +1344,13 @@ int _cdecl wmain(int argc, __in_ecount(argc) LPWSTR argv[]) 102 | WideStringToNarrowDynamic(argv[1], &argInfo.filename); 103 | } 104 | 105 | + if (!insertLoadScriptFile(filenames, argInfo.filename)) { 106 | + PrintUsage(); 107 | + PAL_Shutdown(); 108 | + retval = EXIT_FAILURE; 109 | + goto return_cleanup; 110 | + } 111 | + 112 | if (success) 113 | { 114 | if (HostConfigFlags::flags.CustomConfigFile != NULL) 115 | -------------------------------------------------------------------------------- /engines/utils/new-chakra.patch: -------------------------------------------------------------------------------- 1 | diff --git bin/ch/ch.cpp bin/ch/ch.cpp 2 | index f2d8025..2abb55e 100644 3 | --- bin/ch/ch.cpp 4 | +++ bin/ch/ch.cpp 5 | @@ -14,6 +14,7 @@ 6 | 7 | #ifdef __linux__ 8 | #include 9 | +#include 10 | #elif defined(__APPLE__) 11 | #include 12 | #endif 13 | @@ -1112,6 +1113,67 @@ unsigned int WINAPI StaticThreadProc(void *lpParam) 14 | return ExecuteTestWithMemoryCheck(argInfo->filename); 15 | } 16 | 17 | +bool insertLoadScriptFile(std::vector &filenames, LPSTR mainjs) 18 | +{ 19 | + FILE * file = NULL; 20 | + size_t lengthBytes = 0; 21 | + size_t len = filenames.size(); 22 | + BYTE * buffer = nullptr; 23 | + bool ret = true; 24 | + char stmt[256]; 25 | + char actualpath[256]; 26 | + 27 | + memset(stmt, 0, sizeof(stmt)); 28 | + memset(actualpath, 0, sizeof(actualpath)); 29 | + 30 | + if (len > 0) { 31 | + if (fopen_s(&file, mainjs, "rb") != 0) { 32 | + fprintf(stderr, "Error in opening file '%s' ", mainjs); 33 | + exit(1); 34 | + } else { 35 | + fseek(file, 0, SEEK_END); 36 | + lengthBytes = ftell(file); 37 | + fseek(file, 0, SEEK_SET); 38 | + buffer = (LPBYTE)malloc(lengthBytes); 39 | + size_t readBytes = fread(buffer, sizeof(BYTE), lengthBytes, file); 40 | + if (readBytes != lengthBytes) { 41 | + fprintf(stderr, "Error in reading file '%s' ", mainjs); 42 | + ret = false; 43 | + fclose(file); 44 | + goto free_buffer; 45 | + } 46 | + fclose(file); 47 | + if (fopen_s(&file, mainjs, "wb") != 0) { 48 | + fprintf(stderr, "Error in writing file '%s' ", mainjs); 49 | + ret = false; 50 | + goto free_buffer; 51 | + } 52 | + for (size_t i = 0; i < len; i++) { 53 | + // fprintf(file, "WScript.LoadScriptFile(\"%s\");\n", filenames[i]); 54 | + realpath(filenames[i], actualpath); 55 | + snprintf(stmt, sizeof(stmt), "WScript.LoadScriptFile(\"%s\");\n", actualpath); 56 | + if (!memmem(buffer, lengthBytes, stmt, strlen(stmt))) { 57 | + fprintf(file, stmt); 58 | + } 59 | + } 60 | + size_t writeBytes = fwrite(buffer, sizeof(BYTE), lengthBytes, file); 61 | + if (writeBytes != lengthBytes) { 62 | + fprintf(stderr, "Error in writing file '%s' ", mainjs); 63 | + ret = false; 64 | + fclose(file); 65 | + goto free_buffer; 66 | + } 67 | + fclose(file); 68 | + } 69 | + } 70 | + 71 | +free_buffer: 72 | + if (buffer != nullptr) 73 | + free(buffer); 74 | + 75 | + return ret; 76 | +} 77 | + 78 | #ifndef _WIN32 79 | static char16** argv = nullptr; 80 | int main(int argc, char** c_argv) 81 | @@ -1122,6 +1184,7 @@ int main(int argc, char** c_argv) 82 | #endif 83 | int origargc = argc; // store for clean-up later 84 | argv = new char16*[argc]; 85 | + std::vector filenames; 86 | for (int i = 0; i < argc; i++) 87 | { 88 | NarrowStringToWideDynamic(c_argv[i], &argv[i]); 89 | @@ -1244,6 +1307,13 @@ int _cdecl wmain(int argc, __in_ecount(argc) LPWSTR argv[]) 90 | LPCWSTR startEventStr = argv[i] + wcslen(_u("-TTDStartEvent=")); 91 | startEventCount = (UINT32)_wtoi(startEventStr); 92 | } 93 | + else if(wcsstr(argv[i], _u("-lib=")) == argv[i]) 94 | + { 95 | + LPCWSTR file_str = argv[i] + wcslen(_u("-lib=")); 96 | + char *filename; 97 | + WideStringToNarrowDynamic(file_str, &filename); 98 | + filenames.push_back(filename); 99 | + } 100 | else 101 | { 102 | wchar *temp = argv[cpos]; 103 | @@ -1271,7 +1341,7 @@ int _cdecl wmain(int argc, __in_ecount(argc) LPWSTR argv[]) 104 | #endif // _WIN32 105 | 106 | HostConfigFlags::HandleArgsFlag(argc, argv); 107 | - 108 | + 109 | argInfo = { argc, argv, PrintUsage, nullptr }; 110 | success = ChakraRTInterface::LoadChakraDll(&argInfo, &chakraLibrary); 111 | 112 | @@ -1285,6 +1355,13 @@ int _cdecl wmain(int argc, __in_ecount(argc) LPWSTR argv[]) 113 | WideStringToNarrowDynamic(argv[1], &argInfo.filename); 114 | } 115 | 116 | + if (!insertLoadScriptFile(filenames, argInfo.filename)) { 117 | + PrintUsage(); 118 | + PAL_Shutdown(); 119 | + retval = EXIT_FAILURE; 120 | + goto return_cleanup; 121 | + } 122 | + 123 | if (success) 124 | { 125 | if (HostConfigFlags::flags.CustomConfigFile != NULL) 126 | -------------------------------------------------------------------------------- /fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | output*/ 2 | result/ 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /fuzz/TS/.gitignore: -------------------------------------------------------------------------------- 1 | test*/ 2 | samples/ 3 | node_modules/ 4 | *.swo 5 | test*.js 6 | out* 7 | .flowconfig 8 | err 9 | grammar/ 10 | !grammar/Types.g4 11 | !grammar/Simple.g4 12 | /__pycache__/ 13 | *.pyc 14 | 15 | *.js 16 | *.js.map 17 | package-lock.json 18 | -------------------------------------------------------------------------------- /fuzz/TS/base/const/number.ts: -------------------------------------------------------------------------------- 1 | import * as UTILS from "../utils"; 2 | const Random = UTILS.Random; 3 | 4 | export function index() { 5 | var specials = Random.weighted([ 6 | { w: 3, v: "0" }, 7 | { w: 1, v: "1" }, 8 | { w: 1, v: "100" } 9 | ]) 10 | return Random.pick(specials); 11 | } 12 | 13 | // Get from JsFunfuzz 14 | export function gen(b : any[] = []) { 15 | var specials = Random.weighted([ 16 | // Numbers and number-like things 17 | { w: 1, v: "0" }, 18 | { w: 1, v: "1" }, 19 | { w: 1, v: "2" }, 20 | { w: 1, v: "3" }, 21 | { w: 1, v: "0.1" }, 22 | { w: 1, v: ".2" }, 23 | { w: 1, v: "1.3" }, 24 | { w: 1, v: "4." }, 25 | { w: 1, v: "5.0000000000000000000000" }, 26 | { w: 1, v: "1.2e3" }, 27 | { w: 1, v: "1e81" }, 28 | { w: 1, v: "1e+81" }, 29 | { w: 1, v: "1e-81" }, 30 | { w: 1, v: "1e4" }, 31 | { w: 1, v: "-0" }, 32 | { w: 1, v: "(-0)" }, 33 | { w: 1, v: "-1" }, 34 | { w: 1, v: "(-1)" }, 35 | { w: 1, v: "0x99" }, 36 | { w: 1, v: "033" }, 37 | { w: 1, v: "3/0" }, 38 | { w: 1, v: "-3/0" }, 39 | { w: 1, v: "0/0" }, 40 | { w: 1, v: "Math.PI" }, 41 | { w: 1, v: "0x2D413CCC"}, 42 | { w: 1, v: "0x5a827999"}, 43 | { w: 1, v: "0xB504F332"}, 44 | { w: 1, v: "-0x2D413CCC"}, 45 | { w: 1, v: "-0x5a827999"}, 46 | { w: 1, v: "-0xB504F332"}, 47 | { w: 1, v: "0x50505050"}, 48 | { w: 1, v: "(0x50505050 >> 1)"}, 49 | 50 | // various powers of two, with values near JSVAL_INT_MAX especially tested 51 | { w: 1, v: "0x10000000"}, 52 | { w: 1, v: "0x20000000"}, 53 | { w: 1, v: "0x3FFFFFFE"}, 54 | { w: 1, v: "0x3FFFFFFF"}, 55 | { w: 1, v: "0x40000000"}, 56 | { w: 1, v: "0x40000001"}, 57 | 58 | 59 | // Boundaries 60 | // Boundaries of int, signed, unsigned (near +/- 2^31, +/- 2^32) 61 | { w: 1, v: "0x07fffffff"}, 62 | { w: 1, v: "0x080000000"}, 63 | { w: 1, v: "0x080000001"}, 64 | 65 | { w: 1, v: "-0x07fffffff"}, 66 | { w: 1, v: "-0x080000000"}, 67 | { w: 1, v: "-0x080000001"}, 68 | 69 | { w: 1, v: "0x0ffffffff"}, 70 | { w: 1, v: "0x100000000"}, 71 | { w: 1, v: "0x100000001"}, 72 | 73 | { w: 1, v: "-0x0ffffffff"}, 74 | { w: 1, v: "-0x100000000"}, 75 | { w: 1, v: "-0x100000001"}, 76 | 77 | 78 | // Boundaries of double 79 | { w: 1, v: "Number.MIN_VALUE"}, 80 | { w: 1, v: "-Number.MIN_VALUE"}, 81 | 82 | { w: 1, v: "Number.MAX_VALUE"}, 83 | { w: 1, v: "-Number.MAX_VALUE"}, 84 | 85 | 86 | // Boundaries of maximum safe integer 87 | { w: 1, v: "Number.MIN_SAFE_INTEGER"}, 88 | { w: 1, v: "-Number.MIN_SAFE_INTEGER"}, 89 | 90 | { w: 1, v: "-(2**53-2)"}, 91 | { w: 1, v: "-(2**53)"}, 92 | { w: 1, v: "-(2**53+2)"}, 93 | 94 | { w: 1, v: "Number.MAX_SAFE_INTEGER"}, 95 | { w: 1, v: "-Number.MAX_SAFE_INTEGER"}, 96 | 97 | { w: 1, v: "(2**53)-2"}, 98 | { w: 1, v: "(2**53)"}, 99 | { w: 1, v: "(2**53)+2"}, 100 | 101 | 102 | // See bug 1350097 - 1.79...e308 is the largest (by module) finite number 103 | { w: 1, v: "0.000000000000001"}, 104 | { w: 1, v: "1.7976931348623157e308"}, 105 | 106 | 107 | // Special numbers 108 | { w: 1, v: "(1/0)"}, 109 | { w: 1, v: "(-1/0)"}, 110 | { w: 1, v: "(0/0)"}, 111 | 112 | 113 | // String literals 114 | { w: 1, v: " \"\" "}, 115 | { w: 1, v: " '' "}, 116 | { w: 1, v: " 'A' "}, 117 | { w: 1, v: " '\\0' "}, 118 | { w: 1, v: " 'use strict' "}, 119 | 120 | 121 | // Regular expression literals 122 | { w: 1, v: " /x/ "}, 123 | { w: 1, v: " /x/g "}, 124 | 125 | 126 | // Booleans 127 | { w: 1, v: "true"}, 128 | { w: 1, v: "false"}, 129 | 130 | 131 | // Undefined and null 132 | { w: 1, v: "(void 0)"}, 133 | { w: 1, v: "null"}, 134 | 135 | 136 | // Object literals 137 | { w: 1, v: "[]"}, 138 | { w: 1, v: "[1]"}, 139 | { w: 1, v: "[(void 0)]"}, 140 | { w: 1, v: "{}"}, 141 | { w: 1, v: "{x:3}"}, 142 | { w: 1, v: "({})"}, 143 | { w: 1, v: "({x:3})"}, 144 | 145 | 146 | // Variables that really should have been constants in the ecmascript spec 147 | { w: 1, v: "NaN"}, 148 | { w: 1, v: "Infinity"}, 149 | { w: 1, v: "-Infinity"}, 150 | { w: 1, v: "undefined"}, 151 | 152 | 153 | // Boxed booleans 154 | { w: 1, v: "new Boolean(true)"}, 155 | { w: 1, v: "new Boolean(false)"}, 156 | 157 | 158 | // Boxed numbers 159 | { w: 1, v: "new Number(1)"}, 160 | { w: 1, v: "new Number(1.5)"}, 161 | 162 | 163 | // Boxed strings 164 | { w: 1, v: "new String('')"}, 165 | { w: 1, v: "new String('q')"}, 166 | 167 | 168 | // Fun stuff 169 | { w: 1, v: "function(){}"}, 170 | 171 | { w: 1, v: "{}"}, 172 | { w: 1, v: "[]"}, 173 | { w: 1, v: "[1]"}, 174 | { w: 1, v: "['z']"}, 175 | { w: 1, v: "[undefined]"}, 176 | { w: 1, v: "this"}, 177 | { w: 1, v: "eval"}, 178 | { w: 0, v: "arguments"}, 179 | { w: 0, v: "arguments.caller"}, 180 | { w: 0, v: "arguments.callee"}, 181 | 182 | // Actual variables (slightly dangerous) 183 | { w: 1, v: b.length ? Random.pick(b) : "v0"}, 184 | ]); 185 | return Number(Random.pick(specials)); 186 | } 187 | 188 | -------------------------------------------------------------------------------- /fuzz/TS/base/const/string.ts: -------------------------------------------------------------------------------- 1 | import * as UTILS from "../utils"; 2 | const Random = UTILS.Random; 3 | 4 | export function gen() : string { 5 | var specials = Random.weighted([ 6 | { w : 2, v : [ 7 | "v0", 8 | "v1", 9 | "v2", 10 | "1024", 11 | "\u3056", 12 | "+0", 13 | "-0", 14 | "eval", 15 | "1.23", 16 | "{}", 17 | "", 18 | ]}, 19 | // from jsfunfuzz 20 | {w : 3, v : [ 21 | "__proto__", 22 | "constructor", 23 | "prototype", 24 | "wrappedJSObject", 25 | "arguments", 26 | "caller", 27 | "callee", 28 | "toString", 29 | "valueOf", 30 | "call", 31 | "apply", // ({apply:...}).apply() hits a special case (speculation failure with funapply / funcall bytecode) 32 | "length", 33 | "0", 34 | "1" 35 | ]}, 36 | {w : 3, v : [ 37 | "configurable", 38 | "enumberable", 39 | "value", 40 | "writable", 41 | "get", 42 | "set", 43 | "valueOf" 44 | ]}, 45 | ]); 46 | return Random.pick(Random.pick(specials)); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /fuzz/TS/base/engine/ast.ts: -------------------------------------------------------------------------------- 1 | import * as bt from "@babel/types"; 2 | import { TSNode } from "../esparse"; 3 | import { st, NumberType, BooleanType, RegExpType, StringType, NullType, Types } from "../estypes"; 4 | 5 | // ************************************************************************************** 6 | // 7 | // TSNode Builders 8 | // 9 | // ************************************************************************************** 10 | export class TSNodeBuilder { 11 | 12 | constructor() {} 13 | 14 | public buildNumericLiteral(value: number): TSNode { 15 | let node: TSNode = bt.numericLiteral(value); 16 | node.itype = new NumberType(); 17 | return node; 18 | } 19 | 20 | public buildBooleanLiteral(value: boolean): TSNode { 21 | let node: TSNode = bt.booleanLiteral(value); 22 | node.itype = new BooleanType(); 23 | return node; 24 | } 25 | 26 | public buildRegExpLiteral(pattern: string, flag: string = ""): TSNode { 27 | let node: TSNode = bt.regExpLiteral(pattern, flag); 28 | node.itype = new RegExpType(); 29 | return node; 30 | } 31 | 32 | public buildStringLiteral(value: string) { 33 | let node: TSNode = bt.stringLiteral(value); 34 | node.itype = new StringType(); 35 | return node; 36 | } 37 | 38 | public buildNullLiteral() { 39 | let node: TSNode = bt.nullLiteral(); 40 | node.itype = new NullType(); 41 | return node; 42 | } 43 | 44 | public buildBinaryExpression(operator: bt.BinaryExpression['operator'], left: TSNode, right: TSNode, type: Types) { 45 | let node: TSNode = bt.binaryExpression(operator, left, right); 46 | node.itype = type; 47 | return node; 48 | } 49 | 50 | public buildLogicalExpression(operator: bt.LogicalExpression['operator'], left: TSNode, right: TSNode, type: Types) { 51 | let node: TSNode = bt.logicalExpression(operator, left, right); 52 | node.itype = type; 53 | return node; 54 | } 55 | 56 | public buildUnaryExpression(operator: bt.UnaryExpression['operator'], argument: TSNode, prefix: boolean, type: Types) { 57 | let node: TSNode = bt.unaryExpression(operator, argument, prefix); 58 | node.itype = type; 59 | return node; 60 | } 61 | 62 | public buildUpdateExpression(operator: bt.UpdateExpression['operator'], argument: TSNode, prefix: boolean, type: Types) { 63 | let node: TSNode = bt.updateExpression(operator, argument, prefix); 64 | node.itype = type; 65 | return node; 66 | } 67 | 68 | public buildNewExpression(callee: TSNode, _arguments: Array, type: Types) { 69 | let node: TSNode = bt.newExpression(callee, >_arguments); 70 | node.itype = type; 71 | return node; 72 | } 73 | 74 | public buildIdentifier(name: string, type: Types) { 75 | let node: TSNode = bt.identifier(name); 76 | node.itype = type; 77 | return node; 78 | } 79 | 80 | public buildNumberLiteralSequence(values: Array): Array { 81 | let ret: TSNode[] = new Array(values.length); 82 | for (let i = 0; i < values.length; i++) { 83 | ret[i] = this.buildNumericLiteral(values[i]); 84 | } 85 | return ret; 86 | } 87 | 88 | public buildMemberExpression(object: TSNode, property: TSNode, computed: boolean, type: Types) { 89 | let node: TSNode = bt.memberExpression(object, property, computed); 90 | node.itype = type; 91 | return node; 92 | } 93 | 94 | public buildCallExpression(callee: TSNode, _arguments: Array, type: Types): TSNode { 95 | let node: TSNode = bt.callExpression(callee, >_arguments); 96 | node.itype = type; 97 | return node; 98 | } 99 | 100 | public buildArrayExpression(elements: Array, type: Types): TSNode { 101 | let node: TSNode = bt.arrayExpression(>elements); 102 | node.itype = type; 103 | return node; 104 | } 105 | 106 | public buildObjectProperty(key: TSNode, value: TSNode, computed: boolean) { 107 | let node: TSNode = bt.objectProperty(key, value, computed); 108 | node.itype = st.immutableType; 109 | return node; 110 | } 111 | 112 | public buildObjectExpression(properties: Array, type: Types) { 113 | let node: TSNode = bt.objectExpression(>>properties); 114 | node.itype = type; 115 | return node; 116 | } 117 | 118 | public buildAssignExpression(op: string, left: TSNode, right: TSNode) { 119 | let node: TSNode = bt.assignmentExpression(op, left, right); 120 | node.itype = st.voidType; 121 | return node; 122 | } 123 | 124 | public buildFunctionExpression(id : TSNode, params : Array, body : TSNode, generator : boolean, async : boolean, type : Types) { 125 | let node : TSNode = bt.functionExpression( 126 | id, 127 | >>params, 128 | body, 129 | generator, 130 | async 131 | ); 132 | node.itype = type; 133 | return node; 134 | } 135 | 136 | public buildBlockStatement(body : Array) { 137 | let node: TSNode = bt.blockStatement(>body); 138 | node.itype = st.voidType; 139 | return node; 140 | } 141 | 142 | public buildReturnStatement(argument : TSNode) { 143 | let node: TSNode = bt.returnStatement(argument); 144 | node.itype = st.voidType; 145 | return node; 146 | } 147 | 148 | public buildExpressionStatement(exp : TSNode) { 149 | let node: TSNode = bt.expressionStatement(exp); 150 | node.itype = st.voidType; 151 | return node; 152 | } 153 | 154 | public buildVariableDeclarator(id: TSNode, init: TSNode) { 155 | let node: TSNode = bt.variableDeclarator(id, init); 156 | node.itype = st.voidType; 157 | return node; 158 | } 159 | 160 | public buildVariableDeclaration(kind: string, declarator: TSNode) { 161 | let node: TSNode = bt.variableDeclaration(kind, [declarator]); 162 | node.itype = st.voidType; 163 | return node; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /fuzz/TS/base/engine/function.ts: -------------------------------------------------------------------------------- 1 | export class FunctionBuilder { 2 | constructor() {} 3 | } -------------------------------------------------------------------------------- /fuzz/TS/base/engine/literal.ts: -------------------------------------------------------------------------------- 1 | import { Random, dbglog, assert, printf } from "../utils"; 2 | import { TSNode } from "../esparse"; 3 | import { Weight, LiteralWeight } from "../esweight"; 4 | import { Types, st, ConstructorType} from "../estypes"; 5 | import { NodeBuilder, astBuilder, builder } from "./esbuild"; 6 | import { Dsp, LiteralDsps, TypedArrayNames } from "../esspecs"; 7 | 8 | import * as NUMBER from "../const/number"; 9 | import * as STRING from "../const/string"; 10 | import * as REGEXP from "../const/regexp"; 11 | import * as bt from "@babel/types"; 12 | 13 | // ************************************************************************************** 14 | // 15 | // Literal Builder 16 | // 17 | // ************************************************************************************** 18 | export class LiteralBuilder implements NodeBuilder { 19 | name: string; 20 | dsps: { [s: string]: Dsp }; 21 | weights: Array>; 22 | 23 | constructor() { 24 | this.name = "Literal"; 25 | this.dsps = LiteralDsps; 26 | this.weights = LiteralWeight; 27 | } 28 | 29 | private buildBoolean() : TSNode { 30 | let value : boolean = Random.bool(); 31 | return astBuilder.buildBooleanLiteral(value); 32 | } 33 | 34 | private buildString() : TSNode { 35 | let s : string; 36 | let a : Array = builder.context.tc.getStringLiterals(); 37 | // 2/3 to use existing numbers 38 | if (!a.length || !Random.number(3)) { 39 | s = STRING.gen(); 40 | } else { 41 | s = Random.pick(a); 42 | } 43 | return astBuilder.buildStringLiteral(s); 44 | } 45 | 46 | private buildNumber() : TSNode { 47 | let value : number; 48 | let a : Array = builder.context.tc.getNumberLiterals(); 49 | // 2/3 to use existing numbers 50 | if (!a.length || !Random.number(3)) { 51 | value = NUMBER.gen(); 52 | } else { 53 | value = Random.pick(a); 54 | } 55 | // minus numeric literal is unaryExpression in fact. 56 | let ret : TSNode; 57 | if(value >= 0) 58 | ret = astBuilder.buildNumericLiteral(value); 59 | else 60 | ret = astBuilder.buildUnaryExpression("-", astBuilder.buildNumericLiteral(value * -1), true, st.numberType); 61 | return ret; 62 | } 63 | 64 | private buildNull() : TSNode { 65 | return astBuilder.buildNullLiteral(); 66 | } 67 | 68 | private buildRegExp() : TSNode { 69 | let re : RegExp = REGEXP.gen(); 70 | return astBuilder.buildRegExpLiteral(re.source, re.flags); 71 | } 72 | 73 | public buildBuiltinConstructor(type : Types) { 74 | let t : Types = type; 75 | if (st.isBuiltinConstructor(type)) { 76 | let name: string = (type).name; 77 | if (name == "TypedArray") 78 | return astBuilder.buildIdentifier(Random.pick(TypedArrayNames), type); 79 | else 80 | return astBuilder.buildIdentifier(name, type); 81 | } else { 82 | return null; 83 | } 84 | } 85 | 86 | private buildMath() { 87 | return astBuilder.buildIdentifier("Math", st.mathType); 88 | } 89 | 90 | public buildPrototype(name : string) : TSNode { 91 | if (name == "TypedArray") 92 | name = Random.pick(TypedArrayNames); 93 | let ctor : TSNode = astBuilder.buildIdentifier(name, st.constructorTypes[name]); 94 | //assert(ctor.itype != undefined, name) 95 | let property : TSNode = astBuilder.buildIdentifier("prototype", st.voidType); 96 | return astBuilder.buildMemberExpression(ctor, property, false, st.prototypeTypes[name]); 97 | } 98 | 99 | public build(step : number, suggestedOp : string, type : Types) : TSNode { 100 | return this["build" + suggestedOp](type); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /fuzz/TS/base/engine/type.ts: -------------------------------------------------------------------------------- 1 | import { NodePath } from "@babel/traverse"; 2 | 3 | import { TSNode } from "../esparse"; 4 | import { BuildingContext } from "./context"; 5 | import { Random, printf, assert } from "../utils"; 6 | import { Preference, defaultPreference } from "../espreference"; 7 | import { builder, funcExpBuilder, objExpBuilder, BuildInfo, typeBuilder } from "./esbuild"; 8 | import { ArgsType, Types, FunctionExpressionType, ObjectType, st, getCompatibleBaseTypes, isMatch } from "../estypes"; 9 | import { MutateChange, MUTATE_NODE } from "../esmutator"; 10 | import { TestCase } from "../estestcase"; 11 | 12 | export class TypeBuilder { 13 | 14 | constructor() {} 15 | 16 | private buildArgsType(step: number, type: ArgsType): TSNode[] { 17 | let args: TSNode[] = []; 18 | for (let argType of type.args) { 19 | if (argType.optional && Random.bool()) 20 | break; 21 | // if an argument can appear infinite times, 22 | // let's restrict it from 1 ~ 4. 23 | let n: number = argType.infinite ? Random.range(1, 5) : 1; 24 | for (let i = 0; i < n; i++) { 25 | let arg: TSNode = this.build(step, argType.atype); 26 | if (!arg) { 27 | return null; 28 | } 29 | args.push(arg); 30 | } 31 | } 32 | return args; 33 | } 34 | 35 | public build(step : number, type : Types, pref : Preference = defaultPreference) : TSNode | TSNode[] { 36 | 37 | // for ArgsType, we return TSNode[] 38 | if (type instanceof ArgsType) { 39 | return this.buildArgsType(step, type); 40 | } 41 | 42 | // for FunctionExpressionType, we directly build 43 | if (type instanceof FunctionExpressionType) { 44 | if (builder.isInFuncExp()) 45 | return null; 46 | else 47 | return funcExpBuilder.build(type); 48 | } 49 | 50 | // for ObjectType with a shape, we directly build 51 | if (type === st.propertyType || type === st.proxyhandlerType) { 52 | return objExpBuilder.buildShapedObject(type); 53 | } 54 | 55 | let ret: TSNode = null; 56 | 57 | let varInfo: BuildInfo[] = []; 58 | let litInfo: BuildInfo[] = []; 59 | let memInfo: BuildInfo[] = []; 60 | let expInfo: BuildInfo[] = []; 61 | let buiInfo: BuildInfo[] = []; 62 | let buicInfo: BuildInfo[] = []; 63 | let defInfo: BuildInfo[] = []; 64 | 65 | let context: BuildingContext = builder.context; 66 | let baseTypes: Array = type === st.anyType ? [...context.typeMap.keys()] : getCompatibleBaseTypes(type, pref.objectLike); 67 | 68 | for (let bt of baseTypes) { 69 | if (context.typeMap.has(bt)) { 70 | context.typeMap.get(bt).forEach((t: Types) => { 71 | if (isMatch(t, type, pref.objectLike)) { 72 | if (!pref.noVars && context.varMap.has(t)) { 73 | varInfo = varInfo.concat(context.varMap.get(t)); 74 | } 75 | if (!pref.noLits && context.literalMap.has(t)) { 76 | litInfo = litInfo.concat(context.literalMap.get(t)); 77 | } 78 | if (!pref.noMems && context.memExpMap.has(t)) { 79 | memInfo = memInfo.concat(context.memExpMap.get(t)); 80 | } 81 | if (!pref.noExps && context.expMap.has(t)) { 82 | expInfo = expInfo.concat(context.expMap.get(t)); 83 | } 84 | if (!pref.noBuis && context.builtinMap.has(t)) { 85 | buiInfo = buiInfo.concat(context.builtinMap.get(t)); 86 | } 87 | if (!pref.noBuis && context.builtinCtorMap.has(t)) { 88 | buicInfo = buicInfo.concat(context.builtinCtorMap.get(t)); 89 | } 90 | if (!pref.noDefs && context.defineMap.has(t)) { 91 | defInfo = defInfo.concat(context.defineMap.get(t)); 92 | } 93 | } 94 | }); 95 | } 96 | } 97 | 98 | let solutions = Random.weighted([ 99 | { w: varInfo.length ? 5 : 0, v: varInfo }, 100 | { w: litInfo.length ? 1 : 0, v: litInfo }, 101 | { w: (step && memInfo.length) ? 5 : 0, v: memInfo }, 102 | { w: (step && expInfo.length) ? 5 : 0, v: expInfo }, 103 | { w: (step && buiInfo.length) ? 5 : 0, v: buiInfo }, 104 | { w: (step && buicInfo.length) ? 1 : 0, v: buicInfo }, 105 | { w: (step && defInfo.length) ? 1 : 0, v: defInfo }, 106 | ]); 107 | if (!solutions.length) 108 | return null; 109 | 110 | let bis: BuildInfo[] = Random.pick(solutions); 111 | assert(!!bis.length); 112 | let x = Random.pick(Random.weighted(bis)); 113 | ret = x.b.build(step, x.o, type); 114 | return ret; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /fuzz/TS/base/engine/var.ts: -------------------------------------------------------------------------------- 1 | import { inspect } from "util"; 2 | import * as t from "@babel/types"; 3 | 4 | import { TSNode } from "../esparse"; 5 | import { NodeBuilder, builder, astBuilder } from "./esbuild"; 6 | import { Dsp, VariableDsps } from "../esspecs"; 7 | import { Weight, VariableWeight } from "../esweight"; 8 | import { Types, isMatch } from "../estypes"; 9 | import { Random, assert } from "../utils"; 10 | 11 | // ************************************************************************************** 12 | // 13 | // Variable Builder 14 | // 15 | // ************************************************************************************** 16 | export class VariableBuilder implements NodeBuilder { 17 | name: string; 18 | dsps: { [s: string]: Dsp }; 19 | weights: Array>; 20 | 21 | constructor() { 22 | this.name = "Variable"; 23 | this.dsps = VariableDsps; 24 | this.weights = VariableWeight; 25 | } 26 | 27 | public build(step: number, suggestedOp: string, type: Types): TSNode { 28 | let vars: Array = []; 29 | for (let node of builder.context.variables) { 30 | if (isMatch(node.itype, type, false)) { 31 | vars.push(node); 32 | } 33 | } 34 | let v: TSNode = Random.pick(vars); 35 | if (!v) 36 | return null; 37 | 38 | return astBuilder.buildIdentifier((v).name, v.itype); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /fuzz/TS/base/esgenerator.ts: -------------------------------------------------------------------------------- 1 | import * as bt from "@babel/types" 2 | import traverse, { Node, NodePath } from "@babel/traverse"; 3 | 4 | import { TSNode } from "./esparse"; 5 | import { builder, stmtBuilder } from "./engine/esbuild"; 6 | import { printf } from "./utils"; 7 | import { TestCase } from "./estestcase"; 8 | 9 | export function generate(tc : TestCase, path : NodePath, n : number) : Array { 10 | let stmts: Array = new Array(); 11 | let i: number = 0; 12 | 13 | builder.initBuildingContext(tc, path, 1); 14 | while (i < n) { 15 | let stmt : TSNode = stmtBuilder.build(); 16 | if (stmt) { 17 | stmts.push(stmt); 18 | } 19 | i++; 20 | } 21 | 22 | return >stmts; 23 | } -------------------------------------------------------------------------------- /fuzz/TS/base/esmutator.ts: -------------------------------------------------------------------------------- 1 | import * as FS from "fs"; 2 | import { inspect } from "util"; 3 | 4 | import * as bt from "@babel/types" 5 | import { parse } from "@babel/parser"; 6 | import traverse, { Node, NodePath, Binding } from "@babel/traverse" 7 | import generate from "@babel/generator" 8 | 9 | import { TSNode } from "./esparse"; 10 | import { TestCase } from "./estestcase"; 11 | import { dbglog, assert, printf, Random } from "./utils"; 12 | import { builder, buildStatementForMutation, buildNodeForMutation } from "./engine/esbuild"; 13 | import { Types, st, isEqual, FunctionType } from "./estypes"; 14 | 15 | export type MutateChangeType = 0 | 1; 16 | export const MUTATE_NODE: MutateChangeType = 0; 17 | export const MUTATE_OPRND: MutateChangeType = 1; 18 | export type MutateChange = { 19 | "type": MutateChangeType, 20 | "path": NodePath, 21 | "old": any, 22 | "new": any 23 | }; 24 | 25 | export const TRYTIMES : number = 3; 26 | 27 | function isOpMutableExpression(node): boolean { 28 | return bt.isBinaryExpression(node) 29 | || bt.isLogicalExpression(node) 30 | || bt.isUnaryExpression(node) 31 | || bt.isUpdateExpression(node); 32 | } 33 | 34 | export function revertOp(node: TSNode, op: string): void { 35 | if (isOpMutableExpression(node)) { 36 | (node).operator = op; 37 | } else { 38 | assert(false, "Invalid expression to revert the operand."); 39 | } 40 | } 41 | 42 | export function mutateExpOp(tc: TestCase, path: NodePath): MutateChange { 43 | let node: TSNode = path.node; 44 | let change: MutateChange = null; 45 | 46 | if (!Random.number(3)) { 47 | if (bt.isBinaryExpression(node)) { 48 | change = builder.BinaryExpressionBuilder.mutateOp(path); 49 | } else if (bt.isLogicalExpression(node)) { 50 | change = builder.LogicalExpressionBuilder.mutateOp(path); 51 | } else if (bt.isUnaryExpression(node)) { 52 | change = builder.UnaryExpressionBuilder.mutateOp(path); 53 | } else if (bt.isUpdateExpression(node)) { 54 | change = builder.UpdateExpressionBuilder.mutateOp(path); 55 | } 56 | } 57 | 58 | return change; 59 | } 60 | 61 | export function mutate(tc: TestCase, path: NodePath): MutateChange { 62 | let node: TSNode = path.node; 63 | let type: Types = node.itype; 64 | 65 | if (type && type instanceof FunctionType || type === st.undefinedType) 66 | return null; 67 | 68 | builder.initBuildingContext(tc, path, 0); 69 | 70 | // mutate statement: replace with a new statement 71 | // do all statements have void type? 72 | if (bt.isStatement(node)) { 73 | if (bt.isExpressionStatement(node)) { 74 | return buildStatementForMutation(tc, path); 75 | } else { 76 | return null; 77 | } 78 | } 79 | 80 | // mutate expression 81 | // first, try to mutate op 82 | // if failed, we drop to the later way 83 | if (bt.isExpression(node) && isOpMutableExpression(node)) { 84 | let change: MutateChange = mutateExpOp(tc, path); 85 | if (change) 86 | return change; 87 | } 88 | 89 | if (type) { 90 | // replace-based mutation 91 | return buildNodeForMutation(tc, path); 92 | } 93 | 94 | return null; 95 | } 96 | 97 | -------------------------------------------------------------------------------- /fuzz/TS/base/espreference.ts: -------------------------------------------------------------------------------- 1 | export class Preference { 2 | 3 | // are array expressions or new expressions allowed? 4 | noDefs : boolean; 5 | // are variables allowed? 6 | noVars : boolean; 7 | // are literals allowed? 8 | noLits : boolean; 9 | // are member expressions allowed? 10 | noMems : boolean; 11 | // are expressions allowed? 12 | noExps : boolean; 13 | // are builtins allowed? 14 | noBuis : boolean; 15 | // are ObjectLike types enabled? 16 | objectLike : boolean; 17 | 18 | constructor(noDefs = true, noVars = false, noLits = false, noMems = false, noExps = false, noBuis = false, objectLike = true) { 19 | this.noDefs = noDefs; 20 | this.noVars = noVars; 21 | this.noLits = noLits; 22 | this.noMems = noMems; 23 | this.noExps = noExps; 24 | this.noBuis = noBuis; 25 | this.objectLike = objectLike; 26 | } 27 | }; 28 | export const defaultPreference = new Preference(); 29 | export const lValPreference = new Preference(true, false, true, false, true, true, true); 30 | export const objMemPreference = new Preference(true, false, true, false, true, true, false); 31 | export const complexPreference = new Preference(true, true, true, false, false, false, true); 32 | export const initPreference = new Preference(false, false, false, false, false, false, true); -------------------------------------------------------------------------------- /fuzz/TS/base/esverifier.ts: -------------------------------------------------------------------------------- 1 | import { Program } from "@babel/types"; 2 | import traverse from "@babel/traverse"; 3 | 4 | import { TSNode } from "./esparse"; 5 | import { isEqual } from "./estypes"; 6 | import { assert } from "./utils"; 7 | import { inspect } from "util"; 8 | 9 | export function Verifier(ast : TSNode) { 10 | traverse(ast, { 11 | AssignmentExpression(path) { 12 | let left : TSNode = path.node.left; 13 | let right : TSNode = path.node.right; 14 | assert(isEqual(left.itype, right.itype), inspect(left, false, 1, true) + "\n" + inspect(right, false, 1, true)) 15 | } 16 | }) 17 | } -------------------------------------------------------------------------------- /fuzz/TS/base/utils.ts: -------------------------------------------------------------------------------- 1 | import { inspect } from "util"; 2 | import Colors = require("colors"); 3 | import * as printAST from "ast-pretty-print"; 4 | import { isMemberExpression } from '@babel/types'; 5 | import traverse, { Node, NodePath } from "@babel/traverse"; 6 | import { Random as i_Random, MersenneTwister19937} from "random-js"; 7 | 8 | import { TSNode } from './esparse'; 9 | 10 | export var DEBUG : boolean = false; 11 | 12 | export function EComment(msg : string, codes : string) : string { 13 | return cat("/*", msg, "*/", codes); 14 | } 15 | class _Random { 16 | random: i_Random = null; 17 | init(seed : number) : void { 18 | this.random = new i_Random(MersenneTwister19937.seed(seed)); 19 | } 20 | 21 | number(limit : number) : number { 22 | if (limit == 0) { 23 | return limit; 24 | } 25 | return (this.random.int32() >>> 0) % limit; 26 | } 27 | 28 | pick(list : T[]) : T { 29 | if (!list.length) 30 | return null; 31 | return list[this.number(list.length)]; 32 | } 33 | 34 | range(low : number, high : number) : number { 35 | return this.random.integer(low, high); 36 | } 37 | 38 | bool() : boolean { 39 | return this.random.bool(); 40 | } 41 | 42 | weighted(weighted_array : any[]) : any[] { 43 | var extended : any[] = []; 44 | for (var i = 0; i < weighted_array.length; ++i) { 45 | for (var j = 0; j < weighted_array[i].w; ++j) { 46 | extended.push(weighted_array[i].v); 47 | } 48 | } 49 | return extended; 50 | } 51 | 52 | weightedMap(map : Map) : any[] { 53 | var a : any[] = []; 54 | map.forEach((value : any, key : any) => { 55 | for (var i = 0; i < value; i++) { 56 | a.push(key); 57 | } 58 | }); 59 | return a; 60 | } 61 | 62 | prefix(len: number): string { 63 | var ret: string = ""; 64 | var chars: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 65 | 66 | for (var i = 0; i < len; i++) 67 | ret += chars.charAt(this.number(chars.length)); 68 | 69 | return ret; 70 | } 71 | }; 72 | 73 | export function dbginspect(msg: any): string { 74 | if (DEBUG) { 75 | return inspect(msg, false, 1); 76 | } 77 | } 78 | 79 | export function dbgAST(ast, pretty = true) { 80 | if (DEBUG) { 81 | if (pretty) 82 | printf(printAST(ast, true)) 83 | else { 84 | let prefix = ""; 85 | let stack = []; 86 | traverse(ast, { 87 | enter: path => { 88 | let node: TSNode = path.node; 89 | dbglog(prefix + ("type : " + node.type).cyan); 90 | dbglog(prefix + JSON.stringify(node.loc)); 91 | //dbglog(prefix + "features : " + dbginspect(node.feature)); 92 | if (node.itype) { 93 | if (isMemberExpression(node)) { 94 | dbglog(prefix + ("itype : " + dbginspect(node.itype)).yellow); 95 | } 96 | else { 97 | dbglog(prefix + ("itype : " + dbginspect(node.itype)).blue); 98 | } 99 | } 100 | else { 101 | dbglog(prefix + ("itype : " + dbginspect(node.itype)).red); 102 | } 103 | stack.push(prefix); 104 | prefix += " "; 105 | }, 106 | exit: path => { 107 | prefix = stack.pop(); 108 | } 109 | }) 110 | } 111 | } 112 | } 113 | export const Random = new _Random(); 114 | export function arraysEqual(a : T[], b : T[]) : boolean { 115 | if (a === b) return true; 116 | if (a.length != b.length) return false; 117 | 118 | for (var i = 0; i < a.length; ++i) { 119 | if (a[i] !== b[i]) return false; 120 | } 121 | return true; 122 | } 123 | 124 | export function printf(msg : any) : void { 125 | console.log(msg); 126 | } 127 | 128 | export function dbglog(msg : any, pretty=false) : void { 129 | if(DEBUG) { 130 | if(pretty) 131 | dbglog(dbginspect(msg).red); 132 | else 133 | console.log(msg); 134 | 135 | } 136 | } 137 | 138 | export function assert(cond : boolean, msg : string = "") : void { 139 | if (!cond) { 140 | msg = msg || "Assertion failed!"; 141 | if (typeof Error != "undefined") { 142 | throw new Error("[-] " + msg); 143 | } 144 | throw msg; 145 | } 146 | } 147 | export function dbgassert(cond : boolean, msg : string = "") : void { 148 | if (!cond && DEBUG) { 149 | msg = msg || "Assertion failed!"; 150 | if (typeof Error != "undefined") { 151 | throw new Error("[-] " + msg); 152 | } 153 | throw msg; 154 | } 155 | } 156 | 157 | export function cat(...strs : string[]) : string { 158 | return Array.prototype.join.call(strs, ""); 159 | } 160 | 161 | export function strict(str : string) : boolean { 162 | if (str.includes("use strict") || str.includes("use asm")) { 163 | return true; 164 | } 165 | return false 166 | } 167 | 168 | 169 | export class Pair { 170 | first : T; 171 | second : U; 172 | constructor(first : T, second : U) { 173 | this.first = first; 174 | this.second = second; 175 | } 176 | } 177 | 178 | export type Lit = string | number | boolean | undefined | null | void | {}; 179 | export const tuple = (...args: T) => args; 180 | 181 | export function shuffleArray(array) { 182 | for (let i = array.length - 1; i > 0; i--) { 183 | const j = Random.number(i + 1); 184 | [array[i], array[j]] = [array[j], array[i]]; 185 | } 186 | } 187 | 188 | export function randomArray(length) : number[] { 189 | let array : number[] = new Array(length); 190 | for (let i = 0; i < length; i++) { 191 | array[i] = i; 192 | } 193 | shuffleArray(array); 194 | return array; 195 | } 196 | 197 | export function randomKeyString() : string { 198 | return Random.bool() ? "dun" + Random.number(8) : "" + Random.number(8); 199 | } 200 | 201 | export function equalArray(a : [], b : []) { 202 | if (a === b) return true; 203 | if (a == null || b == null) return false; 204 | if (a.length != b.length) return false; 205 | 206 | for (let i = 0; i < a.length; ++i) { 207 | if (!b.includes(a[i])) return false; 208 | } 209 | return true; 210 | } 211 | 212 | export function isNumeric(x) { 213 | return !isNaN(x); 214 | } 215 | 216 | export function inRange(x : number, range : number[]) : boolean { 217 | return (x >= range[0]) && (x < range[1]); 218 | } 219 | 220 | export function makeLocTuple(node: Node): string { 221 | let start = node.start; 222 | let end = node.end; 223 | if (!node.loc) { 224 | printf(node); 225 | } 226 | let line = node.loc.start.line; 227 | return "<" + start + "," + end + "," + line+ ">"; 228 | } 229 | -------------------------------------------------------------------------------- /fuzz/TS/config.ts: -------------------------------------------------------------------------------- 1 | // Probability for modify non-Literal 2 | export const INSERTION_RATIO_IN_HAVOC: number = 0.4; 3 | export const DELETION_RATIO_IN_HAVOC: number = INSERTION_RATIO_IN_HAVOC / 4; 4 | 5 | export const MAX_MUTATIONS: number = 8; 6 | export const MAX_INSERTIONS: number = 4; 7 | export const MAX_DELETIONS: number = 2; 8 | 9 | // Multiplier to the number of testcases generated for new code coverage 10 | // TODO: Implement dynamic scaling like AFL 11 | export const MULTIPLIER_FOR_NEW_COVERAGE: number = 2; 12 | 13 | // Probbability to preserve type 14 | export const TYPE_PRESERVE_RATIO: number = 0.8; 15 | export const PRESERVE_IDENTIFIER_RATIO: number = 0.8; 16 | 17 | // Maximum number of snippets to sync from redis 18 | export const MIN_SNIPPETS = 64; 19 | export const MAX_SNIPPETS = 512; 20 | 21 | // # of mutations to make mutation chance into 1/2 22 | export const MUTATION_CYCLE = 16; 23 | 24 | export const MAX_FILE_SIZE_TO_INSERT = 2048; 25 | export const MAX_FILE_SIZE_TO_ANALYZE = 128 * 1024; 26 | 27 | export const MAX_SNIPPET_SIZE_TO_INSERT = 256; 28 | export const MAX_SNIPPET_SIZE_TO_MUTATE = 256; 29 | 30 | export const BITMAP_SIZE = 65536; 31 | export const PADDING_ID_SIZE = 0; // 32; // 16 byte 32 | 33 | export const INTERESTING_VALUES = [ 34 | // Subset of interesting values in AFL 35 | -2147483648, 36 | -32769, 37 | -128, 38 | -1, 39 | 0, 40 | 1, 41 | 16, 42 | 32, 43 | 64, 44 | 100, 45 | 127, 46 | 1024, 47 | 4096, 48 | 32767, 49 | 32768, 50 | 65535, 51 | 65536, 52 | 2147483647, 53 | // Floating point 54 | 1.1, 55 | ]; 56 | 57 | export const DEFAULT_HEADER = "var x=1;"; 58 | -------------------------------------------------------------------------------- /fuzz/TS/esfuzz.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import * as path from "path"; 3 | 4 | import traverse, { Node, NodePath } from "@babel/traverse"; 5 | import { Random, assert, printf, strict } from "./base/utils"; 6 | import { TSNode } from "./base/esparse"; 7 | import { Inferer } from "./base/esinfer"; 8 | import { TypedAST } from "./base/esparse"; 9 | import { builder } from "./base/engine/esbuild"; 10 | import { Code, TestCase } from "./base/estestcase"; 11 | 12 | const MUTATE: number = 0, INSERT: number = 1; 13 | 14 | function init(seed: number): number { 15 | let _seed: number = seed ? seed : Math.floor(Math.random() * Math.pow(2, 28)); 16 | Random.init(_seed); 17 | return _seed; 18 | } 19 | 20 | function main() { 21 | 22 | let fpath = process.argv[2]; // input file 23 | let dpath = process.argv[3]; // output dir 24 | let cnt = parseInt(process.argv[4]); // file num 25 | let seed = parseInt(process.argv[5]); // seed for repro seeducing 26 | seed = init(seed); 27 | 28 | if (!fpath.endsWith(".js")) { 29 | assert(false, "corpus should be javascript (.js) file") 30 | return -1; 31 | } 32 | 33 | let code : Code = new Code(fpath); 34 | let tast : TypedAST = code.parse(); 35 | 36 | let tc = new TestCase(code, tast); 37 | 38 | tc.config(4, 8, 2, 1); 39 | builder.config(2, 2); 40 | 41 | for (let i = 0; i < cnt; i++) { 42 | 43 | // for each test case, we reset the var cnt 44 | builder.setVarCnt(tast.maxVarCnt); 45 | let _fpath: string = dpath + "/" + i + ".js"; 46 | switch(Random.number(3)) { 47 | case 0: 48 | case 1: 49 | tc.mutate(); 50 | tc.writeToFile(_fpath, seed, true); 51 | tc.revert(); 52 | break; 53 | case 2: 54 | tc.insert(); 55 | tc.writeToFile(_fpath, seed, true); 56 | tc.revert(); 57 | break; 58 | } 59 | 60 | } 61 | 62 | } 63 | 64 | main(); 65 | -------------------------------------------------------------------------------- /fuzz/TS/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "esfuzz", 3 | "version": "0.0.0", 4 | "description": "esfuzz", 5 | "main": "esfuzz.ts", 6 | "author": { 7 | "name": "Soyeon Park", 8 | "email": "" 9 | }, 10 | "dependencies": { 11 | "@babel/generator": "7.3.3", 12 | "@babel/parser": "7.3.3", 13 | "@babel/traverse": "7.2.3", 14 | "@babel/types": "7.3.3", 15 | "@types/argparse": "^1.0.36", 16 | "@types/async": "^2.4.1", 17 | "@types/babel__generator": "7.0.2", 18 | "@types/babel__traverse": "7.0.6", 19 | "@types/js-beautify": "^1.8.0", 20 | "@types/node": "^10.12.26", 21 | "@types/redis": "^2.8.12", 22 | "antlr4ts": "^0.5.0-alpha.2", 23 | "argparse": "^1.0.10", 24 | "ast-pretty-print": "^2.0.1", 25 | "async": "^2.6.2", 26 | "balanced-match": "^1.0.0", 27 | "child_process": "^1.0.2", 28 | "escodegen": "^1.8.0", 29 | "escope": "^3.6.0", 30 | "esprima": "^4.0.1", 31 | "js-beautify": "^1.8.9", 32 | "path": "^0.12.7", 33 | "random-js": "^2.1.0", 34 | "redis": "^2.8.0", 35 | "typescript": "^3.4.4", 36 | "vm2": "^3.6.10" 37 | }, 38 | "devDependencies": { 39 | "antlr4ts-cli": "^0.5.0-alpha.2", 40 | "arg": "^4.1.0", 41 | "babel": "6.23.0", 42 | "colors": "^1.3.3", 43 | "estraverse": "^4.2.0", 44 | "glob": "^7.1.3", 45 | "tmp": "0.0.33", 46 | "vm2": "^3.6.10" 47 | }, 48 | "scripts": { 49 | "antlr4ts": "antlr4ts -visitor ./grammar/Simple.g4", 50 | "js-beautify": "^1.8.9", 51 | "sqlite3": "^4.0.6", 52 | "ts-node": "^8.0.2" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /fuzz/TS/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "sourceMap": true, 6 | "lib": [ 7 | "dom", 8 | "es7" 9 | ], 10 | }, 11 | "includes": [ 12 | "*" 13 | ], 14 | } 15 | -------------------------------------------------------------------------------- /fuzz/TS/typer/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.pyc 3 | -------------------------------------------------------------------------------- /fuzz/TS/typer/jslib/chakra.js: -------------------------------------------------------------------------------- 1 | 2 | function gc() { 3 | for (let i = 0; i < 10; i++) { 4 | new ArrayBuffer(1024 * 1024 * 10); 5 | } 6 | } 7 | 8 | WScript = { 9 | _jscGC: gc, 10 | _jscPrint: console.log, 11 | _convertPathname : function(dosStylePath) 12 | { 13 | return dosStylePath.replace(/\\/g, "/"); 14 | }, 15 | Arguments : [ "summary" ], 16 | Echo : function() 17 | { 18 | WScript._jscPrint.apply(this, arguments); 19 | }, 20 | LoadScriptFile : function(path) 21 | { 22 | }, 23 | Quit : function() 24 | { 25 | }, 26 | Platform : 27 | { 28 | "BUILD_TYPE": "Debug" 29 | } 30 | }; 31 | 32 | function CollectGarbage() 33 | { 34 | WScript._jscGC(); 35 | } 36 | 37 | function $ERROR(e) 38 | { 39 | } 40 | -------------------------------------------------------------------------------- /fuzz/TS/typer/jslib/jsc.js: -------------------------------------------------------------------------------- 1 | function gc() { 2 | for (let i = 0; i < 10; i++) { 3 | new ArrayBuffer(1024 * 1024 * 10); 4 | } 5 | } 6 | 7 | function noInline() { 8 | } 9 | 10 | function OSRExit() { 11 | } 12 | 13 | function ensureArrayStorage() { 14 | } 15 | 16 | function fiatInt52(i) { 17 | return i; 18 | } 19 | 20 | function noDFG() { 21 | } 22 | 23 | function noOSRExitFuzzing() { 24 | } 25 | 26 | function isFinalTier() { 27 | return true; 28 | } 29 | 30 | function transferArrayBuffer() { 31 | } 32 | 33 | function fullGC() { 34 | if (gc !== undefined) 35 | gc(); 36 | else 37 | CollectGarbage(); 38 | } 39 | 40 | function edenGC() { 41 | if (gc !== undefined) 42 | gc(); 43 | else 44 | CollectGarbage(); 45 | } 46 | 47 | function forceGCSlowPaths() { 48 | if (gc !== undefined) 49 | gc(); 50 | else 51 | CollectGarbage(); 52 | } 53 | 54 | function noFTL() { 55 | 56 | } 57 | 58 | function debug(x) { 59 | console.log(x); 60 | } 61 | 62 | function describe(x) { 63 | console.log(x); 64 | } 65 | 66 | function isInt32(i) { 67 | return (typeof i === "number"); 68 | } 69 | 70 | function BigInt(i) { 71 | return i; 72 | } 73 | -------------------------------------------------------------------------------- /fuzz/TS/typer/resolve.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | def equal_type(t1, t2): 4 | return json.dumps(t1) == json.dumps(t2) 5 | 6 | def resolve(output): 7 | records = {} 8 | 9 | for i, line in enumerate(output.split(b'\n')): 10 | line = line.strip() 11 | if not line.startswith(b"~~~TypeInfo:"): continue 12 | line = line[len(b"~~~TypeInfo:"):] 13 | idx = line.find(b">:") 14 | loc = line[0:idx+1].decode() 15 | t_str = line[idx+2:].decode() 16 | t = None 17 | try : 18 | t = json.loads(t_str) 19 | except : 20 | return "" 21 | 22 | if not loc in records: 23 | records[loc] = t 24 | else: 25 | if records[loc]["type"] == "mixed": # already mixed type 26 | flag = False 27 | for subType in records[loc]["extra"]["subTypes"]: 28 | if equal_type(subType, t): 29 | flag = True 30 | break 31 | if not flag: 32 | records[loc]["extra"]["subTypes"].append(t) 33 | elif not equal_type(records[loc], t): 34 | records[loc] = {"type": "mixed", "extra": {"subTypes": [t, records[loc]]}} 35 | else: 36 | pass # the same; no need to update 37 | 38 | return records 39 | -------------------------------------------------------------------------------- /fuzz/TS/typer/typer.py: -------------------------------------------------------------------------------- 1 | import subprocess, os, sys, tempfile, json 2 | import resolve 3 | 4 | # I prefer to use d8 to run the instrumented code, 5 | # which should be fastest I believe. 6 | 7 | d8_path = "/home/soyeon/jsfuzz/js-static/engines/v8-latest/v8/out/Release/d8" 8 | 9 | def get_lib(path): 10 | if path.find("ChakraCore/") != -1 or path.find("chakra/") != -1: 11 | return "./jslib/chakra.js" 12 | elif path.find("spidermonkey/") != -1 or path.find("firefox/") != -1: 13 | return "./jslib/ffx.js" 14 | elif path.find("jsc/") != -1: 15 | return "./jslib/jsc.js" 16 | elif path.find("v8/") != -1: 17 | return "./jslib/v8.js" 18 | else: 19 | return "" 20 | 21 | if __name__ == "__main__": 22 | 23 | target = sys.argv[1] 24 | FNULL = open(os.devnull, 'w') 25 | 26 | if os.path.isdir(target): 27 | for root, dir, files in os.walk(target): 28 | for f in files: 29 | if not f.endswith(".js"): continue 30 | full_path = os.path.join(root, f) 31 | ins_path = full_path + ".jsi" 32 | type_path = full_path + ".t" 33 | 34 | if os.path.isfile(type_path): 35 | print('The type file for %s exists.') 36 | continue 37 | 38 | print('Instrumenting: %s' % full_path) 39 | try: 40 | subprocess.call(['ts-node', 'typer.ts', full_path, ins_path], stdout=FNULL) 41 | except: 42 | print('Instrumentation failed') 43 | continue 44 | print('Instrumentation finished') 45 | 46 | print('Profiling: %s' % full_path) 47 | output = None 48 | lib = get_lib(full_path) 49 | if not os.path.exists(d8_path): 50 | print("Wrong d8_path. Set correct d8_path.") 51 | exit() 52 | cmd = [d8_path] 53 | if len(lib) > 0: 54 | cmd.append(lib) 55 | cmd.append(ins_path) 56 | output = None 57 | try: 58 | output = subprocess.check_output(cmd, timeout=30) 59 | except subprocess.TimeoutExpired as e: 60 | output = e.output 61 | except subprocess.CalledProcessError as e: 62 | output = e.output 63 | 64 | print('Profiling finished') 65 | records = resolve.resolve(output) 66 | if len(records) > 0: 67 | with open(type_path, 'wb') as f: 68 | f.write(json.dumps(records).encode()) 69 | else: 70 | print("Wrong corpus directory path") 71 | 72 | FNULL.close() 73 | -------------------------------------------------------------------------------- /fuzz/afl/.gitignore: -------------------------------------------------------------------------------- 1 | /afl-analyze 2 | /afl-as 3 | /afl-clang 4 | /afl-clang++ 5 | /afl-fuzz 6 | /afl-g++ 7 | /afl-gcc 8 | /afl-gotcpu 9 | /afl-showmap 10 | /afl-tmin 11 | /as 12 | /afl-clang-fast 13 | /afl-clang-fast++ 14 | /afl-llvm-pass.so 15 | *.o 16 | -------------------------------------------------------------------------------- /fuzz/afl/QuickStartGuide.txt: -------------------------------------------------------------------------------- 1 | docs/QuickStartGuide.txt -------------------------------------------------------------------------------- /fuzz/afl/README: -------------------------------------------------------------------------------- 1 | docs/README -------------------------------------------------------------------------------- /fuzz/afl/README-JS.md: -------------------------------------------------------------------------------- 1 | NOTE: 2 | When compiling llvm_mode with clang version >= 3.8, there is an issue: 3 | https://groups.google.com/forum/#!topic/afl-users/D3-jbylxHeg 4 | 5 | I currently use clang-6.0 and compile llvm_mode 6 | make CC=clang CXX=g++ LLVM_CONFIG=llvm-config-6.0 7 | 8 | * Compile Type Script 9 | ```bash 10 | # TODO: Use ts-node, instead of nodejs 11 | $ cd ../TS 12 | $ tsc 13 | ``` 14 | 15 | * Populate initial testcases 16 | 17 | ```bash 18 | $ ../scripts/make_initial_corpus.py $(JS_SAMPLES_DIR) corpus |cpu count| 19 | 20 | $ for i in $(seq 0 1 $(nproc)) 21 | do 22 | tmux new-window -n corpus-$i \ 23 | ./afl-fuzz -m none -o output-corpus-$i -i corpus/output-$i -- $CMDLINE 24 | done 25 | ``` 26 | 27 | * Run fuzzer 28 | 29 | ```bash 30 | $ for i in $(seq 0 1 $(nproc)) 31 | do 32 | tmux new-window -n fuzz-$i \ 33 | ./afl-fuzz -m none -o output-$i -- $CMDLINE 34 | done 35 | ``` 36 | 37 | * Run in remote server 38 | 39 | ```bash 40 | # Setup SSH tunneling for redis (e.g., connect to localhost:9000) 41 | tmux new-session -s ssh-tunneling -d \ 42 | 'ssh -L 9000:localhost:6379 user@redis.server' 43 | 44 | export REDIS_URL=redis://localhost:9000 45 | 46 | # Then, run fuzzers as before 47 | ``` 48 | -------------------------------------------------------------------------------- /fuzz/afl/afl-gotcpu.c: -------------------------------------------------------------------------------- 1 | /* 2 | american fuzzy lop - free CPU gizmo 3 | ----------------------------------- 4 | 5 | Written and maintained by Michal Zalewski 6 | 7 | Copyright 2015, 2016 Google Inc. All rights reserved. 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at: 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | This tool provides a fairly accurate measurement of CPU preemption rate. 16 | It is meant to complement the quick-and-dirty load average widget shown 17 | in the afl-fuzz UI. See docs/parallel_fuzzing.txt for more info. 18 | 19 | For some work loads, the tool may actually suggest running more instances 20 | than you have CPU cores. This can happen if the tested program is spending 21 | a portion of its run time waiting for I/O, rather than being 100% 22 | CPU-bound. 23 | 24 | The idea for the getrusage()-based approach comes from Jakub Wilk. 25 | 26 | */ 27 | 28 | #define AFL_MAIN 29 | #define _GNU_SOURCE 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "types.h" 43 | #include "debug.h" 44 | 45 | #ifdef __linux__ 46 | # define HAVE_AFFINITY 1 47 | #endif /* __linux__ */ 48 | 49 | 50 | /* Get unix time in microseconds. */ 51 | 52 | static u64 get_cur_time_us(void) { 53 | 54 | struct timeval tv; 55 | struct timezone tz; 56 | 57 | gettimeofday(&tv, &tz); 58 | 59 | return (tv.tv_sec * 1000000ULL) + tv.tv_usec; 60 | 61 | } 62 | 63 | 64 | /* Get CPU usage in microseconds. */ 65 | 66 | static u64 get_cpu_usage_us(void) { 67 | 68 | struct rusage u; 69 | 70 | getrusage(RUSAGE_SELF, &u); 71 | 72 | return (u.ru_utime.tv_sec * 1000000ULL) + u.ru_utime.tv_usec + 73 | (u.ru_stime.tv_sec * 1000000ULL) + u.ru_stime.tv_usec; 74 | 75 | } 76 | 77 | 78 | /* Measure preemption rate. */ 79 | 80 | static u32 measure_preemption(u32 target_ms) { 81 | 82 | static volatile u32 v1, v2; 83 | 84 | u64 st_t, en_t, st_c, en_c, real_delta, slice_delta; 85 | s32 loop_repeats = 0; 86 | 87 | st_t = get_cur_time_us(); 88 | st_c = get_cpu_usage_us(); 89 | 90 | repeat_loop: 91 | 92 | v1 = CTEST_BUSY_CYCLES; 93 | 94 | while (v1--) v2++; 95 | sched_yield(); 96 | 97 | en_t = get_cur_time_us(); 98 | 99 | if (en_t - st_t < target_ms * 1000) { 100 | loop_repeats++; 101 | goto repeat_loop; 102 | } 103 | 104 | /* Let's see what percentage of this time we actually had a chance to 105 | run, and how much time was spent in the penalty box. */ 106 | 107 | en_c = get_cpu_usage_us(); 108 | 109 | real_delta = (en_t - st_t) / 1000; 110 | slice_delta = (en_c - st_c) / 1000; 111 | 112 | return real_delta * 100 / slice_delta; 113 | 114 | } 115 | 116 | 117 | /* Do the benchmark thing. */ 118 | 119 | int main(int argc, char** argv) { 120 | 121 | #ifdef HAVE_AFFINITY 122 | 123 | u32 cpu_cnt = sysconf(_SC_NPROCESSORS_ONLN), 124 | idle_cpus = 0, maybe_cpus = 0, i; 125 | 126 | SAYF(cCYA "afl-gotcpu " cBRI VERSION cRST " by \n"); 127 | 128 | ACTF("Measuring per-core preemption rate (this will take %0.02f sec)...", 129 | ((double)CTEST_CORE_TRG_MS) / 1000); 130 | 131 | for (i = 0; i < cpu_cnt; i++) { 132 | 133 | s32 fr = fork(); 134 | 135 | if (fr < 0) PFATAL("fork failed"); 136 | 137 | if (!fr) { 138 | 139 | cpu_set_t c; 140 | u32 util_perc; 141 | 142 | CPU_ZERO(&c); 143 | CPU_SET(i, &c); 144 | 145 | if (sched_setaffinity(0, sizeof(c), &c)) 146 | PFATAL("sched_setaffinity failed"); 147 | 148 | util_perc = measure_preemption(CTEST_CORE_TRG_MS); 149 | 150 | if (util_perc < 110) { 151 | 152 | SAYF(" Core #%u: " cLGN "AVAILABLE\n" cRST, i); 153 | exit(0); 154 | 155 | } else if (util_perc < 250) { 156 | 157 | SAYF(" Core #%u: " cYEL "CAUTION " cRST "(%u%%)\n", i, util_perc); 158 | exit(1); 159 | 160 | } 161 | 162 | SAYF(" Core #%u: " cLRD "OVERBOOKED " cRST "(%u%%)\n" cRST, i, 163 | util_perc); 164 | exit(2); 165 | 166 | } 167 | 168 | } 169 | 170 | for (i = 0; i < cpu_cnt; i++) { 171 | 172 | int ret; 173 | if (waitpid(-1, &ret, 0) < 0) PFATAL("waitpid failed"); 174 | 175 | if (WEXITSTATUS(ret) == 0) idle_cpus++; 176 | if (WEXITSTATUS(ret) <= 1) maybe_cpus++; 177 | 178 | } 179 | 180 | SAYF(cGRA "\n>>> "); 181 | 182 | if (idle_cpus) { 183 | 184 | if (maybe_cpus == idle_cpus) { 185 | 186 | SAYF(cLGN "PASS: " cRST "You can run more processes on %u core%s.", 187 | idle_cpus, idle_cpus > 1 ? "s" : ""); 188 | 189 | } else { 190 | 191 | SAYF(cLGN "PASS: " cRST "You can run more processes on %u to %u core%s.", 192 | idle_cpus, maybe_cpus, maybe_cpus > 1 ? "s" : ""); 193 | 194 | } 195 | 196 | SAYF(cGRA " <<<" cRST "\n\n"); 197 | return 0; 198 | 199 | } 200 | 201 | if (maybe_cpus) { 202 | 203 | SAYF(cYEL "CAUTION: " cRST "You may still have %u core%s available.", 204 | maybe_cpus, maybe_cpus > 1 ? "s" : ""); 205 | SAYF(cGRA " <<<" cRST "\n\n"); 206 | return 1; 207 | 208 | } 209 | 210 | SAYF(cLRD "FAIL: " cRST "All cores are overbooked."); 211 | SAYF(cGRA " <<<" cRST "\n\n"); 212 | return 2; 213 | 214 | #else 215 | 216 | u32 util_perc; 217 | 218 | SAYF(cCYA "afl-gotcpu " cBRI VERSION cRST " by \n"); 219 | 220 | /* Run a busy loop for CTEST_TARGET_MS. */ 221 | 222 | ACTF("Measuring gross preemption rate (this will take %0.02f sec)...", 223 | ((double)CTEST_TARGET_MS) / 1000); 224 | 225 | util_perc = measure_preemption(CTEST_TARGET_MS); 226 | 227 | /* Deliver the final verdict. */ 228 | 229 | SAYF(cGRA "\n>>> "); 230 | 231 | if (util_perc < 105) { 232 | 233 | SAYF(cLGN "PASS: " cRST "You can probably run additional processes."); 234 | 235 | } else if (util_perc < 130) { 236 | 237 | SAYF(cYEL "CAUTION: " cRST "Your CPU may be somewhat overbooked (%u%%).", 238 | util_perc); 239 | 240 | } else { 241 | 242 | SAYF(cLRD "FAIL: " cRST "Your CPU is overbooked (%u%%).", util_perc); 243 | 244 | } 245 | 246 | SAYF(cGRA " <<<" cRST "\n\n"); 247 | 248 | return (util_perc > 105) + (util_perc > 130); 249 | 250 | #endif /* ^HAVE_AFFINITY */ 251 | 252 | } 253 | -------------------------------------------------------------------------------- /fuzz/afl/dictionaries/README.dictionaries: -------------------------------------------------------------------------------- 1 | ================ 2 | AFL dictionaries 3 | ================ 4 | 5 | (See ../docs/README for the general instruction manual.) 6 | 7 | This subdirectory contains a set of dictionaries that can be used in 8 | conjunction with the -x option to allow the fuzzer to effortlessly explore the 9 | grammar of some of the more verbose data formats or languages. The basic 10 | principle behind the operation of fuzzer dictionaries is outlined in section 9 11 | of the "main" README for the project. 12 | 13 | Custom dictionaries can be added at will. They should consist of a 14 | reasonably-sized set of rudimentary syntax units that the fuzzer will then try 15 | to clobber together in various ways. Snippets between 2 and 16 bytes are usually 16 | the sweet spot. 17 | 18 | Custom dictionaries can be created in two ways: 19 | 20 | - By creating a new directory and placing each token in a separate file, in 21 | which case, there is no need to escape or otherwise format the data. 22 | 23 | - By creating a flat text file where tokens are listed one per line in the 24 | format of name="value". The alphanumeric name is ignored and can be omitted, 25 | although it is a convenient way to document the meaning of a particular 26 | token. The value must appear in quotes, with hex escaping (\xNN) applied to 27 | all non-printable, high-bit, or otherwise problematic characters (\\ and \" 28 | shorthands are recognized, too). 29 | 30 | The fuzzer auto-selects the appropriate mode depending on whether the -x 31 | parameter is a file or a directory. 32 | 33 | In the file mode, every name field can be optionally followed by @, e.g.: 34 | 35 | keyword_foo@1 = "foo" 36 | 37 | Such entries will be loaded only if the requested dictionary level is equal or 38 | higher than this number. The default level is zero; a higher value can be set 39 | by appending @ to the dictionary file name, like so: 40 | 41 | -x path/to/dictionary.dct@2 42 | 43 | Good examples of dictionaries can be found in xml.dict and png.dict. 44 | -------------------------------------------------------------------------------- /fuzz/afl/dictionaries/gif.dict: -------------------------------------------------------------------------------- 1 | # 2 | # AFL dictionary for GIF images 3 | # ----------------------------- 4 | # 5 | # Created by Michal Zalewski 6 | # 7 | 8 | header_87a="87a" 9 | header_89a="89a" 10 | header_gif="GIF" 11 | 12 | marker_2c="," 13 | marker_3b=";" 14 | 15 | section_2101="!\x01\x12" 16 | section_21f9="!\xf9\x04" 17 | section_21fe="!\xfe" 18 | section_21ff="!\xff\x11" 19 | -------------------------------------------------------------------------------- /fuzz/afl/dictionaries/html_tags.dict: -------------------------------------------------------------------------------- 1 | # 2 | # AFL dictionary for HTML parsers (tags only) 3 | # ------------------------------------------- 4 | # 5 | # A basic collection of HTML tags likely to matter to HTML parsers. Does *not* 6 | # include any attributes or attribute values. 7 | # 8 | # Created by Michal Zalewski 9 | # 10 | 11 | tag_a="" 12 | tag_abbr="" 13 | tag_acronym="" 14 | tag_address="
" 15 | tag_annotation_xml="" 16 | tag_applet="" 17 | tag_area="" 18 | tag_article="
" 19 | tag_aside="