From 5e1e88ef69ec82b3f76915e59b901ba621ce9d44 Mon Sep 17 00:00:00 2001 From: jiangkaiwen Date: Sun, 21 Jan 2024 13:56:41 +0000 Subject: [PATCH] fuzzilli supports es2abc Signed-off-by: jiangkaiwen Change-Id: If4c7d0c45ce1c358de3c38d9a6e51fd154e8aa45 --- fuzzilli/BUILD.gn | 49 ++++++ fuzzilli/README.md | 16 ++ fuzzilli/README_zh.md | 16 ++ fuzzilli/config.py | 38 +++++ fuzzilli/coverage/coverage.cpp | 110 +++++++++++++ fuzzilli/coverage/coverage.h | 30 ++++ fuzzilli/gen_abc.py | 271 +++++++++++++++++++++++++++++++++ fuzzilli/main.cpp | 168 ++++++++++++++++++++ fuzzilli/patchs/build_gn.patch | 11 ++ fuzzilli/patchs/fuzzilli.patch | 57 +++++++ fuzzilli/run_fuzzy.py | 178 ++++++++++++++++++++++ 11 files changed, 944 insertions(+) create mode 100644 fuzzilli/BUILD.gn create mode 100644 fuzzilli/README.md create mode 100755 fuzzilli/README_zh.md create mode 100644 fuzzilli/config.py create mode 100644 fuzzilli/coverage/coverage.cpp create mode 100644 fuzzilli/coverage/coverage.h create mode 100644 fuzzilli/gen_abc.py create mode 100644 fuzzilli/main.cpp create mode 100644 fuzzilli/patchs/build_gn.patch create mode 100644 fuzzilli/patchs/fuzzilli.patch create mode 100644 fuzzilli/run_fuzzy.py diff --git a/fuzzilli/BUILD.gn b/fuzzilli/BUILD.gn new file mode 100644 index 0000000000..5143dc34bc --- /dev/null +++ b/fuzzilli/BUILD.gn @@ -0,0 +1,49 @@ +# Copyright (c) 2021-2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import("//arkcompiler/ets_frontend/es2panda/es2abc_config.gni") +import("//arkcompiler/ets_frontend/ets_frontend_config.gni") +import("//arkcompiler/runtime_core/ark_config.gni") + +ohos_executable("arkfuzzer") { + use_exceptions = true + + sources = [ + "coverage/coverage.cpp", + "main.cpp", + ] + + include_dirs = [ "./coverage" ] + + cflags = [] + cflags += [ "-fsanitize-coverage=trace-pc-guard" ] + + ldflags = [] + ldflags += [ "-Wl,-Bstatic" ] + ldflags += [ "-lstdc++" ] + ldflags += [ "-Wl,-Bdynamic" ] + + install_enable = false + + part_name = "ets_frontend" + subsystem_name = "arkcompiler" +} + +group("arkfuzzer_build") { + if (host_os == "linux") { + deps = [ ":arkfuzzer(${toolchain_linux})" ] + } + + if (host_os == "mac") { + deps = [ ":arkfuzzer(${toolchain_mac})" ] + } +} diff --git a/fuzzilli/README.md b/fuzzilli/README.md new file mode 100644 index 0000000000..11011c98e1 --- /dev/null +++ b/fuzzilli/README.md @@ -0,0 +1,16 @@ +# fuzzilli + +## Project Description +The main purpose of this project is to perform fuzzilli adaptation testing on ES2aBC. +This project relies on Python 3, Git, Swift, ets_runtime component ark_js_vm executable files and ets_frond component es2abc executable file. +All outputs of this project are located in the fuzzilli/output directory. + +## Usage notes +Execute Python script run_ fuzzy.py, automatically executes fuzzilli source code downloads, swift tool downloads, patch updates, compilation operations, and runs fuzzilli. + +## Run an example +$:cd arkcompiler/ets_frontend/ +$:python fuzzilli/run_fuzzy.py + +### Precautions +This project relies on ets_runtime's component ark_js_vm executable files and ets_frontend's component es2abc executable file. \ No newline at end of file diff --git a/fuzzilli/README_zh.md b/fuzzilli/README_zh.md new file mode 100755 index 0000000000..fb0712c12c --- /dev/null +++ b/fuzzilli/README_zh.md @@ -0,0 +1,16 @@ +# fuzzilli + +## 项目说明 + 本项目主要目的为fuzzilli适配测试es2abc。 + 本项目依赖python3、git、swift、ets_runtime组件下的ark_js_vm可执行文件以及ets_frontend组件下的es2abc可执行文件。 + 本项目所有输出在fuzzilli/output目录下。 + +## 用法说明 + 执行python脚本run_fuzzy.py,自动执行fuzzilli源码下载、swift工具下载、补丁更新、编译操作以及运行fuzzilli。 + +## 运行示例 +$:cd arkcompiler/ets_frontend/ +$:python fuzzilli/run_fuzzy.py + +## 注意事项 + 本项目依赖ets_runtime组件下的ark_js_vm可执行文件以及ets_frontend组件下的es2abc可执行文件 \ No newline at end of file diff --git a/fuzzilli/config.py b/fuzzilli/config.py new file mode 100644 index 0000000000..92ef25a0b2 --- /dev/null +++ b/fuzzilli/config.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Copyright (c) 2023 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + + +import os + +from test262.config import ARGS_PREFIX, RK3568_PRODUCT_NAME, ARK_DIR_SUFFIX + +FUZZY_DIR_NAME = 'fuzzilli' +FUZZILLI_DIR_NAME = 'fuzzilli' +FUZZILLI_PATCH_DIR_NAME = 'patchs' +FUZZILLI_OUTPUT_DIR_NAME = 'output' +FUZZY_DIR = os.path.join(FUZZY_DIR_NAME, FUZZILLI_DIR_NAME) + +FUZZY_GIT_HASH = "79c777839d23114e6f85322eefa6d44af53814ab" + +FUZZY_GIT_URL = "https://gitee.com/mirrors_googleprojectzero/fuzzilli.git" +SWIFT_DOWNLOAD_URL = 'https://download.swift.org/swift-5.9.2-release/ubuntu1804/'\ + 'swift-5.9.2-RELEASE/swift-5.9.2-RELEASE-ubuntu18.04.tar.gz' + +FUZZY_DEFAULT_ARK_FRONTEND_BINARY = os.path.join(ARGS_PREFIX, RK3568_PRODUCT_NAME, ARK_DIR_SUFFIX, 'es2abc') + +DEFAULT_OPEN_FUZZILLI_MODE = False diff --git a/fuzzilli/coverage/coverage.cpp b/fuzzilli/coverage/coverage.cpp new file mode 100644 index 0000000000..4befd2c424 --- /dev/null +++ b/fuzzilli/coverage/coverage.cpp @@ -0,0 +1,110 @@ +/** + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "coverage.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BYTE_NUMBER 8 +#define SHM_SIZE 0x100000 +#define MAX_EDGES ((SHM_SIZE - 4) * BYTE_NUMBER) + +struct ShareMemData { + uint32_t numEdges; + unsigned char edges[1]; +}; + +struct ShareMemData* shmem; + +uint32_t *edgesStart, *edgesStop; + +void SanitizerCovResetEdgeGuards() +{ + uint32_t n = 0; + for (uint32_t* x = edgesStart; x < edgesStop && n < MAX_EDGES; x++) + *x = ++n; +} + +// SanitizerCoverage fixed interface name +extern "C" void __sanitizer_cov_trace_pc_guard_init(uint32_t* start, uint32_t* stop) +{ + if (shmem) { + if (!(edgesStart == start && edgesStop == stop)) { + fprintf(stderr, + "[COV] Multiple initialization of shmem!" + " This is probably not intended! Currently only one edge" + " region is supported\n"); + return; + } + // Already initialized. + return; + } + // Map the shared memory region + const char* shmKey = getenv("SHM_ID"); + if (!shmKey) { + puts("[COV] no shared memory bitmap available, skipping"); + shmem = reinterpret_cast(malloc(SHM_SIZE)); + } else { + int fd = shm_open(shmKey, O_RDWR, S_IREAD | S_IWRITE); + if (fd <= -1) { + fprintf(stderr, "[COV] Failed to open shared memory region\n"); + return; + } + + shmem = reinterpret_cast(mmap(nullptr, SHM_SIZE, PROT_READ | + PROT_WRITE, MAP_SHARED, fd, 0)); + if (shmem == MAP_FAILED) { + fprintf(stderr, "[COV] Failed to mmap shared memory region\n"); + return; + } + } + + edgesStart = start; + edgesStop = stop; + SanitizerCovResetEdgeGuards(); + + shmem->numEdges = static_cast(stop - start); + printf("[COV] edge counters initialized. Shared memory: %s with %u edges\n", shmKey, shmem->numEdges); +} + +uint32_t SanitizerCovCountDiscoveredEdges() +{ + uint32_t onEdgesCounter = 0; + for (uint32_t i = 1; i < 1 + shmem->numEdges; ++i) { + const uint32_t byteIndex = i >> 3; // Divide by 8 using a shift operation + const uint32_t bitIndex = i & 7; // Modulo 8 using a bitwise AND operation + + if (shmem->edges[byteIndex] & (1 << bitIndex)) { + ++onEdgesCounter; + } + } + return onEdgesCounter; +} + +// SanitizerCoverage fixed interface name +extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t* guard) +{ + uint32_t index = *guard; + shmem->edges[index / BYTE_NUMBER] |= 1 << (index % BYTE_NUMBER); + *guard = 0; +} diff --git a/fuzzilli/coverage/coverage.h b/fuzzilli/coverage/coverage.h new file mode 100644 index 0000000000..ab4f8c0e75 --- /dev/null +++ b/fuzzilli/coverage/coverage.h @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _COVERAGE_H_ +#define _COVERAGE_H_ + +// This file is defining functions to handle coverage which are needed for +// fuzzilli fuzzer It communicates coverage bitmap with fuzzilli through shared +// memory +// https://clang.llvm.org/docs/SanitizerCoverage.html + +#include +#include + +void SanitizerCovResetEdgeGuards(); +uint32_t SanitizerCovCountDiscoveredEdges(); + +#endif // _COVERAGE_H_ \ No newline at end of file diff --git a/fuzzilli/gen_abc.py b/fuzzilli/gen_abc.py new file mode 100644 index 0000000000..447be54da7 --- /dev/null +++ b/fuzzilli/gen_abc.py @@ -0,0 +1,271 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Copyright (c) 2023 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Use ark to execute fuzzilli test suite + +generate abc with javascript +""" + + +import argparse +import collections +import os +import sys +import subprocess +import datetime + +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +from test262.utils import report_command +from test262.config import DEFAULT_TIMEOUT, DEFAULT_THREADS, ARK_FRONTEND_LIST, DEFAULT_ARK_ARCH, ARK_ARCH_LIST, \ + DEFAULT_OPT_LEVEL, DEFAULT_ES2ABC_THREAD_COUNT, DEFAULT_PRODUCT_NAME, DEFAULT_HOST_PATH, DEFAULT_HOST_TYPE, \ + DEFAULT_ARK_TOOL, DEFAULT_ARK_AOT_TOOL, DEFAULT_LIBS_DIR, DEFAULT_MERGE_ABC_BINARY, DEFAULT_MERGE_ABC_MODE, \ + RK3568_PRODUCT_NAME, ARGS_PREFIX, ARK_DIR_SUFFIX, ICUI_DIR_SUFFIX, ARK_JS_RUNTIME_DIR_SUFFIX, ZLIB_DIR_SUFFIX, \ + LLVM_DIR +from config import FUZZY_DEFAULT_ARK_FRONTEND_BINARY, DEFAULT_OPEN_FUZZILLI_MODE + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--dir', metavar='DIR', + help='Directory to test ') + parser.add_argument('--file', metavar='FILE', + required=True, + help='File to test') + parser.add_argument('--mode', + nargs='?', choices=[1, 2, 3], type=int, + help='selection information as: ' + + '1: only default \n ' + + '2: only strict mode \n' + + '3: both default and strict mode\n') + parser.add_argument('--es51', action='store_true', + help='Run test262 ES5.1 version') + parser.add_argument('--es2021', default=False, const='all', + nargs='?', choices=['all', 'only'], + help='Run test262 - ES2021. ' + + 'all: Contains all use cases for es5_tests and es2015_tests and ' + 'es2021_tests and intl_tests' + + 'only: Only include use cases for ES2021') + parser.add_argument('--es2022', default=False, const='all', + nargs='?', choices=['all', 'only'], + help='Run test262 - ES2022. ' + + 'all: Contains all use cases for es5_tests and es2015_tests and es2021_tests' + + 'and es2022_tests and intl_tests' + + 'only: Only include use cases for ES2022') + parser.add_argument('--es2023', default=False, const='all', + nargs='?', choices=['all', 'only'], + help='Run test262 - ES2023. ' + + 'all: Contains all use cases for es5_tests and es2015_tests and es2021_tests' + + 'and es2022_tests and es2023_tests and intl_tests' + + 'only: Only include use cases for ES2023') + parser.add_argument('--intl', default=False, const='intl', + nargs='?', choices=['intl'], + help='Run test262 - Intltest. ' + + 'intl: Only include use cases for intlcsae') + parser.add_argument('--es2015', default=False, const='es2015', + nargs='?', choices=['es2015'], + help='Run test262 - es2015. ' + + 'es2015: Only include use cases for es2015') + parser.add_argument('--ci-build', action='store_true', + help='Run test262 ES2015 filter cases for build version') + parser.add_argument('--esnext', action='store_true', + help='Run test262 - ES.next.') + parser.add_argument('--engine', metavar='FILE', + help='Other engine binarys to run tests(as:d8,qjs...)') + parser.add_argument('--babel', action='store_true', + help='Whether to use Babel conversion') + parser.add_argument('--timeout', default=DEFAULT_TIMEOUT, type=int, + help='Set a custom test timeout in milliseconds !!!\n') + parser.add_argument('--threads', default=DEFAULT_THREADS, type=int, + help="Run this many tests in parallel.") + parser.add_argument('--hostArgs', + help="command-line arguments to pass to eshost host\n") + parser.add_argument('--ark-tool', + help="ark's binary tool") + parser.add_argument('--ark-aot', action='store_true', + help="Run test262 with aot") + parser.add_argument('--ark-aot-tool', + help="ark's aot tool") + parser.add_argument("--libs-dir", + help="The path collection of dependent so has been divided by':'") + parser.add_argument('--ark-frontend', + nargs='?', choices=ARK_FRONTEND_LIST, type=str, + help="Choose one of them") + parser.add_argument('--ark-frontend-binary', + help="ark frontend conversion binary tool") + parser.add_argument('--ark-arch', + default=DEFAULT_ARK_ARCH, + nargs='?', choices=ARK_ARCH_LIST, type=str, + help="Choose one of them") + parser.add_argument('--ark-arch-root', + default=DEFAULT_ARK_ARCH, + help="the root path for qemu-aarch64 or qemu-arm") + parser.add_argument('--opt-level', + default=DEFAULT_OPT_LEVEL, + help="the opt level for es2abc") + parser.add_argument('--es2abc-thread-count', + default=DEFAULT_ES2ABC_THREAD_COUNT, + help="the thread count for es2abc") + parser.add_argument('--merge-abc-binary', + help="frontend merge abc binary tool") + parser.add_argument('--merge-abc-mode', + help="run test for merge abc mode") + parser.add_argument('--product-name', + default=DEFAULT_PRODUCT_NAME, + help="ark's product name") + parser.add_argument('--run-pgo', action='store_true', + help="Run test262 with aot pgo") + parser.add_argument('--open-fuzzy-mode', action='store_true', default=DEFAULT_OPEN_FUZZILLI_MODE, + help='run test with open fuzzilli mode') + return parser.parse_args() + + +def run_check(runnable, env=None): + report_command('Test command:', runnable, env=env) + + if env is not None: + full_env = dict(os.environ) + full_env.update(env) + env = full_env + + proc = subprocess.Popen(runnable, env=env) + stdout, stderr = proc.communicate() + if stdout: + print(f'Out message:{stdout.decode()}') + if stderr: + print(f'Error message:{stderr.decode()}') + return proc.returncode + + +def get_host_path_type(args): + host_path = DEFAULT_HOST_PATH + host_type = DEFAULT_HOST_TYPE + if args.engine: + host_path = args.engine + host_type = os.path.split(args.engine.strip())[1] + return host_path, host_type + + +def get_host_args(args, host_type): + host_args = "" + ark_tool = DEFAULT_ARK_TOOL + ark_aot_tool = DEFAULT_ARK_AOT_TOOL + libs_dir = DEFAULT_LIBS_DIR + ark_frontend = ARK_FRONTEND_LIST[1] + ark_frontend_binary = FUZZY_DEFAULT_ARK_FRONTEND_BINARY + ark_arch = DEFAULT_ARK_ARCH + opt_level = DEFAULT_OPT_LEVEL + es2abc_thread_count = DEFAULT_ES2ABC_THREAD_COUNT + merge_abc_binary = DEFAULT_MERGE_ABC_BINARY + merge_abc_mode = DEFAULT_MERGE_ABC_MODE + product_name = RK3568_PRODUCT_NAME + + if args.product_name: + product_name = args.product_name + ark_dir = f"{ARGS_PREFIX}{product_name}{ARK_DIR_SUFFIX}" + icui_dir = f"{ARGS_PREFIX}{product_name}{ICUI_DIR_SUFFIX}" + ark_js_runtime_dir = f"{ARGS_PREFIX}{product_name}{ARK_JS_RUNTIME_DIR_SUFFIX}" + zlib_dir = f"{ARGS_PREFIX}{product_name}{ZLIB_DIR_SUFFIX}" + + ark_tool = os.path.join(ark_js_runtime_dir, "ark_js_vm") + libs_dir = f"{icui_dir}:{LLVM_DIR}:{ark_js_runtime_dir}:{zlib_dir}" + ark_aot_tool = os.path.join(ark_js_runtime_dir, "ark_aot_compiler") + merge_abc_binary = os.path.join(ark_dir, "merge_abc") + + if args.hostArgs: + host_args = args.hostArgs + + if args.ark_tool: + ark_tool = args.ark_tool + + if args.ark_aot_tool: + ark_aot_tool = args.ark_aot_tool + + if args.libs_dir: + libs_dir = args.libs_dir + + if args.ark_frontend: + ark_frontend = args.ark_frontend + + if args.ark_frontend_binary: + ark_frontend_binary = args.ark_frontend_binary + + if args.opt_level: + opt_level = args.opt_level + + if args.es2abc_thread_count: + es2abc_thread_count = args.es2abc_thread_count + + if args.merge_abc_binary: + merge_abc_binary = args.merge_abc_binary + + if args.merge_abc_mode: + merge_abc_mode = args.merge_abc_mode + + if host_type == DEFAULT_HOST_TYPE: + host_args = f"-B test262/run_sunspider.py " + host_args += f"--ark-tool={ark_tool} " + if args.ark_aot: + host_args += f"--ark-aot " + if args.run_pgo: + host_args += f"--run-pgo " + host_args += f"--ark-aot-tool={ark_aot_tool} " + host_args += f"--libs-dir={libs_dir} " + host_args += f"--ark-frontend={ark_frontend} " + host_args += f"--ark-frontend-binary={ark_frontend_binary} " + host_args += f"--opt-level={opt_level} " + host_args += f"--es2abc-thread-count={es2abc_thread_count} " + host_args += f"--merge-abc-binary={merge_abc_binary} " + host_args += f"--merge-abc-mode={merge_abc_mode} " + host_args += f"--product-name={product_name} " + + if args.ark_arch != ark_arch: + host_args += f"--ark-arch={args.ark_arch} " + host_args += f"--ark-arch-root={args.ark_arch_root} " + + return host_args + + +def run_fuzzy_test(args): + host_path, host_type = get_host_path_type(args) + host_args = get_host_args(args, host_type) + fuzzy_js_file = args.file + host_args = host_args.replace(fuzzy_js_file, '') + test_cmd = ['python3'] + host_args.strip().split(' ') + test_cmd.append(f"--js-file={fuzzy_js_file}") + return run_check(test_cmd) + + +Check = collections.namedtuple('Check', ['enabled', 'runner', 'arg']) + + +def main(args): + if args.open_fuzzy_mode: + print("\nWait a moment..........\n") + start_time = datetime.datetime.now() + check = Check(True, run_fuzzy_test, args) + ret = check.runner(check.arg) + if ret: + sys.exit(ret) + end_time = datetime.datetime.now() + print(f"used time is: {str(end_time - start_time)}") + else: + print('You should execute the script with open fuzzilli mode by `--open-fuzzy-mode`!') + sys.exit(1) + + +if __name__ == "__main__": + sys.exit(main(parse_args())) diff --git a/fuzzilli/main.cpp b/fuzzilli/main.cpp new file mode 100644 index 0000000000..ba288f9166 --- /dev/null +++ b/fuzzilli/main.cpp @@ -0,0 +1,168 @@ +/** + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "coverage/coverage.h" +#include "securec.h" + +#include +#include +#include +#include +#include + +#define REPRL_CRFD 100 // Control read file decriptor +#define REPRL_CWFD 101 // Control write file decriptor +#define REPRL_DRFD 102 // Data read file decriptor +#define REPRL_DWFD 103 // Data write file decriptor +#define REPRL_HELO_LEN 4 +#define REPRL_INFO_LEN 8 +std::ofstream eslog("es2abc.log", std::ios::trunc); + +bool fuzzilliReprl = true; +#define TESTCASE_JS_FILE_PATH "output/" +#define JSTESTCASE_FILE_NAME_LEN 64 +#define COV_INIT_BUILTINS_EDGES 128 +#define RUN_PYTHON_CMD_LEN 1024 +#define EXECUTE_JSTESTCASE_BY_PYTHON "cd ../../;\ +python3 fuzzilli/gen_abc.py --file ./fuzzilli/fuzzilli/%s --es2021 all \ +--ark-frontend-binary=../../out/rk3568/clang_x64/arkcompiler/ets_frontend/es2abc \ +--ark-frontend=es2panda --product-name=rk3568 --open-fuzzy-mode 2>&1" + +int Receve(char *jsName, int nameLen, int bufflen) +{ + char *buffer = new char[bufflen + 1]; + char *ptr = buffer; + size_t remain = bufflen; + while (remain > 0) { + ssize_t rv = read(REPRL_DRFD, ptr, remain); + if (rv == 0) { + break; + } + remain -= rv; + ptr += rv; + } + + // generate js testcase file + buffer[bufflen] = 0; + static int index = 0; + int num = 0; + num = snprintf_s(jsName, nameLen, nameLen - 1, "%s%d.js", TESTCASE_JS_FILE_PATH, index); + if (num < 0) { + delete[] buffer; + return 1; + } + std::string jsTestCaseName = jsName; + std::ofstream jsTestCase(jsTestCaseName, std::ios::trunc); + jsTestCase << buffer << std::endl; + delete[] buffer; + index++; + return 0; +} + +int Execute() +{ + size_t scriptSize; + unsigned action = 0; + int res = 0; + char jsName[JSTESTCASE_FILE_NAME_LEN] = {0}; + ssize_t nRead = read(REPRL_CRFD, &action, REPRL_HELO_LEN); + if (nRead != REPRL_HELO_LEN || action != 'cexe') { + eslog << "REPRL: Unknown action: %u" << action << " line = " << __LINE__ << std::endl; + return 1; // fail + } + if (read(REPRL_CRFD, &scriptSize, REPRL_INFO_LEN) != REPRL_INFO_LEN) { + return 1; + } + if (scriptSize == 0) { + return 0; + } + + res = Receve(jsName, JSTESTCASE_FILE_NAME_LEN, scriptSize); + if (res) { + return 1; + } + + // run received js test case by python + char cmd[RUN_PYTHON_CMD_LEN] = {0}; + char buff[1024] = {0}; + FILE *pr = nullptr; + int num = 0; + num = snprintf_s(cmd, RUN_PYTHON_CMD_LEN, RUN_PYTHON_CMD_LEN - 1, EXECUTE_JSTESTCASE_BY_PYTHON, jsName); + if (num < 0) { + pclose(pr); + return 1; + } + if ((pr = popen(cmd, "r")) != nullptr) { + if (fgets(buff, sizeof(buff) - 1, pr) != nullptr) { + if (!strstr(buff, "Test command")) { + res = 1; + } + } + } + pclose(pr); + + return res; +} + +bool InitialReprl() +{ + char helo[] = "HELO"; + if (write(REPRL_CWFD, helo, REPRL_HELO_LEN) != REPRL_HELO_LEN || + read(REPRL_CRFD, helo, REPRL_HELO_LEN) != REPRL_HELO_LEN) { + eslog << "write or read fail" << __LINE__ << std::endl; + return false; + } + + if (memcmp(helo, "HELO", REPRL_HELO_LEN) != 0) { + eslog << "REPRL: Invalid response from parent" << __LINE__ << std::endl; + return false; + } + + return true; +} + +bool DealResult(int result) +{ + int status = result << REPRL_INFO_LEN; + bool res = true; + fflush(stdout); + fflush(stderr); + if (write(REPRL_CWFD, &status, REPRL_HELO_LEN) != REPRL_HELO_LEN) { + eslog << "Deal result write fail!" << __LINE__ << std::endl; + res = false; + } + SanitizerCovResetEdgeGuards(); + + return res; +} + +int main(int argc, char **argv) +{ + int result = 0; + + if (!InitialReprl()) { + return 1; + } + + do { + result = Execute(); + if (!DealResult(result)) { + fuzzilliReprl = false; + eslog << "DealResult" << __LINE__ << std::endl; + } + } while (fuzzilliReprl); + + return 0; +} \ No newline at end of file diff --git a/fuzzilli/patchs/build_gn.patch b/fuzzilli/patchs/build_gn.patch new file mode 100644 index 0000000000..5e8801f699 --- /dev/null +++ b/fuzzilli/patchs/build_gn.patch @@ -0,0 +1,11 @@ +diff -uN b/BUILD.gn a/BUILD.gn +--- b/BUILD.gn 2023-12-29 19:04:37.622829550 +0800 ++++ a/BUILD.gn 2023-12-29 19:04:03.174744288 +0800 +@@ -15,6 +15,7 @@ + + group("ets_frontend_build") { + deps = [ ++ "./fuzzilli:arkfuzzer_build", + "./es2panda:es2panda_build", + "./merge_abc:merge_proto_abc_build", + ] diff --git a/fuzzilli/patchs/fuzzilli.patch b/fuzzilli/patchs/fuzzilli.patch new file mode 100644 index 0000000000..668ad73579 --- /dev/null +++ b/fuzzilli/patchs/fuzzilli.patch @@ -0,0 +1,57 @@ +diff -uN a/Sources/FuzzilliCli/Profiles/Es2abcProfile.swift b/Sources/FuzzilliCli/Profiles/Es2abcProfile.swift +--- a/Sources/FuzzilliCli/Profiles/Es2abcProfile.swift 1970-01-01 08:00:00.000000000 +0800 ++++ b/Sources/FuzzilliCli/Profiles/Es2abcProfile.swift 2023-12-28 19:22:18.916794700 +0800 +@@ -0,0 +1,44 @@ ++import Fuzzilli ++ ++fileprivate let PrintGenerator = CodeGenerator("PrintGenerator", inputs: .preferred(.object())) {b, o in ++ let f = b.loadBuiltin("arkPrint") ++ b.callFunction(f, withArgs:[o]) ++} ++ ++fileprivate let RunNearStackLimitGenerator = CodeGenerator("RunNearStackLimitGenerator", inputs: .required(.function())) {b, f in ++ let fun = b.loadBuiltin("RunNearStackLimit") ++ b.callFunction(fun, withArgs:[f]) ++} ++ ++let es2abcProfile = Profile( ++ processArgs: { randomize in ++ var args = [""] ++ guard randomize else { return args } ++ return args ++ }, ++ processEnv: [:], ++ maxExecsBeforeRespawn: 2000000, ++ timeout: 10000, ++ codePrefix: """ ++ """, ++ codeSuffix: """ ++ """, ++ //ecmaVersion: ECMAScriptVersion([.LetAndConstDeclare]), ++ ecmaVersion: ECMAScriptVersion.es6, ++ crashTests: [], ++ additionalCodeGenerators:[ ++ (PrintGenerator, 40), ++ (RunNearStackLimitGenerator, 5), ++ ], ++ additionalProgramTemplates: WeightedList([]), ++ disabledCodeGenerators: [], ++ disabledMutators: [], ++ additionalBuiltins: [ ++ "runNearStackLimit" : .function([.function()] => .boolean), ++ "print" : .function([] => .undefined), ++ "arkPrint" : .function([] => .undefined), ++ "sgc" : .function([] => .undefined), ++ "bgc" : .function([] => .undefined), ++ ], ++ optionalPostProcessor: nil ++) +diff -uN a/Sources/FuzzilliCli/Profiles/Profile.swift b/Sources/FuzzilliCli/Profiles/Profile.swift +--- a/Sources/FuzzilliCli/Profiles/Profile.swift 2023-12-28 19:30:58.518023143 +0800 ++++ b/Sources/FuzzilliCli/Profiles/Profile.swift 2023-12-28 19:27:14.554732995 +0800 +@@ -49,4 +49,5 @@ + "duktape": duktapeProfile, + "jerryscript": jerryscriptProfile, + "xs": xsProfile, ++ "es2abc": es2abcProfile, + ] diff --git a/fuzzilli/run_fuzzy.py b/fuzzilli/run_fuzzy.py new file mode 100644 index 0000000000..39b3a23169 --- /dev/null +++ b/fuzzilli/run_fuzzy.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Copyright (c) 2023 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Description: Use ark to execute fuzzilli test suite +""" + +import argparse +import os +import sys +import subprocess +import tarfile + +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +from test262.utils import git_clone, git_checkout, git_apply, mkdir +from test262.config import CODE_ROOT +from config import FUZZY_DIR, FUZZY_GIT_URL, FUZZY_GIT_HASH, FUZZY_DIR_NAME, FUZZILLI_PATCH_DIR_NAME, \ + FUZZILLI_OUTPUT_DIR_NAME, SWIFT_DOWNLOAD_URL + + +def run_command(cmd, shell_flag=False, timeout=60000): + proc = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + encoding="utf-8", + universal_newlines=True, + shell=shell_flag + ) + out, error = proc.communicate(timeout=timeout) + ret_code = proc.returncode + return ret_code, out, error + + +class TestPrepare: + @staticmethod + def prepare_fuzzilli_code(): + if not os.path.isdir(os.path.join(FUZZY_DIR, '.git')): + git_clone(FUZZY_GIT_URL, FUZZY_DIR) + git_checkout(FUZZY_GIT_HASH, FUZZY_DIR) + current_dir = os.getcwd() + fuzzilli_patch_path = os.path.join(current_dir, FUZZY_DIR_NAME, FUZZILLI_PATCH_DIR_NAME, 'fuzzilli.patch') + build_gn_patch_path = os.path.join(current_dir, FUZZY_DIR_NAME, FUZZILLI_PATCH_DIR_NAME, 'build_gn.patch') + if os.path.exists(fuzzilli_patch_path) and os.path.isfile(fuzzilli_patch_path): + git_apply(fuzzilli_patch_path, FUZZY_DIR) + + if os.path.exists(build_gn_patch_path) and os.path.isfile(build_gn_patch_path): + git_apply(build_gn_patch_path, current_dir) + + @staticmethod + def get_sysctl_config(): + cmd = ['sysctl', '-a', '|grep', 'kernel.core_pattern'] + ret, output, error = run_command(cmd) + if not ret: + lines = output.split('\n') + config = {} + for line in lines: + if line.strip() != '': + key, value = line.split(' = ') + config[key.strip()] = value.strip() + return config + + def check_bin_false(self): + config = self.get_sysctl_config() + if config: + kcp_val = config.get('kernel.core_pattern') + return kcp_val == '|/bin/false' + + def init_kernel_core_pattern(self): + is_bin_false = self.check_bin_false() + if not is_bin_false: + cmd = ['sysctl', '-w', 'kernel.core_pattern=|/bin/false'] + ret, _, error = run_command(cmd) + if ret: + raise Exception(f'Set kernel.core_pattern Error: {error}') + return 0 + + @staticmethod + def fuzzy_compiler(profile='es2abc', storage_path=FUZZILLI_OUTPUT_DIR_NAME): + _output_dir = os.path.join(FUZZY_DIR, storage_path) + if not os.path.exists(_output_dir): + mkdir(_output_dir) + try: + swift_tool = check_swift() + except Exception: + swift_tool = prepare_swift() + + # change to child dir + os.chdir(FUZZY_DIR) + # where es2abc path + _DEFAULT_ARK_DIR = f"{CODE_ROOT}/out/rk3568/clang_x64/arkcompiler/ets_frontend" + ejs_shell = os.path.join(_DEFAULT_ARK_DIR, "arkfuzzer") + cmd = [swift_tool, 'run', '-c', 'release', 'FuzzilliCli', f'--profile={profile}', + f'--storagePath={_output_dir}', ejs_shell] + ret, _, error = run_command(cmd) + if ret: + raise Exception(f'fuzzy compiler error: {error}') + return 0 + + @staticmethod + def arkfuzzer_compiler(): + _compiler_dir = f"{CODE_ROOT}" + os.chdir(_compiler_dir) + cmd = ['./build.sh', '--product-name', 'rk3568', '--build-target', 'ark_js_host_linux_tools_packages', + '--build-target', 'ets_frontend_build', f'--no-prebuilt-sdk'] + print('compilering arkfuzzer. Please be patient and wait') + ret, _, error = run_command(cmd) + if ret: + raise Exception(f'Fuzzilli compiler failed:{error}') + print('arkfuzzer compiler done!') + # Return to the original directory + _original_directory = f"{CODE_ROOT}/arkcompiler/ets_frontend" + os.chdir(_original_directory) + return 0 + + def prepare_fuzzy_test(self): + self.prepare_fuzzilli_code() + self.init_kernel_core_pattern() + # compile arkfuzzer + self.arkfuzzer_compiler() + self.fuzzy_compiler() + + def run(self): + self.prepare_fuzzy_test() + + +def prepare_swift(): + print('Start downloading swift……') + swift_path = os.path.join(FUZZY_DIR_NAME, 'swift.tar.gz') + _cmd = ['wget', '-O', swift_path, SWIFT_DOWNLOAD_URL] + ret, output, error = run_command(_cmd) + if ret: + raise Exception(f'Download swift error: {error}') + print('Downloading swift finished.') + with tarfile.open(swift_path, 'r:gz') as tar: + tar.extractall(FUZZY_DIR_NAME) + + current_dir = os.getcwd() + swift_path = os.path.join(current_dir, FUZZY_DIR_NAME, 'swift-5.9.2-RELEASE-ubuntu18.04', 'usr', 'bin', 'swift') + try: + check_swift(swift_path) + except Exception as e: + raise Exception(str(e)) + return swift_path + + +def check_swift(swift_path='swift'): + version_cmd = [swift_path, '--version'] + try: + ret, output, error = run_command(version_cmd) + except FileNotFoundError: + raise Exception('Swift not found.') + if ret: + raise Exception('Swift not found.') + print(output) + return swift_path + + +def main(): + test_prepare = TestPrepare() + test_prepare.run() + + +if __name__ == "__main__": + sys.exit(main()) -- Gitee