diff --git a/.gitmodules b/.gitmodules index 5b761d3..82926c7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,7 @@ [submodule "UniTSyn"] path = UniTSyn url = https://github.com/SecurityLab-UCD/UniTSyn.git +[submodule "fuzz/oss-fuzz"] + path = fuzz/oss-fuzz + url = https://github.com/joyguoguo/oss-fuzz.git + branch = main diff --git a/valid_projects.txt b/data/valid_projects.txt similarity index 100% rename from valid_projects.txt rename to data/valid_projects.txt diff --git a/fuzz/build_oss_fuzz.py b/fuzz/build_oss_fuzz.py new file mode 100644 index 0000000..fdd894e --- /dev/null +++ b/fuzz/build_oss_fuzz.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +build_oss_fuzz.py + +Parallel build of OSS-Fuzz projects (Docker images and Fuzzer compilation). +Uses multiprocessing.Pool to distribute projects across multiple CPU cores for concurrent processing. + +Usage: python3 build_oss_fuzz.py [project_list_file] [--sanitizer type] [--workers N] +Example: python3 fuzz/build_oss_fuzz.py data/valid_projects.txt \ + --sanitizer address \ + --workers 8 +""" + +import os +import sys +import subprocess +import argparse +from datetime import datetime +from pathlib import Path +from typing import List, Optional, Tuple +from multiprocessing import Pool, cpu_count + +# --- Global configuration --- +HOME_DIR = Path.home() +OSS_FUZZ_DIR = HOME_DIR / "FuzzAug" / "fuzz" / "oss-fuzz" +LOG_DIR = OSS_FUZZ_DIR / "build_logs" + +def setup_logging(project_name: str) -> Path: + """Create a timestamped log file for a single project""" + LOG_DIR.mkdir(parents=True, exist_ok=True) + timestamp = datetime.now().strftime("%Y%m%d%H%M%S") + return LOG_DIR / f"build_{project_name}_{timestamp}.log" + +def log_and_print(message: str, log_file: Path, to_stdout: bool = True): + """Write message to log and print to console""" + if to_stdout: + print(f"[PID:{os.getpid()}] {message}") + with open(log_file, "a", encoding="utf-8") as f: + f.write(f"{datetime.now().isoformat()} {message}\n") + +def run_command( + cmd: str, + log_msg: str, + log_file: Path, + allowed_exit_codes: Optional[List[int]] = None +) -> bool: + """Execute a shell command and stream output to log in real-time""" + allowed_exit_codes = allowed_exit_codes or [] + log_and_print(f"▶️ {log_msg}...", log_file, to_stdout=False) + log_and_print(f" $ {cmd}", log_file, to_stdout=False) + + try: + process = subprocess.Popen( + f"yes | {cmd}", # Auto-confirm all prompts + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + encoding="utf-8", + errors="replace" + ) + with open(log_file, "a", encoding="utf-8") as f: + if process.stdout is not None: + for line in iter(process.stdout.readline, ""): + f.write(line) + else: + log_and_print("⚠️ Warning: process.stdout is None", log_file) + process.wait() + exit_code = process.returncode + if exit_code in [0, *allowed_exit_codes]: + log_and_print(f"✅ Command completed successfully", log_file, to_stdout=False) + return True + log_and_print(f"❌ Command failed (exit code: {exit_code})", log_file) + return False + except Exception as e: + log_and_print(f"💥 Execution exception: {e}", log_file) + return False + +def build_project(project_name: str, sanitizer: str) -> Tuple[bool, str]: + """Build workflow for a single project""" + log_file = setup_logging(project_name) + os.chdir(OSS_FUZZ_DIR) + + log_and_print("="*60, log_file) + log_and_print(f"🔨 Starting build for project: {project_name}", log_file) + log_and_print(f"📝 Log path: {log_file}", log_file) + log_and_print("="*60, log_file) + + # 1. Build Docker image + if not run_command( + f"python3 infra/helper.py build_image {project_name}", + "Step 1/2: Building Docker image", + log_file + ): + return (False, project_name) + + # 2. Compile Fuzzers + if not run_command( + f"python3 infra/helper.py build_fuzzers --sanitizer {sanitizer} {project_name}", + f"Step 2/2: Compiling Fuzzers (sanitizer={sanitizer})", + log_file + ): + return (False, project_name) + + log_and_print(f"✅ Project {project_name} build completed", log_file) + return (True, project_name) + +def main(): + parser = argparse.ArgumentParser(description="OSS-Fuzz Parallel Build Tool") + parser.add_argument("project_list", help="Project list file path") + parser.add_argument("--sanitizer", default="address", choices=["address", "memory", "undefined"]) + parser.add_argument("--workers", type=int, default=cpu_count()) + args = parser.parse_args() + + # Read project list + try: + with open(args.project_list, "r") as f: + projects = [line.strip() for line in f if line.strip()] + except Exception as e: + print(f"❌ Failed to read project list: {e}") + sys.exit(1) + + # Parallel build + with Pool(args.workers) as pool: + results = pool.starmap(build_project, [(p, args.sanitizer) for p in projects]) + + # Output results + failed = [p for success, p in results if not success] + print(f"\n📊 Build completed: Success {len(projects)-len(failed)}/{len(projects)}") + if failed: + print("❌ Failed projects: " + ", ".join(failed)) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/fuzz/oss-fuzz b/fuzz/oss-fuzz new file mode 160000 index 0000000..f73b405 --- /dev/null +++ b/fuzz/oss-fuzz @@ -0,0 +1 @@ +Subproject commit f73b405d84e886bac90f8b15200230f08a2709c9 diff --git a/fuzz/run_fuzz_target.py b/fuzz/run_fuzz_target.py new file mode 100644 index 0000000..4a9f15a --- /dev/null +++ b/fuzz/run_fuzz_target.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +run_fuzz_target.py + +Run OSS-Fuzz test targets in parallel. +Uses multiprocessing.Pool to distribute tasks to multiple CPU cores. + +Usage: python3 run_fuzz_target.py [project_list_file] [--timeout seconds] [--workers N] +Example: python3 fuzz/run_fuzz_target.py data/valid_projects.txt --timeout 60 --workers 4 +""" + +import os +import sys +import subprocess +import argparse +from datetime import datetime +from pathlib import Path +from typing import List, Optional, Tuple +from multiprocessing import Pool, cpu_count + +# --- Global configuration --- +HOME_DIR = Path.home() +OSS_FUZZ_DIR = HOME_DIR / "FuzzAug" / "fuzz" / "oss-fuzz" +LOG_DIR = OSS_FUZZ_DIR / "run_logs" + +def setup_logging(project_name: str) -> Path: + """Create a timestamped run log""" + LOG_DIR.mkdir(parents=True, exist_ok=True) + timestamp = datetime.now().strftime("%Y%m%d%H%M%S") + return LOG_DIR / f"run_{project_name}_{timestamp}.log" + +def log_and_print(message: str, log_file: Path, to_stdout: bool = True): + """Log and console output""" + if to_stdout: + print(f"[PID:{os.getpid()}] {message}") + with open(log_file, "a", encoding="utf-8") as f: + f.write(f"{datetime.now().isoformat()} {message}\n") + +def run_command( + cmd: str, + log_msg: str, + log_file: Path, + allowed_exit_codes: Optional[List[int]] = None +) -> bool: + """Execute command and log output in real-time""" + allowed_exit_codes = allowed_exit_codes or [] + log_and_print(f"▶️ {log_msg}...", log_file, to_stdout=False) + log_and_print(f" $ {cmd}", log_file, to_stdout=False) + + try: + process = subprocess.Popen( + cmd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + encoding="utf-8", + errors="replace" + ) + with open(log_file, "a", encoding="utf-8") as f: + if process.stdout is not None: + for line in iter(process.stdout.readline, ""): + f.write(line) + else: + log_and_print("⚠️ Warning: process.stdout is None", log_file) + process.wait() + return process.returncode in [0, *allowed_exit_codes] + except Exception as e: + log_and_print(f"💥 Execution exception: {e}", log_file) + return False + +def discover_targets(project_name: str) -> List[str]: + """Discover available Fuzz targets""" + out_dir = OSS_FUZZ_DIR / "build" / "out" / project_name + targets = [] + if out_dir.exists(): + for f in out_dir.iterdir(): + if f.is_file() and f.name.startswith("fuzz_") and os.access(f, os.X_OK): + targets.append(f.name) + return targets + +def run_project(project_name: str, timeout: int) -> Tuple[bool, str]: + """Testing workflow for a single project""" + log_file = setup_logging(project_name) + os.chdir(OSS_FUZZ_DIR) + + log_and_print("="*60, log_file) + log_and_print(f"🚀 Starting testing for project: {project_name}", log_file) + log_and_print(f"📝 Log path: {log_file}", log_file) + log_and_print("="*60, log_file) + + # 1. Discover test targets + targets = discover_targets(project_name) + if not targets: + log_and_print("⚠️ No test targets found", log_file) + return (False, project_name) + log_and_print(f"🔍 Discovered {len(targets)} test targets", log_file) + + # 2. Run all targets + all_success = True + for i, target in enumerate(targets, 1): + cmd = f"python3 infra/helper.py run_fuzzer {project_name} {target} -- -max_total_time={timeout}" + success = run_command( + cmd, + f"Running target [{i}/{len(targets)}] {target} (timeout={timeout}s)", + log_file, + allowed_exit_codes=[1, 124] # Allow timeout exit codes + ) + all_success &= success + + # 3. Generate report (placeholder) + log_and_print("📊 Coverage report generation (not implemented in current version)", log_file) + return (all_success, project_name) + +def main(): + parser = argparse.ArgumentParser(description="OSS-Fuzz Parallel Testing Tool") + parser.add_argument("project_list", help="Project list file path") + parser.add_argument("--timeout", type=int, default=60, help="Timeout per target test (seconds)") + parser.add_argument("--workers", type=int, default=cpu_count()) + args = parser.parse_args() + + # Read project list + try: + with open(args.project_list) as f: + projects = [line.strip() for line in f if line.strip()] + except Exception as e: + print(f"❌ Failed to read project list: {e}") + sys.exit(1) + + # Parallel execution + with Pool(args.workers) as pool: + results = pool.starmap(run_project, [(p, args.timeout) for p in projects]) + + # Output results + failed = [p for success, p in results if not success] + print(f"\n📊 Testing completed: Success {len(projects)-len(failed)}/{len(projects)}") + if failed: + print("❌ Failed projects: " + ", ".join(failed)) + +if __name__ == "__main__": + main() diff --git a/script_fuzz_py_batch_final.sh b/script_fuzz_py_batch_final.sh deleted file mode 100644 index 1d7d9af..0000000 --- a/script_fuzz_py_batch_final.sh +++ /dev/null @@ -1,201 +0,0 @@ -#!/bin/bash -# script_fuzz_py_batch_final.sh -# 批量执行OSS-Fuzz本地测试全流程:从文件读取项目列表,依次为每个项目自动发现目标 -> 构建镜像 -> 编译fuzzer -> 运行测试 -> 生成覆盖率报告(暂无)) -# 用法:./script_fuzz_py_batch_final.sh [项目列表文件] [sanitizer类型] -# 示例: ./script_fuzz_py_batch_final.sh valid_projects.txt address - -# --- 全局配置 --- -PROJECT_LIST_FILE="${1:-valid_projects.txt}" # 默认项目列表文件 -SANITIZER="${2:-address}" # 默认检测器类型 -OSS_FUZZ_DIR="$HOME/oss-fuzz-py/oss-fuzz" # OSS-Fuzz目录 -LOG_DIR="$OSS_FUZZ_DIR/script_lz4_batch_logs" # 所有项目的总日志目录 -FAILED_PROJECTS=() # 存储失败项目列表 - -# --- 环境检查 --- -check_environment() { - if [ ! -d "$OSS_FUZZ_DIR" ]; then - echo "❌ 错误: OSS-Fuzz 目录 '$OSS_FUZZ_DIR' 不存在!" - return 1 - fi - if [ ! -f "$PROJECT_LIST_FILE" ]; then - echo "❌ 错误: 项目列表文件 '$PROJECT_LIST_FILE' 不存在!" - return 1 - fi - mkdir -p "$LOG_DIR" - chmod 777 "$LOG_DIR" 2>/dev/null || true - cd "$OSS_FUZZ_DIR" || return 1 - echo "✅ 环境检查通过。OSS-Fuzz 目录: $OSS_FUZZ_DIR" -} - -# --- 带日志记录的命令执行 --- -run_command() { - local cmd="$1" - local log_msg="$2" - local log_file="$3" # 日志文件作为参数传入 - local allowed_exit="${4:-}" - - echo "▶️ $log_msg..." | tee -a "$log_file" - set +e - { yes | eval "$cmd" ; } 2>&1 | tee -a "$log_file" - local exit_code=${PIPESTATUS[0]} - set -e - - if [[ -n "$allowed_exit" && ",$allowed_exit," =~ ",$exit_code," ]]; then - echo "ℹ️ 命令以预期状态退出: $exit_code" | tee -a "$log_file" - return 0 - elif [ $exit_code -ne 0 ]; then - echo "❌ 命令执行失败: $cmd (退出码: $exit_code)" | tee -a "$log_file" - return 1 # 返回错误而不是退出脚本 - fi -} - -# --- 自动发现 Fuzz 目标 --- -discover_fuzz_targets() { - local project_name="$1" - local project_dir="$OSS_FUZZ_DIR/build/out/$project_name" - local project_src="$OSS_FUZZ_DIR/projects/$project_name" - local targets=() - - if [ -d "$project_dir" ]; then - while IFS= read -r -d $'\0' file; do - filename=$(basename "$file") - if [[ -x "$file" && "$filename" =~ ^fuzz_ && ! "$file" =~ \..*$ ]]; then - targets+=("$filename") - fi - done < <(find "$project_dir" -maxdepth 1 -type f -print0) - fi - - if [ ${#targets[@]} -eq 0 ] && [ -d "$project_src" ]; then - while IFS= read -r -d $'\0' file; do - if grep -q "atheris.Setup" "$file"; then - targets+=("$(basename "${file%.*}")") - fi - done < <(find "$project_src" -name 'fuzz_*.py' -print0) - fi - - echo "${targets[@]}" -} - -# --- 单个项目的完整处理流程 --- -process_project() { - local project_name="$1" - local log_file="$LOG_DIR/oss_fuzz_${project_name}_$(date +%Y%m%d%H%M%S).log" - local project_failed=0 - - echo "============================================================" | tee -a "$log_file" - echo "🚀 开始处理项目: $project_name" | tee -a "$log_file" - echo "📝 日志文件: $log_file" | tee -a "$log_file" - echo "============================================================" | tee -a "$log_file" - - #1. 构建Docker镜像 - if ! run_command \ - "python3 infra/helper.py build_image $project_name" \ - "步骤1/5: 构建 $project_name 的Docker镜像" \ - "$log_file"; then - echo "❌ 项目 $project_name 构建镜像失败,跳过后续步骤" | tee -a "$log_file" - project_failed=1 - fi - - # 2. 编译带检测器的fuzzer (仅在构建镜像成功后执行) - if [ $project_failed -eq 0 ]; then - if ! run_command \ - "python3 infra/helper.py build_fuzzers --sanitizer $SANITIZER $project_name" \ - "步骤2/5: 编译 $project_name 的fuzzer (sanitizer=$SANITIZER)" \ - "$log_file"; then - echo "❌ 项目 $project_name 编译fuzzer失败,跳过后续步骤" | tee -a "$log_file" - project_failed=1 - fi - fi - - # 3. 自动发现目标 (仅在编译成功后执行) - if [ $project_failed -eq 0 ]; then - echo "🔍 正在为 $project_name 自动发现fuzz目标..." | tee -a "$log_file" - FUZZ_TARGETS=($(discover_fuzz_targets "$project_name")) - - if [ ${#FUZZ_TARGETS[@]} -eq 0 ]; then - echo "⚠️ 警告: 项目 $project_name 未找到任何fuzz目标!跳过运行步骤。" | tee -a "$log_file" - else - echo "✅ 发现目标: ${FUZZ_TARGETS[*]}" | tee -a "$log_file" - - # 4. 遍历运行所有目标 默认测试60秒 - for target in "${FUZZ_TARGETS[@]}"; do - if ! run_command \ - "python3 infra/helper.py run_fuzzer $project_name $target -- -max_total_time=60" \ - "步骤3/5: 运行目标 [$target] (60秒超时)" \ - "$log_file" \ - "124,1"; then # 允许超时(124)和发现崩溃(1) - echo "⚠️ 警告: 目标 [$target] 运行失败,继续下一个目标" | tee -a "$log_file" - fi - done - fi - fi - - # 5. 生成覆盖率报告 (已注释掉,与原脚本保持一致) - # [保留原有注释的覆盖率代码] - - if [ $project_failed -eq 0 ]; then - echo "✅ 项目 $project_name 处理完成!" | tee -a "$log_file" - - else - echo "❌ 项目 $project_name 处理失败!" | tee -a "$log_file" - - fi - - echo "------------------------------------------------------------" - return $project_failed -} - -# --- 主流程 --- -main() { -if ! check_environment; then - echo "❌ 环境检查失败,脚本终止" - exit 1 - fi - - # 新增:读取项目列表到数组(过滤空行和注释行) - local PROJECTS=() - while IFS= read -r line || [[ -n "$line" ]]; do - if [[ -z "$line" || "$line" =~ ^# ]]; then - continue - fi - PROJECTS+=("$line") - done < "$PROJECT_LIST_FILE" - - # 项目总数从数组长度获取(原逻辑从文件行数获取) - local total_projects=${#PROJECTS[@]} - local current_project_num=0 - local success_count=0 - local fail_count=0 - - # 新增:遍历数组处理项目(替代原while读取文件的循环) - for project_name in "${PROJECTS[@]}"; do - - current_project_num=$((current_project_num + 1)) - echo ">>> [ $current_project_num / $total_projects ] 开始处理项目: $project_name <<<" - - if process_project "$project_name"; then - echo "✅ [$current_project_num/$total_projects] 项目 $project_name 成功完成" - ( success_count=$[ $success_count + 1 ]) - else - echo "❌ [$current_project_num/$total_projects] 项目 $project_name 处理失败" - FAILED_PROJECTS+=("$project_name") - ( success_count=$[ $success_count + 1 ]) - fi - - done - - echo "============================================================" - echo "🎉 批量处理完成!" - echo "📊 总计: $total_projects 个项目" - echo "✅ 成功: $success_count" - echo "❌ 失败: $fail_count" - - if [ ${#FAILED_PROJECTS[@]} -gt 0 ]; then - echo "📛 失败项目列表:" - printf ' • %s\n' "${FAILED_PROJECTS[@]}" - echo "💡 提示: 可以重新运行失败项目,检查日志获取详细信息" - echo " 日志目录: $LOG_DIR" - fi -} - -main "$@" \ No newline at end of file diff --git a/script_fuzz_py_final.sh b/script_fuzz_py_final.sh deleted file mode 100644 index c2bf00a..0000000 --- a/script_fuzz_py_final.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/bin/bash -# script_fuzz_py_final.sh -# 执行OSS-Fuzz本地测试全流程:自动发现目标 -> 构建镜像 -> 编译fuzzer -> 运行测试 -> 生成覆盖率报告 -# 用法:script_fuzz_py_final.sh <项目名> [sanitizer类型] - -set -e # 遇到错误立即退出 - -PROJECT_NAME="${1:-abseil-py}" # 默认项目名 -SANITIZER="${2:-address}" # 默认检测器类型 -OSS_FUZZ_DIR="$HOME/oss-fuzz-py/oss-fuzz" # OSS-Fuzz目录 -LOG_DIR="$OSS_FUZZ_DIR/script_lz4_logs" -LOG_FILE="$LOG_DIR/oss_fuzz_${PROJECT_NAME}_$(date +%Y%m%d%H%M%S).log" -# 验证目录有效性 -check_environment() { - if [ ! -d "$OSS_FUZZ_DIR" ]; then - echo "❌ 错误: $OSS_FUZZ_DIR 目录不存在!" - exit 1 - fi - mkdir -p "$LOG_DIR" # 关键修复:创建日志目录 - chmod 777 "$LOG_DIR" 2>/dev/null || true # 宽松权限设置 - cd "$OSS_FUZZ_DIR" || exit 1 -} - -# 带日志记录的命令执行(支持允许的退出码) -run_command() { - local cmd="$1" - local log_msg="$2" - local allowed_exit="${3:-}" # 可选:允许的退出码(逗号分隔) - - echo "▶️ $log_msg..." | tee -a "$LOG_FILE" - set +e # 临时禁用错误退出 - eval "$cmd" 2>&1 | tee -a "$LOG_FILE" - local exit_code=${PIPESTATUS[0]} - set -e # 重新启用错误退出 - - # 检查退出码是否被允许 - if [[ -n "$allowed_exit" && ",$allowed_exit," =~ ",$exit_code," ]]; then - echo "ℹ️ 命令以预期状态退出: $exit_code" | tee -a "$LOG_FILE" - return 0 - elif [ $exit_code -ne 0 ]; then - echo "❌ 命令执行失败: $cmd (退出码: $exit_code)" | tee -a "$LOG_FILE" - exit 1 - fi -} - -# 自动发现fuzz目标 -discover_fuzz_targets() { - local project_dir="$OSS_FUZZ_DIR/build/out/$PROJECT_NAME" - local project_src="$OSS_FUZZ_DIR/projects/$PROJECT_NAME" - local targets=() - - # 编译目录扫描:仅匹配"fuzz_"开头的可执行文件 - if [ -d "$project_dir" ]; then - while IFS= read -r -d $'\0' file; do - filename=$(basename "$file") - if [[ -x "$file" && "$filename" =~ ^fuzz_ && ! "$file" =~ \..*$ ]]; then - targets+=("$filename") - fi - done < <(find "$project_dir" -maxdepth 1 -type f -print0) - fi - - # 源码目录扫描:仅匹配"fuzz_*.py"且含Atheris标识 - if [ ${#targets[@]} -eq 0 ] && [ -d "$project_src" ]; then - while IFS= read -r -d $'\0' file; do - if grep -q "atheris.Setup" "$file"; then - targets+=("$(basename "${file%.*}")") - fi - done < <(find "$project_src" -name 'fuzz_*.py' -print0) - fi - - echo "${targets[@]}" -} - -# 主流程 -main() { - check_environment - echo "==============================" - echo "🚀 开始OSS-Fuzz测试 - 项目: $PROJECT_NAME" - echo "📝 日志文件: $LOG_FILE" - echo "==============================" - - #1. 构建Docker镜像 - run_command \ - "python3 infra/helper.py build_image $PROJECT_NAME" \ - "步骤1/5: 构建Docker镜像" - - # 2. 编译带检测器的fuzzer - run_command \ - "python3 infra/helper.py build_fuzzers --sanitizer $SANITIZER $PROJECT_NAME" \ - "步骤2/5: 编译fuzzer (sanitizer=$SANITIZER)" - - # 3. 自动发现目标 - echo "🔍 自动发现fuzz目标..." - FUZZ_TARGETS=($(discover_fuzz_targets)) - - if [ ${#FUZZ_TARGETS[@]} -eq 0 ]; then - echo "❌ 未找到任何fuzz目标!检查项目配置" | tee -a "$LOG_FILE" - exit 1 - fi - - echo "✅ 发现目标: ${FUZZ_TARGETS[*]}" | tee -a "$LOG_FILE" - - # 4. 遍历运行所有目标 - for target in "${FUZZ_TARGETS[@]}"; do - run_command \ - "python3 infra/helper.py run_fuzzer $PROJECT_NAME $target -- -max_total_time=180" \ - "步骤3/5: 运行目标 [$target] (120秒超时)" \ - "124,1" # 允许超时(124)和发现崩溃(1) -done - - # 5. 生成覆盖率报告 - # run_command \ - # "python3 infra/helper.py build_fuzzers --sanitizer coverage $PROJECT_NAME" \ - # "步骤4/5: 编译覆盖率版本" - - # run_command \ - # "python3 infra/helper.py coverage --no-serve $PROJECT_NAME" \ - # "步骤5/5: 生成覆盖率报告" - - echo "✅ 所有步骤完成!结果查看:" - echo "🔍 测试日志: $LOG_FILE" - echo "📊 覆盖率报告(暂无): $OSS_FUZZ_DIR/build/out/$PROJECT_NAME/report/coverage/index.html" - echo "💥 崩溃报告: $OSS_FUZZ_DIR/build/out/$PROJECT_NAME/crashes/" -} - -main "$@" \ No newline at end of file