/*
   american fuzzy lop++ - fuzzer code
   --------------------------------

   Originally written by Michal Zalewski

   Now maintained by Marc Heuse <mh@mh-sec.de>,
                     Dominik Meier <mail@dmnk.co>,
                     Andrea Fioraldi <andreafioraldi@gmail.com>, and
                     Heiko Eissfeldt <heiko.eissfeldt@hexco.de>

   Copyright 2016, 2017 Google Inc. All rights reserved.
   Copyright 2019-2024 AFLplusplus Project. All rights reserved.

   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:

     https://www.apache.org/licenses/LICENSE-2.0

   This is the real deal: the program takes an instrumented binary and
   attempts a variety of basic fuzzing tricks, paying close attention to
   how they affect the execution path.

 */
//慕容承霖提交
//引入了 AFL++ 的核心头文件、CMPLog 相关头文件、通用函数头文件等。
//根据编译选项，可能还会包含其他系统头文件，如内存映射、文件操作等。

#include "afl-fuzz.h"
#include "cmplog.h"
#include "common.h"
#include <limits.h>
#include <stdlib.h>
#ifndef USEMMAP
  #include <sys/mman.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <sys/ipc.h>
  #include <sys/shm.h>
#endif
#ifdef HAVE_ZLIB

  #define ck_gzread(fd, buf, len, fn)                            \
    do {                                                         \
                                                                 \
      s32 _len = (s32)(len);                                     \
      s32 _res = gzread(fd, buf, _len);                          \
      if (_res != _len) RPFATAL(_res, "Short read from %s", fn); \
                                                                 \
    } while (0)

  #define ck_gzwrite(fd, buf, len, fn)                                    \
    do {                                                                  \
                                                                          \
      if (len <= 0) break;                                                \
      s32 _written = 0, _off = 0, _len = (s32)(len);                      \
                                                                          \
      do {                                                                \
                                                                          \
        s32 _res = gzwrite(fd, (buf) + _off, _len);                       \
        if (_res != _len && (_res > 0 && _written + _res != _len)) {      \
                                                                          \
          if (_res > 0) {                                                 \
                                                                          \
            _written += _res;                                             \
            _len -= _res;                                                 \
            _off += _res;                                                 \
                                                                          \
          } else {                                                        \
                                                                          \
            RPFATAL(_res, "Short write to %s (%d of %d bytes)", fn, _res, \
                    _len);                                                \
                                                                          \
          }                                                               \
                                                                          \
        } else {                                                          \
                                                                          \
          break;                                                          \
                                                                          \
        }                                                                 \
                                                                          \
      } while (1);                                                        \
                                                                          \
                                                                          \
                                                                          \
    } while (0)
//定义了与 zlib 相关的宏，用于处理压缩文件的读写操作。
//对于苹果系统，引入了特定的头文件以支持线程优先级设置。
//如果启用了性能分析，则声明了一个外部变量 time_spent_working 用于记录工作时间
  #include <zlib.h>
  #define ZLIBOPEN gzopen
  #define ZLIBREAD ck_gzread
  #define NZLIBREAD gzread
  #define ZLIBWRITE ck_gzwrite
  #define ZLIBCLOSE gzclose
  #define ZLIB_EXTRA "9"
#else
  #define ZLIBOPEN open
  #define NZLIBREAD read
  #define ZLIBREAD ck_read
  #define ZLIBWRITE ck_write
  #define ZLIBCLOSE close
#endif

#ifdef __APPLE__
  #include <sys/qos.h>
  #include <pthread/qos.h>
#endif

#ifdef PROFILING
extern u64 time_spent_working;
#endif
//程序退出时的清理函数
static void at_exit() {//at_exit 函数在 AFL++ 程序退出时被调用，用于清理资源和终止子进程
//首先尝试获取环境变量 __AFL_TARGET_PID2 和 __AFL_TARGET_PID1，这些变量存储了目标进程的 PID
  s32   i, pid1 = 0, pid2 = 0, pgrp = -1;
  char *list[4] = {SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, CMPLOG_SHM_ENV_VAR, NULL};
  char *ptr;
//如果找到有效的 PID，则获取其进程组 ID 并向进程组发送 SIGTERM 信号以终止整个进程组，
//然后单独向目标进程发送 SIGTERM 信号。
  ptr = getenv("__AFL_TARGET_PID2");
  if (ptr && *ptr && (pid2 = atoi(ptr)) > 0) {

    pgrp = getpgid(pid2);
    if (pgrp > 0) { killpg(pgrp, SIGTERM); }
    kill(pid2, SIGTERM);

  }

  ptr = getenv("__AFL_TARGET_PID1");
  if (ptr && *ptr && (pid1 = atoi(ptr)) > 0) {

    pgrp = getpgid(pid1);
    if (pgrp > 0) { killpg(pgrp, SIGTERM); }
    kill(pid1, SIGTERM);

  }
//尝试获取环境变量 CPU_AFFINITY_ENV_VAR，如果存在且非空，则删除该文件以解除 CPU 亲和性设置
  ptr = getenv(CPU_AFFINITY_ENV_VAR);
  if (ptr && *ptr) unlink(ptr);
//遍历 list 数组，获取每个环境变量的值，如果存在且非空，
//则根据编译选项使用不同的共享内存删除函数（shm_unlink 或 shmctl）来删除共享内存
  i = 0;
  while (list[i] != NULL) {

    ptr = getenv(list[i]);
    if (ptr && *ptr) {

#ifdef USEMMAP

      shm_unlink(ptr);

#else

      shmctl(atoi(ptr), IPC_RMID, NULL);

#endif

    }

    i++;

  }

  int kill_signal = SIGKILL;
  /* AFL_KILL_SIGNAL should already be a valid int at this point */
  if ((ptr = getenv("AFL_KILL_SIGNAL"))) { kill_signal = atoi(ptr); }

  if (pid1 > 0) {

    pgrp = getpgid(pid1);
    if (pgrp > 0) { killpg(pgrp, kill_signal); }
    kill(pid1, kill_signal);

  }

  if (pid2 > 0) {

    pgrp = getpgid(pid1);
    if (pgrp > 0) { killpg(pgrp, kill_signal); }
    kill(pid2, kill_signal);
//最后，获取环境变量 AFL_KILL_SIGNAL 的值作为要发送的信号类型（默认为 SIGKILL），
//然后再次检查 PID1 和 PID2，获取其进程组 ID 并向进程组发送相应的信号，单独向目标进程发送信号以确保其被终止
  }

}

/* Display usage hints. */
//主要为显示说明
static void usage(u8 *argv0, int more_help) {

  SAYF(
      "\n%s [ options ] -- /path/to/fuzzed_app [ ... ]\n\n"

      "Required parameters:\n"
      "  -i dir        - input directory with test cases (or '-' to resume, "
      "also see \n"
      "                  AFL_AUTORESUME)\n"
      "  -o dir        - output directory for fuzzer findings\n\n"
  //-i dir：指定输入目录，该目录包含用于模糊测试的测试用例。如果输入为 -，则表示恢复之前的模糊测试会话。
  //-o dir：指定输出目录，用于存储模糊测试过程中发现的结果。
      "Execution control settings:\n"
      "  -P strategy   - set fix mutation strategy: explore (focus on new "
      "coverage),\n"
      "                  exploit (focus on triggering crashes). You can also "
      "set a\n"
      "                  number of seconds after without any finds it switches "
      "to\n"
      "                  exploit mode, and back on new coverage (default: %u)\n"
      "  -p schedule   - power schedules compute a seed's performance score:\n"
      "                  explore(default), fast, exploit, seek, rare, mmopt, "
      "coe, lin\n"
      "                  quad -- see docs/FAQ.md for more information\n"
      "  -f file       - location read by the fuzzed program (default: stdin "
      "or @@)\n"
      "  -t msec       - timeout for each run (auto-scaled, default %u ms). "
      "Add a '+'\n"
      "                  to auto-calculate the timeout, the value being the "
      "maximum.\n"
      "  -m megs       - memory limit for child process (%u MB, 0 = no limit "
      "[default])\n"
//-P strategy：设置固定的变异策略。可以选择 explore（专注于发现新覆盖率）或 exploit（专注于触发崩溃）。还可以设置在没有发现新结果时自动切换到 exploit 模式的时间（以秒为单位），并在发现新覆盖率时切换回 explore 模式。
//-p schedule：设置功率调度策略，用于计算种子的性能得分。可选的策略包括 explore（默认）、fast、exploit、seek、rare、mmopt、coe、lin 和 quad。具体的策略选择和效果可以参考 AFL++ 的文档。
//-f file：指定被模糊测试程序读取的文件位置，默认为标准输入或 @@。
//-t msec：设置每次运行的超时时间（自动缩放，默认为指定的毫秒数）。可以在超时值后加上 +，表示自动计算超时时间，指定的值为最大值。
//-m megs：设置子进程的内存限制（以兆字节为单位，默认为 0，表示不限制）
#if defined(__linux__) && defined(__aarch64__)
      "  -A            - use binary-only instrumentation (ARM CoreSight mode)\n"
#endif
      "  -O            - use binary-only instrumentation (FRIDA mode)\n"
#if defined(__linux__)
      "  -Q            - use binary-only instrumentation (QEMU mode)\n"
      "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
      "  -W            - use qemu-based instrumentation with Wine (Wine mode)\n"
#endif
#if defined(__linux__)
      "  -X            - use VM fuzzing (NYX mode - standalone mode)\n"
      "  -Y            - use VM fuzzing (NYX mode - multiple instances mode)\n"
//-A：在 ARM 架构的 Linux 系统上，使用二进制插桩（ARM CoreSight 模式）。
//-O：使用 FRIDA 模式进行二进制插桩。
//-Q：在 Linux 系统上，使用 QEMU 模式进行二进制插桩。
//-U：在 Linux 系统上，使用基于 Unicorn 的插桩（Unicorn 模式）。
//-W：在 Linux 系统上，使用基于 QEMU 和 Wine 的插桩（Wine 模式）。
//-X 和 -Y：在 Linux 系统上，使用 VM 模糊测试（NYX 模式），分别支持独立模式和多实例模式。
#endif
      "\n"

      "Mutator settings:\n"
      "  -a type       - target input format, \"text\" or \"binary\" (default: "
      "generic)\n"
      "  -g minlength  - set min length of generated fuzz input (default: 1)\n"
      "  -G maxlength  - set max length of generated fuzz input (default: "
      "%lu)\n"
      "  -L minutes    - use MOpt(imize) mode and set the time limit for "
      "entering the\n"
      "                  pacemaker mode (minutes of no new finds). 0 = "
      "immediately,\n"
      "                  -1 = immediately and together with normal mutation.\n"
      "                  Note: this option is usually not very effective\n"
      "  -c program    - enable CmpLog by specifying a binary compiled for "
      "it.\n"
      "                  if using QEMU/FRIDA or the fuzzing target is "
      "compiled\n"
      "                  for CmpLog then use '-c 0'. To disable CMPLOG use '-c "
      "-'.\n"
      "  -l cmplog_opts - CmpLog configuration values (e.g. \"2ATR\"):\n"
      "                  1=small files, 2=larger files (default), 3=all "
      "files,\n"
      "                  A=arithmetic solving, T=transformational solving,\n"
      "                  X=extreme transform solving, R=random colorization "
      "bytes.\n\n"
      "Fuzzing behavior settings:\n"
      "  -Z            - sequential queue selection instead of weighted "
      "random\n"
      "  -N            - do not unlink the fuzzing input file (for devices "
      "etc.)\n"
      "  -n            - fuzz without instrumentation (non-instrumented mode)\n"
      "  -x dict_file  - fuzzer dictionary (see README.md, specify up to 4 "
      "times)\n\n"

      "Test settings:\n"
      "  -s seed       - use a fixed seed for the RNG\n"
      "  -V seconds    - fuzz for a specified time then terminate (fuzz time "
      "only!)\n"
      "  -E execs      - fuzz for an approx. no. of total executions then "
      "terminate\n"
      "                  Note: not precise and can have several more "
      "executions.\n\n"

      "Other stuff:\n"
      "  -M/-S id      - distributed mode (-M sets -Z and disables trimming)\n"
      "                  see docs/fuzzing_in_depth.md#c-using-multiple-cores\n"
      "                  for effective recommendations for parallel fuzzing.\n"
      "  -F path       - sync to a foreign fuzzer queue directory (requires "
      "-M, can\n"
      "                  be specified up to %u times)\n"
      "  -z            - skip the enhanced deterministic fuzzing\n"
      "                  (note that the old -d and -D flags are ignored.)\n"
      "  -T text       - text banner to show on the screen\n"
      "  -I command    - execute this command/script when a new crash is "
      "found\n"
      //"  -B bitmap.txt - mutate a specific test case, use the
      // out/default/fuzz_bitmap file\n"
      "  -C            - crash exploration mode (the peruvian rabbit thing)\n"
      "  -b cpu_id     - bind the fuzzing process to the specified CPU core "
      "(0-...)\n"
      "  -e ext        - file extension for the fuzz test input file (if "
      "needed)\n"
      "\n",
      argv0, STRATEGY_SWITCH_TIME, EXEC_TIMEOUT, MEM_LIMIT, MAX_FILE,
      FOREIGN_SYNCS_MAX);

  if (more_help > 1) {

#if defined USE_COLOR && !defined ALWAYS_COLORED
  #define DYN_COLOR \
    "AFL_NO_COLOR or AFL_NO_COLOUR: switch colored console output off\n"
    //定义了 USE_COLOR 但未定义 ALWAYS_COLORED，则定义 DYN_COLOR 宏，用于提示用户如何关闭控制台的颜色输出
#else
  #define DYN_COLOR
#endif
//如果定义了 AFL_PERSISTENT_RECORD，则定义 PERSISTENT_MSG 宏，用于提示用户 AFL_PERSISTENT_RECORD 环境变量的作用
#ifdef AFL_PERSISTENT_RECORD
  #define PERSISTENT_MSG                                                 \
    "AFL_PERSISTENT_RECORD: record the last X inputs to every crash in " \
    "out/crashes\n"
#else
  #define PERSISTENT_MSG
#endif

    SAYF(//用于输出详细的帮助信息，包括 AFL++ 使用的各种环境变量及其作用。
      "Environment variables used:\n"
      "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
      "ASAN_OPTIONS: custom settings for ASAN\n"
      "              (must contain abort_on_error=1 and symbolize=0)\n"
      "MSAN_OPTIONS: custom settings for MSAN\n"
      "              (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
      "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n"
      "AFL_BENCH_JUST_ONE: run the target just once\n"
      "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n"
      "AFL_CMPLOG_ONLY_NEW: do not run cmplog on initial testcases (good for resumes!)\n"
      "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n"
      "AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n"
      "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n"
      "AFL_CYCLE_SCHEDULES: after completing a cycle, switch to a different -p schedule\n"
      "AFL_DEBUG: extra debugging output for Python mode trimming\n"
      "AFL_DEBUG_CHILD: do not suppress stdout/stderr from target\n"
      "AFL_DISABLE_REDUNDANT: disable any queue item that is redundant\n"
      "AFL_DISABLE_TRIM: disable the trimming of test cases\n"
      "AFL_DUMB_FORKSRV: use fork server without feedback from target\n"
      "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n"
      "AFL_EXIT_ON_TIME: exit when no new coverage is found within the specified time\n"
      "AFL_EXIT_ON_SEED_ISSUES: exit on any kind of seed issues\n"
      "AFL_EXPAND_HAVOC_NOW: immediately enable expand havoc mode (default: after 60\n"
      "                      minutes and a cycle without finds)\n"
      "AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n"
      "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n"
      "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in ms)\n"
      "AFL_HANG_TMOUT: override timeout value (in milliseconds)\n"
      "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n"
      "AFL_IGNORE_PROBLEMS: do not abort fuzzing if an incorrect setup is detected\n"
      "AFL_IGNORE_PROBLEMS_COVERAGE: if set in addition to AFL_IGNORE_PROBLEMS - also\n"
      "                              ignore those libs for coverage\n"
      "AFL_IGNORE_SEED_PROBLEMS: skip over crashes and timeouts in the seeds instead of\n"
      "                          exiting\n"
      "AFL_IGNORE_TIMEOUTS: do not process or save any timeouts\n"
      "AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n"
      "AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n"
      "AFL_INPUT_LEN_MIN/AFL_INPUT_LEN_MAX: like -g/-G set min/max fuzz length produced\n"
      "AFL_PIZZA_MODE: 1 - enforce pizza mode, -1 - disable for April 1st,\n"
      "                0 (default) - activate on April 1st\n"
      "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc.\n"
      "                 (default: SIGKILL)\n"
      "AFL_FORK_SERVER_KILL_SIGNAL: Kill signal for the fork server on termination\n"
      "                             (default: SIGTERM). If unset and AFL_KILL_SIGNAL is\n"
      "                             set, that value will be used.\n"
      "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
      "              the target was compiled for\n"
      "AFL_MAX_DET_EXTRAS: if more entries are in the dictionary list than this value\n"
      "                    then they are randomly selected instead all of them being\n"
      "                    used. Defaults to 200.\n"
      "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n"
      "AFL_TRY_AFFINITY: try to bind to an unused core, but don't fail if unsuccessful\n"
      "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n"
      "AFL_NO_AUTODICT: do not load an offered auto dictionary compiled into a target\n"
      "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n"
      "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n"
      "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n"
      "AFL_NO_STARTUP_CALIBRATION: no initial seed calibration, start fuzzing at once\n"
      "AFL_NO_WARN_INSTABILITY: no warn about instability issues on startup calibration\n"
      "AFL_NO_UI: switch status screen off\n"
      "AFL_NYX_AUX_SIZE: size of the Nyx auxiliary buffer. Must be a multiple of 4096.\n"
      "                  Increase this value in case the crash reports are truncated.\n"
      "                  Default value is 4096.\n"
      "AFL_NYX_DISABLE_SNAPSHOT_MODE: disable snapshot mode (must be supported by the agent)\n"
      "AFL_NYX_LOG: output NYX hprintf messages to another file\n"
      "AFL_NYX_REUSE_SNAPSHOT: reuse an existing Nyx root snapshot\n"
      DYN_COLOR

      "AFL_PATH: path to AFL support binaries\n"
      "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n"
      "AFL_QUIET: suppress forkserver status messages\n"

      PERSISTENT_MSG

      "AFL_POST_PROCESS_KEEP_ORIGINAL: save the file as it was prior post-processing to\n"
      "                                the queue, but execute the post-processed one\n"
      "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
      "AFL_TARGET_ENV: pass extra environment variables to target\n"
      "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
      "AFL_SKIP_BIN_CHECK: skip afl compatibility checks, also disables auto map size\n"
      "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n"
      //"AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n"
      "AFL_STATSD: enables StatsD metrics collection\n"
      "AFL_STATSD_HOST: change default statsd host (default 127.0.0.1)\n"
      "AFL_STATSD_PORT: change default statsd port (default: 8125)\n"
      "AFL_STATSD_TAGS_FLAVOR: set statsd tags format (default: disable tags)\n"
      "                        suported formats: dogstatsd, librato, signalfx, influxdb\n"
      "AFL_NO_FASTRESUME: do not read or write a fast resume file\n"
      "AFL_NO_SYNC: disables all syncing\n"
      "AFL_SYNC_TIME: sync time between fuzzing instances (in minutes)\n"
      "AFL_FINAL_SYNC: sync a final time when exiting (will delay the exit!)\n"
      "AFL_NO_CRASH_README: do not create a README in the crashes directory\n"
      "AFL_TESTCACHE_SIZE: use a cache for testcases, improves performance (in MB)\n"
      "AFL_TMPDIR: directory to use for input file generation (ramdisk recommended)\n"
      "AFL_EARLY_FORKSERVER: force an early forkserver in an afl-clang-fast/\n"
      "                      afl-clang-lto/afl-gcc-fast target\n"
      "AFL_PERSISTENT: enforce persistent mode (if __AFL_LOOP is in a shared lib)\n"
      "AFL_DEFER_FORKSRV: enforced deferred forkserver (__AFL_INIT is in a shared lib)\n"
      "AFL_FUZZER_STATS_UPDATE_INTERVAL: interval to update fuzzer_stats file in\n"
      "                                  seconds (default: 60, minimum: 1)\n"
      "\n"
    );
  /*
  LD_BIND_LAZY：指示 AFL++ 不要为目标程序设置 LD_BIND_NOW 环境变量。
ASAN_OPTIONS 和 MSAN_OPTIONS：用于自定义 ASAN 和 MSAN 的设置，必须包含特定的选项以确保 AFL++ 正常工作。
AFL_AUTORESUME：如果输出目录已存在，则自动恢复模糊测试。
AFL_BENCH_JUST_ONE 和 AFL_BENCH_UNTIL_CRASH：用于性能测试，分别表示只运行目标程序一次和在找到第一个崩溃输入后退出。
AFL_CMPLOG_ONLY_NEW：在初始测试用例上不运行 CMPLog，适用于恢复模糊测试。
AFL_CRASH_EXITCODE：指定 AFL++ 应解释为崩溃的子进程退出代码。
AFL_CUSTOM_MUTATOR_LIBRARY 和 AFL_CUSTOM_MUTATOR_ONLY：用于自定义变异器库和仅使用自定义变异器。
AFL_CYCLE_SCHEDULES：在完成一个周期后切换到不同的功率调度策略。
AFL_DEBUG 和 AFL_DEBUG_CHILD：用于调试输出和不抑制目标程序的 stdout/stderr。
AFL_DISABLE_REDUNDANT 和 AFL_DISABLE_TRIM：禁用冗余队列项和测试用例的修剪。
AFL_DUMB_FORKSRV：使用没有目标反馈的 fork 服务器。
AFL_EXIT_WHEN_DONE 和 AFL_EXIT_ON_TIME：在所有输入运行完毕且没有新发现时退出，或在指定时间内没有发现新覆盖率时退出。
AFL_EXIT_ON_SEED_ISSUES：在种子问题时退出。
AFL_EXPAND_HAVOC_NOW：立即启用扩展的 Havoc 模式。
AFL_FAST_CAL：限制校准阶段为三个周期以加速。
AFL_FORCE_UI：强制显示状态屏幕（适用于虚拟控制台）。
AFL_FORKSRV_INIT_TMOUT：在启动时等待 fork 服务器的时间（以毫秒为单位）。
AFL_HANG_TMOUT：覆盖超时值（以毫秒为单位）。
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES：不警告关于核心转储处理器的问题。
AFL_IGNORE_PROBLEMS 和 AFL_IGNORE_PROBLEMS_COVERAGE：不因检测到不正确的设置而终止模糊测试，以及忽略相关库的覆盖率。
AFL_IGNORE_SEED_PROBLEMS 和 AFL_IGNORE_TIMEOUTS：在种子中跳过崩溃和超时，而不是退出。
AFL_IGNORE_UNKNOWN_ENVS：不警告未知的环境变量。
AFL_IMPORT_FIRST：首先同步并导入来自其他模糊测试实例的测试用例。
AFL_INPUT_LEN_MIN/AFL_INPUT_LEN_MAX：设置 AFL++ 产生的模糊长度的最小值和最大值。
AFL_PIZZA_MODE：控制 AFL++ 是否在 4 月 1 日启用“披萨模式”。
AFL_KILL_SIGNAL 和 AFL_FORK_SERVER_KILL_SIGNAL：指定在超时等情况下发送给子进程和 fork 服务器的信号 ID。
AFL_MAP_SIZE：目标程序的共享内存大小，必须大于或等于目标程序编译时的大小。
AFL_MAX_DET_EXTRAS：如果字典列表中的条目多于该值，则随机选择而不是使用所有条目。
AFL_NO_AFFINITY 和 AFL_TRY_AFFINITY：不检查未使用的 CPU 核心用于模糊测试，或尝试绑定到未使用的 CPU 核心但不失败。
AFL_NO_ARITH 和 AFL_NO_AUTODICT：在确定性阶段跳过算术变异和不加载目标程序中编译的自动字典。
AFL_NO_CPU_RED 和 AFL_NO_FORKSRV：避免显示非常高的 CPU 使用率的红色和通过 execve 运行目标程序而不是使用 fork 服务器。
AFL_NO_SNAPSHOT 和 AFL_NO_STARTUP_CALIBRATION：不使用快照功能和不进行初始种子校准。
AFL_NO_WARN_INSTABILITY 和 AFL_NO_UI：不在启动校准期间警告稳定性问题和关闭状态屏幕。
AFL_NYX_AUX_SIZE：Nyx 辅助缓冲区的大小，必须是 4096 的倍数。
AFL_NYX_DISABLE_SNAPSHOT_MODE 和 AFL_NYX_LOG：禁用快照模式和将 NYX hprintf 消息输出到另一个文件。
AFL_NYX_REUSE_SNAPSHOT：重用现有的 Nyx 根快照。
AFL_PATH：AFL 支持二进制文件的路径。
AFL_PYTHON_MODULE：使用指定的 Python 模块变异和修剪输入。
AFL_QUIET：抑制 fork 服务器状态消息。
AFL_POST_PROCESS_KEEP_ORIGINAL：保存后处理前的文件到队列中，但执行后处理后的文件。
AFL_PRELOAD：目标程序的 LD_PRELOAD/DYLD_INSERT_LIBRARIES 设置。
AFL_TARGET_ENV：传递额外的环境变量给目标程序。
AFL_SHUFFLE_QUEUE：在启动时随机重新排序输入队列。
AFL_SKIP_BIN_CHECK 和 AFL_SKIP_CPUFREQ：跳过 AFL 兼容性检查和不警告 CPU 时钟变化。
AFL_STATSD 和相关变量：启用 StatsD 指标收集及其配置。
AFL_NO_FASTRESUME 和 AFL_NO_SYNC：不读写快速恢复文件和禁用所有同步。
AFL_SYNC_TIME 和 AFL_FINAL_SYNC：模糊测试实例之间的同步时间和退出时的最终同步。
AFL_NO_CRASH_README：不在崩溃目录中创建 README 文件。
AFL_TESTCACHE_SIZE 和 AFL_TMPDIR：测试用例缓存大小和输入文件生成目录。
AFL_EARLY_FORKSERVER 和 AFL_PERSISTENT：在 AFL-clang-fast/AFL-clang-lto/AFL-gcc-fast 目标中强制早期 fork 服务器和持久模式。
AFL_DEFER_FORKSRV：强制延迟 fork 服务器（__AFL_INIT 在共享库中）。
AFL_FUZZER_STATS_UPDATE_INTERVAL：更新 fuzzer_stats 文件的间隔（以秒为单位）。*/
  } else {

    SAYF(
        "To view also the supported environment variables of afl-fuzz please "
        "use \"-hh\".\n\n");

  }

#ifdef USE_PYTHON
  SAYF("Compiled with %s module support, see docs/custom_mutators.md\n",
       (char *)PYTHON_VERSION);
/*
如果定义了 USE_PYTHON，则输出 AFL++ 是使用 Python 模块支持编译的，并提示用户查看相关文档以了解如何使用自定义变异器。
否则，输出 AFL++ 是没有 Python 模块支持编译的*/
#else
  SAYF("Compiled without Python module support.\n");
#endif
/*如果定义了 AFL_PERSISTENT_RECORD，则输出 AFL++ 是使用持久记录支持编译的。
否则，输出 AFL++ 是没有持久记录支持编译的。*/
#ifdef AFL_PERSISTENT_RECORD
  SAYF("Compiled with AFL_PERSISTENT_RECORD support.\n");
 
#else
  SAYF("Compiled without AFL_PERSISTENT_RECORD support.\n");
#endif
 /*如果定义了 USEMMAP，则输出 AFL++ 是使用 shm_open 支持编译的。
否则，输出 AFL++ 是使用 shmat 支持编译的。*/
#ifdef USEMMAP
  SAYF("Compiled with shm_open support.\n");
#else
  SAYF("Compiled with shmat support.\n");
#endif
/*如果定义了 ASAN_BUILD，则输出 AFL++ 是使用 ASAN 构建编译的。*/
#ifdef ASAN_BUILD
  SAYF("Compiled with ASAN_BUILD.\n");
#endif
/*如果定义了 NO_SPLICING，则输出 AFL++ 是使用禁止拼接选项编译的*/
#ifdef NO_SPLICING
  SAYF("Compiled with NO_SPLICING.\n");
#endif
/*如果定义了 FANCY_BOXES_NO_UTF，则输出 AFL++ 是没有 UTF-8 支持编译的，这会影响状态屏幕中的线条渲染。*/
#ifdef FANCY_BOXES_NO_UTF
  SAYF("Compiled without UTF-8 support for line rendering in status screen.\n");
#endif
/*如果定义了 PROFILING，则输出 AFL++ 是使用性能分析编译的。*/
#ifdef PROFILING
  SAYF("Compiled with PROFILING.\n");
#endif
/*如果定义了 INTROSPECTION，则输出 AFL++ 是使用自省编译的。*/
#ifdef INTROSPECTION
  SAYF("Compiled with INTROSPECTION.\n");
#endif
/*如果定义了 _DEBUG，则输出 AFL++ 是使用调试模式编译的*/
#ifdef _DEBUG
  SAYF("Compiled with _DEBUG.\n");
#endif
/*如果定义了 _AFL_DOCUMENT_MUTATIONS，则输出 AFL++ 是使用记录变异编译的。*/
#ifdef _AFL_DOCUMENT_MUTATIONS
  SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS.\n");
#endif
/*如果定义了 _AFL_SPECIAL_PERFORMANCE，则输出 AFL++ 是使用特定系统的特殊性能选项编译的，并提醒用户这可能不适用于其他平台。*/
#ifdef _AFL_SPECIAL_PERFORMANCE
  SAYF(
      "Compiled with special performance options for this specific system, it "
      "might not work on other platforms!\n");
#endif

  SAYF("For additional help please consult %s/README.md :)\n\n", doc_path);

  exit(1);
#undef PHYTON_SUPPORT
/*额外帮助：输出提示信息，建议用户查阅 README.md 文件以获取更多帮助。
退出程序：调用 exit(1) 退出程序，返回状态码 1 表示程序因错误或异常而退出。
取消宏定义：使用 #undef PHYTON_SUPPORT 取消 PHYTON_SUPPORT 宏的定义，尽管这里可能是一个拼写错误，应该是 PYTHON_SUPPORT。*/
}

#ifndef AFL_LIB

static int stricmp(char const *a, char const *b) {

  if (!a || !b) { FATAL("Null reference"); }

  for (;; ++a, ++b) {

    int d;
    d = tolower((int)*a) - tolower((int)*b);
    if (d != 0 || !*a) { return d; }

  }

}

static void fasan_check_afl_preload(char *afl_preload) {

  char   first_preload[PATH_MAX + 1] = {0};
  char  *separator = strchr(afl_preload, ':');
  size_t first_preload_len = PATH_MAX;
  char  *basename;
  char   clang_runtime_prefix[] = "libclang_rt.asan";

  if (separator != NULL && (separator - afl_preload) < PATH_MAX) {

    first_preload_len = separator - afl_preload;

  }

  strncpy(first_preload, afl_preload, first_preload_len);

  basename = strrchr(first_preload, '/');
  if (basename == NULL) {

    basename = first_preload;

  } else {

    basename = basename + 1;

  }

  if (strncmp(basename, clang_runtime_prefix,
              sizeof(clang_runtime_prefix) - 1) != 0) {

    FATAL("Address Sanitizer DSO must be the first DSO in AFL_PRELOAD");

  }

  if (access(first_preload, R_OK) != 0) {

    FATAL("Address Sanitizer DSO not found");

  }

  OKF("Found ASAN DSO: %s", first_preload);

}

/* Main entry point */

int main(int argc, char **argv_orig, char **envp) {

  s32 opt, auto_sync = 0 /*, user_set_cache = 0*/;//用于存储 getopt 函数返回的选项字符
  u64 prev_queued = 0;//自动同步标志，初始值为 0。
  //用于记录上一次排队的项目数量。
  u32 sync_interval_cnt /*同步间隔计数器*/= 0, seek_to = 0, show_help = 0, default_output = 1,
      map_size = get_map_size();
  u8 *extras_dir[4];
  u8  mem_limit_given = 0, exit_1 = 0, debug = 0,
     extras_dir_cnt = 0 /*, have_p = 0*/;
  char  *afl_preload;
  char  *frida_afl_preload = NULL;
  char **use_argv;

  struct timeval  tv;
  struct timezone tz;
/*eek_to：用于指定从哪个位置开始处理队列。
show_help：显示帮助信息的标志。
default_output：默认输出标志，初始值为 1。
map_size：共享内存映射的大小，通过 get_map_size 函数获取。
extras_dir[4]：存储额外字典目录的数组。
mem_limit_given：内存限制是否已指定的标志。
exit_1：是否仅运行一次的标志。
debug：调试模式标志。
extras_dir_cnt：额外字典目录的数量。
afl_preload 和 frida_afl_preload：用于存储 AFL 预加载库的路径。
use_argv：用于存储处理后的命令行参数。
struct timeval tv 和 struct timezone tz：用于获取当前时间*/
  doc_path = access(DOC_PATH, F_OK) != 0 ? (u8 *)"docs" : (u8 *)DOC_PATH;
//根据 DOC_PATH 环境变量或默认路径 "docs" 初始化文档路径
  if (argc > 1 && strcmp(argv_orig[1], "--version") == 0) {

    printf("afl-fuzz" VERSION "\n");
    exit(0);

  }

  if (argc > 1 && strcmp(argv_orig[1], "--help") == 0) {

    usage(argv_orig[0], 1);
    exit(0);

  }
/*版本信息：如果命令行参数包含 --version，则输出 AFL++ 的版本信息并退出程序。
帮助信息：如果命令行参数包含 --help，则调用 usage 函数显示帮助信息并退出程序。*/
  #if defined USE_COLOR && defined ALWAYS_COLORED
  if (getenv("AFL_NO_COLOR") || getenv("AFL_NO_COLOUR")) {

    WARNF(
        "Setting AFL_NO_COLOR has no effect (colors are configured on at "
        "compile time)");

  }
/*颜色输出：如果定义了 USE_COLOR 和 ALWAYS_COLORED，并且环境变量 AFL_NO_COLOR 或 AFL_NO_COLOUR 被设置，则输出警告信息，提示用户颜色设置在编译时已配置。*/
  #endif

  char **argv = argv_cpy_dup(argc, argv_orig);
//argv_cpy_dup：复制命令行参数数组，以便在后续处理中使用
  afl_state_t *afl = calloc(1, sizeof(afl_state_t));
  if (!afl) { FATAL("Could not create afl state"); }

  if (get_afl_env("AFL_DEBUG")) { debug = afl->debug = 1; }

  afl_state_init(afl, map_size);
  afl->debug = debug;
  afl_fsrv_init(&afl->fsrv);
  if (debug) { afl->fsrv.debug = true; }
  read_afl_environment(afl, envp);
  if (afl->shm.map_size) { afl->fsrv.map_size = afl->shm.map_size; }
  exit_1 = !!afl->afl_env.afl_bench_just_one;
//SAYF：输出 AFL++ 的版本信息和基于的原始 AFL 作者信息。
  SAYF(cCYA "afl-fuzz" VERSION cRST
            " based on afl by Michal Zalewski and a large online community\n");
//gettimeofday：获取当前时间。
//rand_set_seed：根据当前时间设置随机种子，用于后续的随机数生成
  gettimeofday(&tv, &tz);
  rand_set_seed(afl, tv.tv_sec ^ tv.tv_usec ^ getpid());
//afl->shmem_testcase_mode：设置为 1，表示始终尝试使用共享内存进行模糊测试。
  afl->shmem_testcase_mode = 1;  // we always try to perform shmem fuzzing
/*分配内存：为 afl_state_t 结构体分配内存，用于存储 AFL++ 的状态信息。
调试模式：检查环境变量 AFL_DEBUG，如果设置，则启用调试模式。
初始化状态：调用 afl_state_init 函数初始化 AFL 状态，设置共享内存映射大小。
文件服务器初始化：调用 afl_fsrv_init 函数初始化文件服务器状态。
读取环境变量：调用 read_afl_environment 函数读取 AFL++ 相关的环境变量设置。
内存映射大小：如果环境变量中指定了共享内存映射大小，则更新文件服务器状态中的映射大小。
仅运行一次：检查是否仅运行一次的标志*/
  // still available: HjJkKqruvwz
  while ((opt = getopt(argc, argv,
                       "+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:"
                       "T:UV:WXx:YzZ")) > 0) {

    switch (opt) {

      case 'a':

        if (!stricmp(optarg, "text") || !stricmp(optarg, "ascii") ||
            !stricmp(optarg, "txt") || !stricmp(optarg, "asc")) {

          afl->input_mode = 1;

        } else if (!stricmp(optarg, "bin") || !stricmp(optarg, "binary")) {

          afl->input_mode = 2;

        } else if (!stricmp(optarg, "def") || !stricmp(optarg, "default")) {

          afl->input_mode = 0;

        } else {

          FATAL("-a input mode needs to be \"text\" or \"binary\".");

        }

        break;

      case 'P':
        if (!stricmp(optarg, "explore") || !stricmp(optarg, "exploration")) {

          afl->fuzz_mode = 0;
          afl->switch_fuzz_mode = 0;

        } else if (!stricmp(optarg, "exploit") ||

                   !stricmp(optarg, "exploitation")) {

          afl->fuzz_mode = 1;
          afl->switch_fuzz_mode = 0;

        } else {

          if ((afl->switch_fuzz_mode = (u32)atoi(optarg)) > INT_MAX) {

            FATAL(
                "Parameter for option -P must be \"explore\", \"exploit\" or a "
                "number!");

          } else {

            afl->switch_fuzz_mode *= 1000;

          }

        }

        break;

      case 'g':
        afl->min_length = atoi(optarg);
        break;

      case 'G':
        afl->max_length = atoi(optarg);
        break;

      case 'Z':
        afl->old_seed_selection = 1;
        break;

      case 'I':
        afl->infoexec = optarg;
        break;

      case 'b': {                                          /* bind CPU core */

        if (afl->cpu_to_bind != -1) FATAL("Multiple -b options not supported");

        if (sscanf(optarg, "%d", &afl->cpu_to_bind) < 0) {

          FATAL("Bad syntax used for -b");

        }
/*getopt 循环：使用 getopt 函数解析命令行选项。
-a 选项：设置输入模式，可以是 "text"、"binary" 或 "default"。
-P 选项：设置固定的变异策略，可以是 "explore"、"exploit" 或指定一个秒数，表示在没有发现新结果时自动切换到 "exploit" 模式的时间。
-g 选项：设置生成的模糊输入的最小长度。
-G 选项：设置生成的模糊输入的最大长度。
-Z 选项：启用旧的种子选择方式。
-I 选项：设置信息执行命令。
-b 选项：绑定 AFL++ 进程到指定的 CPU 核心*/

        break;

      }

      case 'c': {
/*-c 选项
功能：用于启用或禁用 CMPLog 模式。
逻辑：
如果选项参数为 "-"，则表示禁用 CMPLog 模式。如果之前已经启用，则输出提示信息并禁用 CMPLog 模式，同时将 cmplog_binary 设置为 NULL。
如果选项参数不为 "-"，则启用 CMPLog 模式，并将 cmplog_binary 设置为选项参数指定的路径。*/        

        if (strcmp(optarg, "-") == 0) {

          if (afl->shm.cmplog_mode) {

            ACTF("Disabling cmplog again because of '-c -'.");
            afl->shm.cmplog_mode = 0;
            afl->cmplog_binary = NULL;

          }

        } else {

          afl->shm.cmplog_mode = 1;
          afl->cmplog_binary = ck_strdup(optarg);

        }

        break;

      }

      case 's': {
/*-s 选项
功能：用于设置固定的随机种子。
逻辑：
如果选项参数为 NULL，则输出错误信息并终止程序。
否则，使用选项参数指定的种子值初始化随机数生成器，并设置 fixed_seed 标志为 1，表示使用固定的随机种子。*/
        if (optarg == NULL) { FATAL("No valid seed provided. Got NULL."); }
        rand_set_seed(afl, strtoul(optarg, 0L, 10));
        afl->fixed_seed = 1;
        break;

      }

      case 'p':                                           /* Power schedule */
/*-p 选项
功能：用于设置功率调度策略，决定如何计算种子的性能得分。
逻辑：
根据选项参数的值，将 afl->schedule 设置为相应的功率调度策略枚举值。支持的策略包括 FAST、COE、EXPLOIT、LIN、QUAD、MMOPT、RARE、EXPLORE 和 SEEK。
如果选项参数不匹配任何已知策略，则输出错误信息并终止程序。
*/
        if (!stricmp(optarg, "fast")) {

          afl->schedule = FAST;

        } else if (!stricmp(optarg, "coe")) {

          afl->schedule = COE;

        } else if (!stricmp(optarg, "exploit")) {

          afl->schedule = EXPLOIT;

        } else if (!stricmp(optarg, "lin")) {

          afl->schedule = LIN;

        } else if (!stricmp(optarg, "quad")) {

          afl->schedule = QUAD;

        } else if (!stricmp(optarg, "mopt") || !stricmp(optarg, "mmopt")) {

          afl->schedule = MMOPT;

        } else if (!stricmp(optarg, "rare")) {

          afl->schedule = RARE;

        } else if (!stricmp(optarg, "explore") || !stricmp(optarg, "afl") ||

                   !stricmp(optarg, "default") ||

                   !stricmp(optarg, "normal")) {

          afl->schedule = EXPLORE;

        } else if (!stricmp(optarg, "seek")) {

          afl->schedule = SEEK;

        } else {

          FATAL("Unknown -p power schedule");

        }

        // have_p = 1;

        break;

      case 'e':
/*-e 选项
功能：用于设置目标程序输入文件的扩展名。
逻辑：
如果 afl->file_extension 已经被设置，则输出错误信息并终止程序，表示不支持多个 -e 选项。
否则，将 afl->file_extension 设置为选项参数指定的扩展名。*/
        if (afl->file_extension) { FATAL("Multiple -e options not supported"); }

        afl->file_extension = optarg;

        break;

      case 'i':                                                /* input dir */
/*-i 选项
功能：用于指定输入目录，该目录包含用于模糊测试的测试用例。
逻辑：
如果 afl->in_dir 已经被设置，则输出错误信息并终止程序，表示不支持多个 -i 选项。
如果选项参数为 NULL，则输出错误信息并终止程序，表示无效的 -i 选项。
否则，将 afl->in_dir 设置为选项参数指定的输入目录路径。
如果输入目录为 "-"，则设置 afl->in_place_resume 标志为 1，表示恢复之前的模糊测试会话。*/
        if (afl->in_dir) { FATAL("Multiple -i options not supported"); }
        if (optarg == NULL) { FATAL("Invalid -i option (got NULL)."); }
        afl->in_dir = optarg;

        if (!strcmp(afl->in_dir, "-")) { afl->in_place_resume = 1; }

        break;

      case 'o':                                               /* output dir */
/*-o 选项
功能：用于指定输出目录，用于存储模糊测试过程中发现的结果。
逻辑：
如果 afl->out_dir 已经被设置，则输出错误信息并终止程序，表示不支持多个 -o 选项。
否则，将 afl->out_dir 设置为选项参数指定的输出目录路径。*/
        if (afl->out_dir) { FATAL("Multiple -o options not supported"); }
        afl->out_dir = optarg;
        break;

      case 'M': {                                           /* main sync ID */
/*-M 选项
功能：用于设置主同步 ID，用于分布式模糊测试中的主节点。
逻辑：
检查是否处于非插桩模式或 ARM CoreSight 模式，如果是，则输出错误信息并终止程序，因为这些模式不支持 -M 选项。
检查是否已经设置了同步 ID，如果是，则输出错误信息并终止程序，表示不支持多个 -S 或 -M 选项。
检查选项参数是否以 - 开头，如果是，则输出错误信息并终止程序，因为 - 通常用于选项。
将同步 ID 设置为选项参数指定的值。
设置 old_seed_selection 标志为 1，表示使用旧的队列遍历种子选择方式。
设置 disable_trim 标志为 1，表示禁用修剪功能。
如果同步 ID 中包含 :，则解析主节点 ID 和主节点最大值，并进行有效性检查。如果解析失败或值无效，则输出错误信息并终止程序。
设置 is_main_node 标志为 1，表示当前节点是主节点。
*/
        u8 *c;

        if (afl->non_instrumented_mode) {

          FATAL("-M is not supported in non-instrumented mode");

        }

        if (afl->fsrv.cs_mode) {

          FATAL("-M is not supported in ARM CoreSight mode");

        }

        if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); }

        /* sanity check for argument: should not begin with '-' (possible
         * option) */
        if (optarg && *optarg == '-') {

          FATAL(
              "argument for -M started with a dash '-', which is used for "
              "options");

        }

        afl->sync_id = ck_strdup(optarg);
        afl->old_seed_selection = 1;  // force old queue walking seed selection
        afl->disable_trim = 1;        // disable trimming

        if ((c = strchr(afl->sync_id, ':'))) {

          *c = 0;

          if (sscanf(c + 1, "%u/%u", &afl->main_node_id, &afl->main_node_max) !=
                  2 ||
              !afl->main_node_id || !afl->main_node_max ||
              afl->main_node_id > afl->main_node_max ||
              afl->main_node_max > 1000000) {

            FATAL("Bogus main node ID passed to -M");

          }

        }

        afl->is_main_node = 1;

      }

      break;

      case 'S':                                        /* secondary sync id */
/*-S 选项
功能：用于设置次级同步 ID，用于分布式模糊测试中的次级节点。
逻辑：
检查是否处于非插桩模式或 ARM CoreSight 模式，如果是，则输出错误信息并终止程序，因为这些模式不支持 -S 选项。
检查是否已经设置了同步 ID，如果是，则输出错误信息并终止程序，表示不支持多个 -S 或 -M 选项。
检查选项参数是否以 - 开头，如果是，则输出错误信息并终止程序，因为 - 通常用于选项。
将同步 ID 设置为选项参数指定的值。
设置 is_secondary_node 标志为 1，表示当前节点是次级节点*/
        if (afl->non_instrumented_mode) {

          FATAL("-S is not supported in non-instrumented mode");

        }

        if (afl->fsrv.cs_mode) {

          FATAL("-S is not supported in ARM CoreSight mode");

        }

        if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); }

        /* sanity check for argument: should not begin with '-' (possible
         * option) */
        if (optarg && *optarg == '-') {

          FATAL(
              "argument for -M started with a dash '-', which is used for "
              "options");

        }

        afl->sync_id = ck_strdup(optarg);
        afl->is_secondary_node = 1;
        break;

      case 'F':                                         /* foreign sync dir */
/*-F 选项
功能：用于指定外部同步目录，用于分布式模糊测试中与其他模糊测试实例同步。
逻辑：
检查是否提供了选项参数，如果没有，则输出错误信息并终止程序。
检查是否是主节点，如果不是，则输出错误信息并终止程序，因为 -F 选项只能在主节点中指定。
检查是否已经达到外部同步目录的最大数量限制，如果是，则输出错误信息并终止程序。
将外部同步目录添加到 foreign_syncs 数组中，并去除路径末尾的斜杠。*/
        if (!optarg) { FATAL("Missing path for -F"); }
        if (!afl->is_main_node) {

          FATAL(
              "Option -F can only be specified after the -M option for the "
              "main fuzzer of a fuzzing campaign");

        }

        if (afl->foreign_sync_cnt >= FOREIGN_SYNCS_MAX) {

          FATAL("Maximum %u entried of -F option can be specified",
                FOREIGN_SYNCS_MAX);

        }

        afl->foreign_syncs[afl->foreign_sync_cnt].dir = optarg;
        while (afl->foreign_syncs[afl->foreign_sync_cnt]
                   .dir[strlen(afl->foreign_syncs[afl->foreign_sync_cnt].dir) -
                        1] == '/') {

          afl->foreign_syncs[afl->foreign_sync_cnt]
              .dir[strlen(afl->foreign_syncs[afl->foreign_sync_cnt].dir) - 1] =
              0;

        }

        afl->foreign_sync_cnt++;
        break;

      case 'f':                                              /* target file */
/*-f 选项
功能：用于指定目标程序读取的文件路径。
逻辑：
检查是否已经设置了输出文件，如果是，则输出错误信息并终止程序，表示不支持多个 -f 选项。
将输出文件路径设置为选项参数指定的值。
设置 use_stdin 标志为 0，表示不使用标准输入。
设置 default_output 标志为 0，表示不使用默认输出。*/
        if (afl->fsrv.out_file) { FATAL("Multiple -f options not supported"); }

        afl->fsrv.out_file = ck_strdup(optarg);
        afl->fsrv.use_stdin = 0;
        default_output = 0;
        break;

      case 'x':                                               /* dictionary */
/*-x 选项
功能：用于指定字典文件路径，用于辅助模糊测试。
逻辑：
检查是否已经设置了超过四个字典文件，如果是，则输出错误信息并终止程序，表示不支持超过四个 -x 选项。
将字典文件路径添加到 extras_dir 数组中，并增加 extras_dir_cnt 计数。*/
        if (extras_dir_cnt >= 4) {

          FATAL("More than four -x options are not supported");

        }

        extras_dir[extras_dir_cnt++] = optarg;
        break;

      case 't': {                                                /* timeout */
/*-t 选项
功能：用于设置每次运行的超时时间。
逻辑：
检查是否已经设置了超时时间，如果是，则输出错误信息并终止程序，表示不支持多个 -t 选项。
解析选项参数，提取超时时间值和可能的后缀（如 +）。
如果超时时间值小于 5 毫秒，则输出错误信息并终止程序，表示超时时间过低。
根据后缀设置 timeout_given 标志，+ 表示自动计算超时时间。*/
        u8 suffix = 0;

        if (afl->timeout_given) { FATAL("Multiple -t options not supported"); }

        if (!optarg ||
            sscanf(optarg, "%u%c", &afl->fsrv.exec_tmout, &suffix) < 1 ||
            optarg[0] == '-') {

          FATAL("Bad syntax used for -t");

        }

        if (afl->fsrv.exec_tmout < 5) { FATAL("Dangerously low value of -t"); }

        if (suffix == '+') {

          afl->timeout_given = 2;

        } else {

          afl->timeout_given = 1;

        }

        break;

      }

      case 'm': {                                              /* mem limit */
/*-m 选项
功能：用于设置子进程的内存限制。
逻辑：
检查是否已经设置了内存限制，如果是，则输出警告信息，表示将覆盖之前的 -m 选项。
解析选项参数，提取内存限制值和可能的单位后缀（如 T、G、k、M）。
根据单位后缀将内存限制值转换为相应的字节数。
如果内存限制值小于 5 字节，则输出错误信息并终止程序，表示内存限制过低。
在 32 位系统上，如果内存限制值大于 2000 MB，则输出错误信息并终止程序，表示内存限制超出范围。*/
        u8 suffix = 'M';

        if (mem_limit_given) {

          WARNF("Overriding previous -m option.");

        } else {

          mem_limit_given = 1;

        }

        if (!optarg) { FATAL("Wrong usage of -m"); }

        if (!strcmp(optarg, "none")) {

          afl->fsrv.mem_limit = 0;
          break;

        }

        if (sscanf(optarg, "%llu%c", &afl->fsrv.mem_limit, &suffix) < 1 ||
            optarg[0] == '-') {

          FATAL("Bad syntax used for -m");

        }

        switch (suffix) {

          case 'T':
            afl->fsrv.mem_limit *= 1024 * 1024;
            break;
          case 'G':
            afl->fsrv.mem_limit *= 1024;
            break;
          case 'k':
            afl->fsrv.mem_limit /= 1024;
            break;
          case 'M':
            break;

          default:
            FATAL("Unsupported suffix or bad syntax for -m");

        }

        if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 5) {

          FATAL("Dangerously low value of -m");

        }

        if (sizeof(rlim_t) == 4 && afl->fsrv.mem_limit > 2000) {

          FATAL("Value of -m out of range on 32-bit systems");

        }

      }

      break;

      case 'd':
      case 'D':                                        /* old deterministic */
/*-d 和 -D 选项
功能：这两个选项已被弃用，用于旧的确定性模糊测试。
逻辑：
输出警告信息，提示用户新的增强确定性模糊测试已默认激活，如果需要禁用，请使用 -z 选项。*/
        WARNF(
            "Parameters -d and -D are deprecated, a new enhanced deterministic "
            "fuzzing is active by default, to disable it use -z");
        break;

      case 'z':                                         /* no deterministic */
/*-z 选项
功能：用于禁用确定性模糊测试。
逻辑：
设置 skip_deterministic 标志为 1，表示跳过确定性模糊测试阶段。*/
        afl->skip_deterministic = 1;
        break;

      case 'B':                                              /* load bitmap */
/*-B 选项
功能：用于加载位图，这是一个未公开的选项。
逻辑：
如果已经设置了 in_bitmap，则输出错误信息并终止程序，表示不支持多个 -B 选项。
将 in_bitmap 设置为选项参数指定的位图文件路径。
说明：该选项用于在正常的模糊测试过程中发现有趣的测试用例时，加载之前运行产生的位图，*/
        /* This is a secret undocumented option! It is useful if you find
           an interesting test case during a normal fuzzing process, and want
           to mutate it without rediscovering any of the test cases already
           found during an earlier run.

           To use this mode, you need to point -B to the fuzz_bitmap produced
           by an earlier run for the exact same binary... and that's it.

           I only used this once or twice to get variants of a particular
           file, so I'm not making this an official setting. */

        if (afl->in_bitmap) { FATAL("Multiple -B options not supported"); }

        afl->in_bitmap = optarg;
        break;

      case 'C':                                               /* crash mode */
/*-C 选项
功能：用于设置崩溃模式。
逻辑：
如果已经设置了 crash_mode，则输出错误信息并终止程序，表示不支持多个 -C 选项。
将 crash_mode 设置为 FSRV_RUN_CRASH，表示启用崩溃模式。*/
        if (afl->crash_mode) { FATAL("Multiple -C options not supported"); }
        afl->crash_mode = FSRV_RUN_CRASH;
        break;

      case 'n':                                                /* dumb mode */
/*-n 选项
功能：用于设置非插桩模式。
逻辑：
检查是否是主节点或次级节点，如果是，则输出错误信息并终止程序，因为非插桩模式不支持与 -M 或 -S 一起使用。
检查是否已经设置了 non_instrumented_mode，如果是，则输出错误信息并终止程序，表示不支持多个 -n 选项。
根据环境变量 AFL_DUMB_FORKSRV 的设置，将 non_instrumented_mode 设置为 1 或 2，表示启用非插桩模式。*/
        if (afl->is_main_node || afl->is_secondary_node) {

          FATAL("Non instrumented mode is not supported with -M / -S");

        }

        if (afl->non_instrumented_mode) {

          FATAL("Multiple -n options not supported");

        }

        if (afl->afl_env.afl_dumb_forksrv) {

          afl->non_instrumented_mode = 2;

        } else {

          afl->non_instrumented_mode = 1;

        }

        break;

      case 'T':                                                   /* banner */
/*-T 选项
功能：用于设置横幅。
逻辑：
如果已经设置了 use_banner，则输出错误信息并终止程序，表示不支持多个 -T 选项。
将 use_banner 设置为选项参数指定的横幅文本。*/
        if (afl->use_banner) { FATAL("Multiple -T options not supported"); }
        afl->use_banner = optarg;
        break;

  #ifdef __linux__
      case 'X':                                                 /* NYX mode */
/*-X 和 -Y 选项（仅限 Linux）
功能：用于设置 Nyx 模式。
逻辑：
-X 选项：设置 Nyx 独立模式。
检查是否已经设置了 nyx_mode，如果是，则输出错误信息并终止程序，表示不支持多个 -X 选项。
设置 nyx_parent、nyx_standalone 和 nyx_mode 标志，表示启用 Nyx 独立模式。
-Y 选项：设置 Nyx 分布式模式。
检查是否已经设置了 nyx_mode，如果是，则输出错误信息并终止程序，表示不支持多个 -Y 选项。
设置 nyx_mode 标志，表示启用 Nyx 分布式模式*/
        if (afl->fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); }

        afl->fsrv.nyx_parent = true;
        afl->fsrv.nyx_standalone = true;
        afl->fsrv.nyx_mode = 1;
        afl->fsrv.nyx_id = 0;

        break;

      case 'Y':                                     /* NYX distributed mode */
        if (afl->fsrv.nyx_mode) { FATAL("Multiple -Y options not supported"); }

        afl->fsrv.nyx_mode = 1;

        break;
  #else
      case 'X':
      case 'Y':
        FATAL("Nyx mode is only availabe on linux...");
        break;
  #endif
      case 'A':                                           /* CoreSight mode */
/*-A 选项（仅限 ARM64 和 Linux）
功能：用于设置 ARM CoreSight 模式。
逻辑：
检查是否是主节点或次级节点，如果是，则输出错误信息并终止程序，因为 ARM CoreSight 模式不支持与 -M 或 -S 一起使用。
检查是否已经设置了 cs_mode，如果是，则输出错误信息并终止程序，表示不支持多个 -A 选项。
设置 cs_mode 标志，表示启用 ARM CoreSight 模式。*/
  #if !defined(__aarch64__) || !defined(__linux__)
        FATAL("-A option is not supported on this platform");
  #endif

        if (afl->is_main_node || afl->is_secondary_node) {

          FATAL("ARM CoreSight mode is not supported with -M / -S");

        }

        if (afl->fsrv.cs_mode) { FATAL("Multiple -A options not supported"); }

        afl->fsrv.cs_mode = 1;

        break;

      case 'O':                                               /* FRIDA mode */
/*-O 选项
功能：用于设置 FRIDA 模式。
逻辑：
检查是否已经设置了 frida_mode，如果是，则输出错误信息并终止程序，表示不支持多个 -O 选项。
设置 frida_mode 标志，表示启用 FRIDA 模式。
检查环境变量 AFL_USE_FASAN，如果设置，则设置 frida_asan 标志为 1，表示使用 FRIDA 地址制裁模式。*/
        if (afl->fsrv.frida_mode) {

          FATAL("Multiple -O options not supported");

        }

        afl->fsrv.frida_mode = 1;
        if (get_afl_env("AFL_USE_FASAN")) { afl->fsrv.frida_asan = 1; }

        break;

      case 'Q':                                                /* QEMU mode */
/*-Q 选项
功能：用于启用 QEMU 模式。
逻辑：
检查是否已经设置了 qemu_mode，如果是，则输出错误信息并终止程序，表示不支持多个 -Q 选项。
设置 qemu_mode 标志为 1，表示启用 QEMU 模式。
如果没有指定内存限制，则将 mem_limit 设置为 MEM_LIMIT_QEMU，即 QEMU 模式的默认内存限制。*/
        if (afl->fsrv.qemu_mode) { FATAL("Multiple -Q options not supported"); }

        afl->fsrv.qemu_mode = 1;

        if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_QEMU; }

        break;

      case 'N':                                             /* Unicorn mode */
/*-N 选项
功能：用于设置不删除模糊测试输入文件的标志。
逻辑：
检查是否已经设置了 no_unlink，如果是，则输出错误信息并终止程序，表示不支持多个 -N 选项。
设置 no_unlink 标志为 true，表示在模糊测试过程中不删除输入文件。*/
        if (afl->no_unlink) { FATAL("Multiple -N options not supported"); }
        afl->fsrv.no_unlink = (afl->no_unlink = true);

        break;

      case 'U':                                             /* Unicorn mode */
/*-U 选项
功能：用于启用 Unicorn 模式。
逻辑：
检查是否已经设置了 unicorn_mode，如果是，则输出错误信息并终止程序，表示不支持多个 -U 选项。
设置 unicorn_mode 标志为 1，表示启用 Unicorn 模式。
如果没有指定内存限制，则将 mem_limit 设置为 MEM_LIMIT_UNICORN，即 Unicorn 模式的默认内存限制。
*/
        if (afl->unicorn_mode) { FATAL("Multiple -U options not supported"); }
        afl->unicorn_mode = 1;

        if (!mem_limit_given) { afl->fsrv.mem_limit = MEM_LIMIT_UNICORN; }

        break;

      case 'W':                                           /* Wine+QEMU mode */
/*-W 选项
功能：用于启用 Wine+QEMU 模式。
逻辑：
检查是否已经设置了 use_wine，如果是，则输出错误信息并终止程序，表示不支持多个 -W 选项。
设置 qemu_mode 标志为 1，表示启用 QEMU 模式。
设置 use_wine 标志为 1，表示启用 Wine 模式。
如果没有指定内存限制，则将 mem_limit 设置为 0，即不限制内存。*/
        if (afl->use_wine) { FATAL("Multiple -W options not supported"); }
        afl->fsrv.qemu_mode = 1;
        afl->use_wine = 1;

        if (!mem_limit_given) { afl->fsrv.mem_limit = 0; }

        break;

      case 'V': {
/*-V 选项
功能：用于设置 AFL++ 运行的最大时间。
逻辑：
设置 most_time_key 标志为 1，表示启用了运行时间限制。
解析选项参数，提取最大运行时间值。
如果解析失败或参数格式不正确，则输出错误信息并终止程序。*/
        afl->most_time_key = 1;
        if (!optarg || sscanf(optarg, "%llu", &afl->most_time) < 1 ||
            optarg[0] == '-') {

          FATAL("Bad syntax used for -V");

        }

      } break;

      case 'E': {
/*-E 选项
功能：用于设置 AFL++ 运行的最大执行次数。
逻辑：
设置 most_execs_key 标志为 1，表示启用了执行次数限制。
解析选项参数，提取最大执行次数值。
如果解析失败或参数格式不正确，则输出错误信息并终止程序。*/
        afl->most_execs_key = 1;
        if (!optarg || sscanf(optarg, "%llu", &afl->most_execs) < 1 ||
            optarg[0] == '-') {

          FATAL("Bad syntax used for -E");

        }

      } break;

      case 'l': {
/*-l 选项
功能：用于配置 CMPLog 的行为。
逻辑：
检查是否提供了选项参数，如果没有，则输出错误信息并终止程序。
遍历选项参数中的每个字符，根据字符设置相应的 CMPLog 配置：
'0'、'1'：设置 CMPLog 级别为 1。
'2'：设置 CMPLog 级别为 2。
'3'：设置 CMPLog 级别为 3，并禁用修剪功能。
'a'、'A'：启用算术求解。
's'、'S'：启用缩放求解。
't'、'T'：启用变换求解。
'x'、'X'：启用极端变换求解。
'r'、'R'：启用随机颜色化。
如果 CMPLog 级别达到最大值 CMPLOG_LVL_MAX，则将 cmplog_max_filesize 设置为 MAX_FILE，即最大文件大小限制。*/
        if (!optarg) { FATAL("missing parameter for 'l'"); }
        char *c = optarg;
        while (*c) {

          switch (*c) {

            case '0':
            case '1':
              afl->cmplog_lvl = 1;
              break;
            case '2':
              afl->cmplog_lvl = 2;
              break;
            case '3':
              afl->cmplog_lvl = 3;

              if (!afl->disable_trim) {

                ACTF("Deactivating trimming due CMPLOG level 3");
                afl->disable_trim = 1;

              }

              break;
            case 'a':
            case 'A':
              afl->cmplog_enable_arith = 1;
              break;
            case 's':
            case 'S':
              afl->cmplog_enable_scale = 1;
              break;
            case 't':
            case 'T':
              afl->cmplog_enable_transform = 1;
              break;
            case 'x':
            case 'X':
              afl->cmplog_enable_xtreme_transform = 1;
              break;
            case 'r':
            case 'R':
              afl->cmplog_random_colorization = 1;
              break;
            default:
              FATAL("Unknown option value '%c' in -l %s", *c, optarg);

          }

          ++c;

        }

        if (afl->cmplog_lvl == CMPLOG_LVL_MAX) {

          afl->cmplog_max_filesize = MAX_FILE;

        }

      } break;

      case 'L': {                                              /* MOpt mode */
/*-L 选项
功能：用于设置 MOpt 模式的时间限制，以分钟为单位。
逻辑：
检查是否已经设置了 limit_time_sig，如果是，则输出错误信息并终止程序，表示不支持多个 -L 选项。
设置 havoc_max_mult 为 HAVOC_MAX_MULT_MOPT，这是 MOpt 模式下的 Havoc 变异次数乘数。
解析选项参数，提取时间限制值。
如果解析失败，则输出错误信息并终止程序。
如果时间限制值为 -1，则将 limit_time_sig 设置为 -1，表示立即进入 MOpt 模式，并将 limit_time_puppet 设置为 0。
如果时间限制值小于 0 但不等于 -1，则输出错误信息并终止程序，因为时间限制值必须在 0 到 2000000 之间或为 -1。
否则，将 limit_time_sig 设置为 1，表示时间限制有效。
设置 old_seed_selection 为 1，表示使用旧的种子选择方式。
将时间限制值转换为毫秒（乘以 60 * 1000），并检查是否发生溢出。
初始化 MOpt 模式相关的变量，包括 swarm_now、key_puppet、g_now、w_now 等。
遍历每个“swarm”（群体），初始化相关的变量，如 swarm_fitness、stage_finds_puppet、probability_now、x_now、v_now、L_best、G_best、eff_best 等。
计算每个操作符的概率和速度。
确保概率值在合理范围内。
输出警告信息，提示用户 MOpt 模式不再被维护，且不如正常的 Havoc 模式有效。*/
        if (afl->limit_time_sig) { FATAL("Multiple -L options not supported"); }

        afl->havoc_max_mult = HAVOC_MAX_MULT_MOPT;

        if (sscanf(optarg, "%d", &afl->limit_time_puppet) < 1) {

          FATAL("Bad syntax used for -L");

        }

        if (afl->limit_time_puppet == -1) {

          afl->limit_time_sig = -1;
          afl->limit_time_puppet = 0;

        } else if (afl->limit_time_puppet < 0) {

          FATAL("-L value must be between 0 and 2000000 or -1");

        } else {

          afl->limit_time_sig = 1;

        }

        afl->old_seed_selection = 1;
        u64 limit_time_puppet2 = afl->limit_time_puppet * 60 * 1000;

        if ((s32)limit_time_puppet2 < afl->limit_time_puppet) {

          FATAL("limit_time overflow");

        }

        afl->limit_time_puppet = limit_time_puppet2;
        afl->swarm_now = 0;
        if (afl->limit_time_puppet == 0) { afl->key_puppet = 1; }

        int j;
        int tmp_swarm = 0;

        if (afl->g_now > afl->g_max) { afl->g_now = 0; }
        afl->w_now = (afl->w_init - afl->w_end) * (afl->g_max - afl->g_now) /
                         (afl->g_max) +
                     afl->w_end;

        for (tmp_swarm = 0; tmp_swarm < swarm_num; ++tmp_swarm) {

          double total_puppet_temp = 0.0;
          afl->swarm_fitness[tmp_swarm] = 0.0;

          for (j = 0; j < operator_num; ++j) {

            afl->stage_finds_puppet[tmp_swarm][j] = 0;
            afl->probability_now[tmp_swarm][j] = 0.0;
            afl->x_now[tmp_swarm][j] =
                ((double)(random() % 7000) * 0.0001 + 0.1);
            total_puppet_temp += afl->x_now[tmp_swarm][j];
            afl->v_now[tmp_swarm][j] = 0.1;
            afl->L_best[tmp_swarm][j] = 0.5;
            afl->G_best[j] = 0.5;
            afl->eff_best[tmp_swarm][j] = 0.0;

          }

          for (j = 0; j < operator_num; ++j) {

            afl->stage_cycles_puppet_v2[tmp_swarm][j] =
                afl->stage_cycles_puppet[tmp_swarm][j];
            afl->stage_finds_puppet_v2[tmp_swarm][j] =
                afl->stage_finds_puppet[tmp_swarm][j];
            afl->x_now[tmp_swarm][j] =
                afl->x_now[tmp_swarm][j] / total_puppet_temp;

          }

          double x_temp = 0.0;

          for (j = 0; j < operator_num; ++j) {

            afl->probability_now[tmp_swarm][j] = 0.0;
            afl->v_now[tmp_swarm][j] =
                afl->w_now * afl->v_now[tmp_swarm][j] +
                RAND_C *
                    (afl->L_best[tmp_swarm][j] - afl->x_now[tmp_swarm][j]) +
                RAND_C * (afl->G_best[j] - afl->x_now[tmp_swarm][j]);

            afl->x_now[tmp_swarm][j] += afl->v_now[tmp_swarm][j];

            if (afl->x_now[tmp_swarm][j] > v_max) {

              afl->x_now[tmp_swarm][j] = v_max;

            } else if (afl->x_now[tmp_swarm][j] < v_min) {

              afl->x_now[tmp_swarm][j] = v_min;

            }

            x_temp += afl->x_now[tmp_swarm][j];

          }

          for (j = 0; j < operator_num; ++j) {

            afl->x_now[tmp_swarm][j] = afl->x_now[tmp_swarm][j] / x_temp;
            if (likely(j != 0)) {

              afl->probability_now[tmp_swarm][j] =
                  afl->probability_now[tmp_swarm][j - 1] +
                  afl->x_now[tmp_swarm][j];

            } else {

              afl->probability_now[tmp_swarm][j] = afl->x_now[tmp_swarm][j];

            }

          }

          if (afl->probability_now[tmp_swarm][operator_num - 1] < 0.99 ||
              afl->probability_now[tmp_swarm][operator_num - 1] > 1.01) {

            FATAL("ERROR probability");

          }

        }

        for (j = 0; j < operator_num; ++j) {

          afl->core_operator_finds_puppet[j] = 0;
          afl->core_operator_finds_puppet_v2[j] = 0;
          afl->core_operator_cycles_puppet[j] = 0;
          afl->core_operator_cycles_puppet_v2[j] = 0;
          afl->core_operator_cycles_puppet_v3[j] = 0;

        }

        WARNF(
            "Note that the MOpt mode is not maintained and is not as effective "
            "as normal havoc mode.");

      } break;

      case 'h':
        show_help++;
        break;  // not needed
/*-h 选项
功能：用于显示帮助信息。
逻辑：
增加 show_help 计数器的值。
break 语句实际上在这里是多余的，因为 switch 语句的每个 case 都是独立的。
*/
      case 'R':
/*-R 选项
功能：用于处理 Radamsa 相关的选项。
逻辑：
输出错误信息并终止程序，提示用户 Radamsa 现在是一个自定义变异器，应该使用自定义变异器的方式（custom_mutators/radamsa/）来使用。*/
        FATAL(
            "Radamsa is now a custom mutator, please use that "
            "(custom_mutators/radamsa/).");

        break;
/*默认情况
功能：处理未匹配的选项。
逻辑：
如果 show_help 未被设置，则将其设置为 1，表示需要显示帮助信息。*/
      default:
        if (!show_help) { show_help = 1; }

    }

  }
/*同步 ID 检查
功能：检查同步 ID 是否为保留名称。
逻辑：
如果 sync_id 被设置为 "addseeds"，则输出错误信息并终止程序，因为 "addseeds" 是一个保留名称，不能用作同步 ID*/
  if (afl->sync_id && strcmp(afl->sync_id, "addseeds") == 0) {

    FATAL("-M/-S name 'addseeds' is a reserved name, choose something else");

  }
/*主节点和功率调度检查
功能：检查主节点的功率调度设置。
逻辑：
如果当前是主节点（is_main_node 为 1），并且功率调度不是 FAST 或 EXPLORE，则输出错误信息并终止程序，因为 -M 选项仅与 FAST 和 EXPLORE 功率调度兼容*/
  if (afl->is_main_node == 1 && afl->schedule != FAST &&
      afl->schedule != EXPLORE) {

    FATAL("-M is compatible only with fast and explore -p power schedules");

  }
/*参数检查和帮助信息显示
功能：检查命令行参数的完整性，并在需要时显示帮助信息。
逻辑：
如果 optind 等于 argc（表示没有剩余的命令行参数）、输入目录未设置、输出目录未设置或 show_help 被设置，则调用 usage 函数显示帮助信息并退出程序。*/
  if (optind == argc || !afl->in_dir || !afl->out_dir || show_help) {

    usage(argv[0], show_help);

  }

  if (unlikely(afl->afl_env.afl_persistent_record)) {

  #ifdef AFL_PERSISTENT_RECORD
/*持久记录配置检查
功能：检查 AFL_PERSISTENT_RECORD 环境变量的设置。
逻辑：
如果 afl_env.afl_persistent_record 被设置：
如果 AFL++ 是使用 AFL_PERSISTENT_RECORD 编译的：
将 fsrv.persistent_record 设置为环境变量的值。
如果设置的值小于 2，则输出错误信息并终止程序，因为 AFL_PERSISTENT_RECORD 的值必须至少为 2，推荐值为 100 或 1000。
如果 AFL++ 未使用 AFL_PERSISTENT_RECORD 编译，则输出错误信息并终止程序，提示 AFL++ 未启用 AFL_PERSISTENT_RECORD 支持。*/
    afl->fsrv.persistent_record = atoi(afl->afl_env.afl_persistent_record);

    if (afl->fsrv.persistent_record < 2) {

      FATAL(
          "AFL_PERSISTENT_RECORD value must be be at least 2, recommended is "
          "100 or 1000.");

    }

  #else

    FATAL(
        "afl-fuzz was not compiled with AFL_PERSISTENT_RECORD enabled in "
        "config.h!");

  #endif

  }

  if (afl->fsrv.mem_limit && afl->shm.cmplog_mode) afl->fsrv.mem_limit += 260;
/*内存限制调整
逻辑：
如果设置了内存限制并且启用了 CMPLog 模式，则将内存限制增加 260 字节。这可能是为了确保 CMPLog 模式有足够的内存来存储额外的信息。*/
  OKF("AFL++ is maintained by Marc \"van Hauser\" Heuse, Dominik Maier, Andrea "
      "Fioraldi and Heiko \"hexcoder\" Eißfeldt");
  OKF("AFL++ is open source, get it at "
      "https://github.com/AFLplusplus/AFLplusplus");
  OKF("NOTE: AFL++ >= v3 has changed defaults and behaviours - see README.md");
/*版本信息显示
逻辑：
输出 AFL++ 的维护者信息，包括 Marc "van Hauser" Heuse、Dominik Maier、Andrea Fioraldi 和 Heiko "hexcoder" Eißfeldt。
提示 AFL++ 是开源软件，并提供 GitHub 仓库链接。
提醒用户 AFL++ 从版本 3 开始改变了默认设置和行为，建议查看 README.md 文件了解详细信息。*/
  #ifdef __linux__
  if (afl->fsrv.nyx_mode) {

    OKF("AFL++ Nyx mode is enabled (developed and maintained by Sergej "
        "Schumilo)");
    OKF("Nyx is open source, get it at https://github.com/Nyx-Fuzz");

  }
/*Nyx 模式信息显示（仅限 Linux）
逻辑：
如果启用了 Nyx 模式，输出 Nyx 模式的信息，包括开发者和维护者 Sergej Schumilo，以及 Nyx 的 GitHub 仓库链接。*/
  #endif

  // silently disable deterministic mutation if custom mutators are used
  if (!afl->skip_deterministic && afl->afl_env.afl_custom_mutator_only) {
/*确定性变异禁用
逻辑：
如果启用了自定义变异器且未禁用确定性变异，则自动禁用确定性变异。这是因为自定义变异器可能已经包含了确定性变异的功能。*/
    afl->skip_deterministic = 1;

  }

  if (afl->fixed_seed) {
/*固定种子信息显示
逻辑：
如果设置了固定种子，则输出正在使用的固定种子值。*/
    OKF("Running with fixed seed: %u", (u32)afl->init_seed);

  }

  #if defined(__SANITIZE_ADDRESS__)
  if (afl->fsrv.mem_limit) {

    WARNF("in the ASAN build we disable all memory limits");
    afl->fsrv.mem_limit = 0;

  }

  #endif
/*信号配置
逻辑：
调用 configure_afl_kill_signals 函数配置 AFL++ 的信号处理，设置子进程和 fork 服务器的终止信号。如果启用了 QEMU、Unicorn、fauxsrv 或 Nyx 模式，则使用 SIGKILL 信号，否则使用 SIGTERM 信号。*/
  configure_afl_kill_signals(
      &afl->fsrv, afl->afl_env.afl_child_kill_signal,
      afl->afl_env.afl_fsrv_kill_signal,
      (afl->fsrv.qemu_mode || afl->unicorn_mode || afl->fsrv.use_fauxsrv
  #ifdef __linux__
       || afl->fsrv.nyx_mode
  #endif
       )
          ? SIGKILL
          : SIGTERM);
/*信号处理设置
逻辑：
调用 setup_signal_handlers 函数设置 AFL++ 的信号处理程序，以便在接收到特定信号时执行相应的操作。*/
  setup_signal_handlers();
  check_asan_opts(afl);
/*ASAN 构建内存限制禁用（仅限 ASAN 构建）
逻辑：
如果 AFL++ 是使用 ASAN 构建的，并且设置了内存限制，则输出警告信息并禁用内存限制。这是因为 ASAN 可能需要更多的内存来检测内存问题。*/
  afl->power_name = power_names[afl->schedule];
/*ASAN 选项检查
逻辑：
调用 check_asan_opts 函数检查 ASAN 相关的选项设置，确保 AFL++ 能够与 ASAN 正常配合使用。*/
/*功率调度名称设置
逻辑：
根据当前的功率调度策略，从 power_names 数组中获取对应的名称，并将其存储在 afl->power_name 中。*/ 
  if (!afl->non_instrumented_mode && !afl->sync_id) {

    auto_sync = 1;
    afl->sync_id = ck_strdup("default");
    afl->is_secondary_node = 1;
    OKF("No -M/-S set, autoconfiguring for \"-S %s\"", afl->sync_id);

  }
/*Nyx 模式同步配置（仅限 Linux）
逻辑：
如果启用了 Nyx 模式：
如果是 Nyx 独立模式且同步 ID 不是 "default"，则输出错误信息并终止程序，因为独立模式不支持分布式模糊测试。
如果是 Nyx 分布式模式：
如果是主节点且同步 ID 不是 "0"，则输出错误信息并终止程序，因为主节点的 ID 必须是 "0"。
如果是次级节点，则解析同步 ID 并进行有效性检查。如果 ID 不是有效的数字或小于 1，则输出错误信息并终止程序。*/
  #ifdef __linux__
  if (afl->fsrv.nyx_mode) {

    if (afl->fsrv.nyx_standalone && strcmp(afl->sync_id, "default") != 0) {

      FATAL(
          "distributed fuzzing is not supported in this Nyx mode (use -Y "
          "instead)");

    }

    if (!afl->fsrv.nyx_standalone) {

      if (afl->is_main_node) {

        if (strcmp("0", afl->sync_id) != 0) {

          FATAL(
              "for Nyx -Y mode, the Main (-M) parameter has to be set to 0 (-M "
              "0)");

        }

        afl->fsrv.nyx_parent = true;
        afl->fsrv.nyx_id = 0;

      }

      if (afl->is_secondary_node) {

        long nyx_id = strtol(afl->sync_id, NULL, 10);

        if (nyx_id == 0 || nyx_id == LONG_MAX) {

          FATAL(
              "for Nyx -Y mode, the Secondary (-S) parameter has to be a "
              "numeric value and >= 1 (e.g. -S 1)");

        }

        afl->fsrv.nyx_id = nyx_id;

      }

    }

  }

  #endif

  if (afl->sync_id) { fix_up_sync(afl); }

  if (!strcmp(afl->in_dir, afl->out_dir)) {

    FATAL("Input and output directories can't be the same");

  }

  if (afl->non_instrumented_mode) {

    if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); }
    if (afl->fsrv.frida_mode) { FATAL("-O and -n are mutually exclusive"); }
    if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); }
    if (afl->fsrv.cs_mode) { FATAL("-A and -n are mutually exclusive"); }
    if (afl->unicorn_mode) { FATAL("-U and -n are mutually exclusive"); }

  }

  setenv("__AFL_OUT_DIR", afl->out_dir, 1);

  if (get_afl_env("AFL_DISABLE_TRIM") || get_afl_env("AFL_NO_TRIM")) {

    afl->disable_trim = 1;

  }

  if (getenv("AFL_NO_UI") && getenv("AFL_FORCE_UI")) {

    FATAL("AFL_NO_UI and AFL_FORCE_UI are mutually exclusive");

  }

  if (unlikely(afl->afl_env.afl_statsd)) { statsd_setup_format(afl); }

  if (!afl->use_banner) { afl->use_banner = argv[optind]; }

  if (afl->shm.cmplog_mode && strcmp("0", afl->cmplog_binary) == 0) {

    afl->cmplog_binary = strdup(argv[optind]);

  }

  if (strchr(argv[optind], '/') == NULL && !afl->unicorn_mode) {

    WARNF(cLRD
          "Target binary called without a prefixed path, make sure you are "
          "fuzzing the right binary: " cRST "%s",
          argv[optind]);

  }

  ACTF("Getting to work...");

  switch (afl->schedule) {

    case FAST:
      OKF("Using exponential power schedule (FAST)");
      break;
    case COE:
      OKF("Using cut-off exponential power schedule (COE)");
      break;
    case EXPLOIT:
      OKF("Using exploitation-based constant power schedule (EXPLOIT)");
      break;
    case LIN:
      OKF("Using linear power schedule (LIN)");
      break;
    case QUAD:
      OKF("Using quadratic power schedule (QUAD)");
      break;
    case MMOPT:
      OKF("Using modified MOpt power schedule (MMOPT)");
      break;
    case RARE:
      OKF("Using rare edge focus power schedule (RARE)");
      break;
    case SEEK:
      OKF("Using seek power schedule (SEEK)");
      break;
    case EXPLORE:
      OKF("Using exploration-based constant power schedule (EXPLORE)");
      break;
    default:
      FATAL("Unknown power schedule");
      break;

  }

  if (afl->shm.cmplog_mode) { OKF("CmpLog level: %u", afl->cmplog_lvl); }

  /* Dynamically allocate memory for AFLFast schedules */
  if (afl->schedule >= FAST && afl->schedule <= RARE) {

    afl->n_fuzz = ck_alloc(N_FUZZ_SIZE * sizeof(u32));

  }

  if (get_afl_env("AFL_NO_FORKSRV")) { afl->no_forkserver = 1; }
  if (get_afl_env("AFL_NO_CPU_RED")) { afl->no_cpu_meter_red = 1; }
  if (get_afl_env("AFL_NO_ARITH")) { afl->no_arith = 1; }
  if (get_afl_env("AFL_SHUFFLE_QUEUE")) { afl->shuffle_queue = 1; }
  if (get_afl_env("AFL_EXPAND_HAVOC_NOW")) { afl->expand_havoc = 1; }

  if (afl->afl_env.afl_autoresume) {

    afl->autoresume = 1;
    if (afl->in_place_resume) {

      SAYF("AFL_AUTORESUME has no effect for '-i -'");

    }

  }

  if (afl->afl_env.afl_hang_tmout) {

    s32 hang_tmout = atoi(afl->afl_env.afl_hang_tmout);
    if (hang_tmout < 1) { FATAL("Invalid value for AFL_HANG_TMOUT"); }
    afl->hang_tmout = (u32)hang_tmout;

  }

  if (afl->afl_env.afl_exit_on_time) {

    u64 exit_on_time = atoi(afl->afl_env.afl_exit_on_time);
    afl->exit_on_time = (u64)exit_on_time * 1000;

  }

  if (afl->afl_env.afl_max_det_extras) {

    s32 max_det_extras = atoi(afl->afl_env.afl_max_det_extras);
    if (max_det_extras < 1) { FATAL("Invalid value for AFL_MAX_DET_EXTRAS"); }
    afl->max_det_extras = (u32)max_det_extras;

  } else {

    afl->max_det_extras = MAX_DET_EXTRAS;

  }

  if (afl->afl_env.afl_testcache_size) {

    afl->q_testcase_max_cache_size =
        (u64)atoi(afl->afl_env.afl_testcache_size) * 1048576;

  }

  if (afl->afl_env.afl_testcache_entries) {

    afl->q_testcase_max_cache_entries =
        (u32)atoi(afl->afl_env.afl_testcache_entries);

    // user_set_cache = 1;

  }

  if (!afl->afl_env.afl_testcache_size || !afl->afl_env.afl_testcache_entries) {

    afl->afl_env.afl_testcache_entries = 0;
    afl->afl_env.afl_testcache_size = 0;

  }

  if (!afl->q_testcase_max_cache_size) {

    ACTF(
        "No testcache was configured. it is recommended to use a testcache, it "
        "improves performance: set AFL_TESTCACHE_SIZE=(value in MB)");

  } else if (afl->q_testcase_max_cache_size < 2 * MAX_FILE) {

    FATAL("AFL_TESTCACHE_SIZE must be set to %ld or more, or 0 to disable",
          (2 * MAX_FILE) % 1048576 == 0 ? (2 * MAX_FILE) / 1048576
                                        : 1 + ((2 * MAX_FILE) / 1048576));

  } else {

    OKF("Enabled testcache with %llu MB",
        afl->q_testcase_max_cache_size / 1048576);

  }

  if (afl->afl_env.afl_forksrv_init_tmout) {

    afl->fsrv.init_tmout = atoi(afl->afl_env.afl_forksrv_init_tmout);
    if (!afl->fsrv.init_tmout) {

      FATAL("Invalid value of AFL_FORKSRV_INIT_TMOUT");

    }

  } else {

    afl->fsrv.init_tmout = afl->fsrv.exec_tmout * FORK_WAIT_MULT;

  }

  if (afl->afl_env.afl_crash_exitcode) {

    long exitcode = strtol(afl->afl_env.afl_crash_exitcode, NULL, 10);
    if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
        exitcode < -127 || exitcode > 128) {

      FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
            afl->afl_env.afl_crash_exitcode);

    }

    afl->fsrv.uses_crash_exitcode = true;
    // WEXITSTATUS is 8 bit unsigned
    afl->fsrv.crash_exitcode = (u8)exitcode;

  }

  if (afl->non_instrumented_mode == 2 && afl->no_forkserver) {

    FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive");

  }

  // Marker: ADD_TO_INJECTIONS
  if (getenv("AFL_LLVM_INJECTIONS_ALL") || getenv("AFL_LLVM_INJECTIONS_SQL") ||
      getenv("AFL_LLVM_INJECTIONS_LDAP") || getenv("AFL_LLVM_INJECTIONS_XSS")) {

    OKF("Adding injection tokens to dictionary.");
    if (getenv("AFL_LLVM_INJECTIONS_ALL") ||
        getenv("AFL_LLVM_INJECTIONS_SQL")) {

      add_extra(afl, "'\"\"'", 4);

    }

    if (getenv("AFL_LLVM_INJECTIONS_ALL") ||
        getenv("AFL_LLVM_INJECTIONS_LDAP")) {

      add_extra(afl, "*)(1=*))(|", 10);

    }

    if (getenv("AFL_LLVM_INJECTIONS_ALL") ||
        getenv("AFL_LLVM_INJECTIONS_XSS")) {

      add_extra(afl, "1\"><\"", 5);

    }

  }

  OKF("Generating fuzz data with a length of min=%u max=%u", afl->min_length,
      afl->max_length);
  u32 min_alloc = MAX(64U, afl->min_length);
  afl_realloc(AFL_BUF_PARAM(in_scratch), min_alloc);
  afl_realloc(AFL_BUF_PARAM(in), min_alloc);
  afl_realloc(AFL_BUF_PARAM(out_scratch), min_alloc);
  afl_realloc(AFL_BUF_PARAM(out), min_alloc);
  afl_realloc(AFL_BUF_PARAM(eff), min_alloc);
  afl_realloc(AFL_BUF_PARAM(ex), min_alloc);

  afl->fsrv.use_fauxsrv = afl->non_instrumented_mode == 1 || afl->no_forkserver;
  afl->fsrv.max_length = afl->max_length;

  #ifdef __linux__
  if (!afl->fsrv.nyx_mode) {

    check_crash_handling();
    check_cpu_governor(afl);

  } else {

    u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so");
    afl->fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
    if (afl->fsrv.nyx_handlers == NULL) {

      FATAL("failed to initialize libnyx.so...");

    }

  }

  #else
  check_crash_handling();
  check_cpu_governor(afl);
  #endif

  #ifdef __APPLE__
  setenv("DYLD_NO_PIE", "1", 0);
  #endif

  if (getenv("LD_PRELOAD")) {

    WARNF(
        "LD_PRELOAD is set, are you sure that is what you want to do "
        "instead of using AFL_PRELOAD?");

  }

  if (afl->afl_env.afl_preload) {

    if (afl->fsrv.qemu_mode) {

      /* afl-qemu-trace takes care of converting AFL_PRELOAD. */

    } else if (afl->fsrv.frida_mode) {

      afl_preload = getenv("AFL_PRELOAD");
      u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
      OKF("Injecting %s ...", frida_binary);
      if (afl_preload) {

        if (afl->fsrv.frida_asan) {

          OKF("Using Frida Address Sanitizer Mode");

          if (afl->fsrv.mem_limit) {

            WARNF(
                "in the Frida Address Sanitizer Mode we disable all memory "
                "limits");
            afl->fsrv.mem_limit = 0;

          }

          fasan_check_afl_preload(afl_preload);

          setenv("ASAN_OPTIONS", "detect_leaks=false", 1);

        }

        u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
        OKF("Injecting %s ...", frida_binary);
        frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary);

        ck_free(frida_binary);

        setenv("LD_PRELOAD", frida_afl_preload, 1);
        setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);

      }

    } else {

      /* CoreSight mode uses the default behavior. */

      setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
      setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);

    }

  } else if (afl->fsrv.frida_mode) {

    if (afl->fsrv.frida_asan) {

      OKF("Using Frida Address Sanitizer Mode");
      FATAL(
          "Address Sanitizer DSO must be loaded using AFL_PRELOAD in Frida "
          "Address Sanitizer Mode");

    } else {

      u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
      OKF("Injecting %s ...", frida_binary);
      setenv("LD_PRELOAD", frida_binary, 1);
      setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
      ck_free(frida_binary);

    }

  }

  if (getenv("AFL_LD_PRELOAD")) {

    FATAL("Use AFL_PRELOAD instead of AFL_LD_PRELOAD");

  }

  if (afl->afl_env.afl_target_env &&
      !extract_and_set_env(afl->afl_env.afl_target_env)) {

    FATAL("Bad value of AFL_TARGET_ENV");

  }

  save_cmdline(afl, argc, argv);
  check_if_tty(afl);
  if (afl->afl_env.afl_force_ui) { afl->not_on_tty = 0; }

  get_core_count(afl);

  atexit(at_exit);

  setup_dirs_fds(afl);

  #ifdef HAVE_AFFINITY
  bind_to_free_cpu(afl);
  #endif                                                   /* HAVE_AFFINITY */

  #ifdef __linux__
  if (afl->fsrv.nyx_mode && afl->fsrv.nyx_bind_cpu_id == 0xFFFFFFFF) {

    afl->fsrv.nyx_bind_cpu_id = 0;

  }

  #endif

  #ifdef __HAIKU__
  /* Prioritizes performance over power saving */
  set_scheduler_mode(SCHEDULER_MODE_LOW_LATENCY);
  #endif

  #ifdef __APPLE__
  if (pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0) != 0) {

    WARNF("general thread priority settings failed");

  }

  #endif

  init_count_class16();

  if (afl->is_main_node && check_main_node_exists(afl) == 1) {

    WARNF("it is wasteful to run more than one main node!");
    sleep(1);

  } else if (!auto_sync && afl->is_secondary_node &&

             check_main_node_exists(afl) == 0) {

    WARNF(
        "no -M main node found. It is recommended to run exactly one main "
        "instance.");
    sleep(1);

  }

  #ifdef RAND_TEST_VALUES
  u32 counter;
  for (counter = 0; counter < 100000; counter++)
    printf("DEBUG: rand %06d is %u\n", counter, rand_below(afl, 65536));
  #endif

  if (!getenv("AFL_CUSTOM_INFO_PROGRAM")) {

    setenv("AFL_CUSTOM_INFO_PROGRAM", argv[optind], 1);

  }

  if (!getenv("AFL_CUSTOM_INFO_PROGRAM_INPUT") && afl->fsrv.out_file) {

    setenv("AFL_CUSTOM_INFO_PROGRAM_INPUT", afl->fsrv.out_file, 1);

  }

  if (!getenv("AFL_CUSTOM_INFO_PROGRAM_ARGV")) {

    u8 envbuf[8096] = "", tmpbuf[8096] = "";
    for (s32 i = optind + 1; i < argc; ++i) {

      strcpy(tmpbuf, envbuf);
      if (strchr(argv[i], ' ') && !strchr(argv[i], '"') &&
          !strchr(argv[i], '\'')) {

        if (!strchr(argv[i], '\'')) {

          snprintf(envbuf, sizeof(tmpbuf), "%s '%s'", tmpbuf, argv[i]);

        } else {

          snprintf(envbuf, sizeof(tmpbuf), "%s \"%s\"", tmpbuf, argv[i]);

        }

      } else {

        snprintf(envbuf, sizeof(tmpbuf), "%s %s", tmpbuf, argv[i]);

      }

    }

    setenv("AFL_CUSTOM_INFO_PROGRAM_ARGV", envbuf + 1, 1);

  }

  if (!getenv("AFL_CUSTOM_INFO_OUT")) {

    setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1);  // same as __AFL_OUT_DIR

  }

  setup_custom_mutators(afl);

  if (afl->afl_env.afl_custom_mutator_only) {

    if (!afl->custom_mutators_count) {

      if (afl->shm.cmplog_mode) {

        WARNF(
            "No custom mutator loaded, using AFL_CUSTOM_MUTATOR_ONLY is "
            "pointless and only allowed now to allow experiments with CMPLOG.");

      } else {

        FATAL(
            "No custom mutator loaded but AFL_CUSTOM_MUTATOR_ONLY specified.");

      }

    }

    /* This ensures we don't proceed to havoc/splice */
    afl->custom_only = 1;

    /* Ensure we also skip all deterministic steps */
    afl->skip_deterministic = 1;

  }

  if (afl->custom_mutators_count && afl->afl_env.afl_custom_mutator_late_send) {

    u32 count_send = 0;
    LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {

      if (el->afl_custom_fuzz_send) {

        if (count_send) {

          FATAL(
              "You can only have one custom send() function if you are using "
              "AFL_CUSTOM_MUTATOR_LATE_SEND!");

        }

        afl->fsrv.late_send = el->afl_custom_fuzz_send;
        afl->fsrv.custom_data_ptr = el->data;
        count_send = 1;

      }

    });

  }

  if (afl->limit_time_sig > 0 && afl->custom_mutators_count) {

    if (afl->custom_only) {

      FATAL("Custom mutators are incompatible with MOpt (-L)");

    }

    u32 custom_fuzz = 0;
    LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {

      if (el->afl_custom_fuzz) { custom_fuzz = 1; }

    });

    if (custom_fuzz) {

      WARNF("afl_custom_fuzz is incompatible with MOpt (-L)");

    }

  }

  /* Simply code if AFL_TMPDIR is used or not */
  if (!afl->afl_env.afl_tmpdir) {

    afl->tmp_dir = afl->out_dir;

  } else {

    afl->tmp_dir = afl->afl_env.afl_tmpdir;

  }

  setup_cmdline_file(afl, argv + optind);
  check_binary(afl, argv[optind]);

  u64 prev_target_hash = 0;
  s32 fast_resume = 0;
  #ifdef HAVE_ZLIB
  gzFile fr_fd = NULL;
  #else
  s32 fr_fd = -1;
  #endif

  if (afl->in_place_resume && !afl->afl_env.afl_no_fastresume) {

    u8 fn[PATH_MAX], buf[32];
    snprintf(fn, PATH_MAX, "%s/target_hash", afl->out_dir);
    s32 fd = open(fn, O_RDONLY);
    if (fd >= 0) {

      if (read(fd, buf, 32) >= 16) {

        sscanf(buf, "%p", (void **)&prev_target_hash);

      }

      close(fd);

    }

  }

  write_setup_file(afl, argc, argv);

  if (afl->in_place_resume && !afl->afl_env.afl_no_fastresume) {

  #ifdef __linux__
    u64 target_hash = 0;
    if (afl->fsrv.nyx_mode) {

      nyx_load_target_hash(&afl->fsrv);
      target_hash = afl->fsrv.nyx_target_hash64;

    } else {

      target_hash = get_binary_hash(afl->fsrv.target_path);

    }

  #else
    u64 target_hash = get_binary_hash(afl->fsrv.target_path);
  #endif

    if ((!target_hash || prev_target_hash != target_hash)
  #ifdef __linux__
        || (afl->fsrv.nyx_mode && target_hash == 0)
  #endif
    ) {

      ACTF("Target binary is different, cannot perform FAST RESUME!");

    } else {

      u8 fn[PATH_MAX];
      snprintf(fn, PATH_MAX, "%s/fastresume.bin", afl->out_dir);
  #ifdef HAVE_ZLIB
      if ((fr_fd = ZLIBOPEN(fn, "rb")) != NULL) {

  #else
      if ((fr_fd = open(fn, O_RDONLY)) >= 0) {

  #endif

        u8   ver_string[8];
        u64 *ver = (u64 *)ver_string;
        u64  expect_ver =
            afl->shm.cmplog_mode + (sizeof(struct queue_entry) << 1);

        if (NZLIBREAD(fr_fd, ver_string, sizeof(ver_string)) !=
            sizeof(ver_string))
          WARNF("Emtpy fastresume.bin, ignoring, cannot perform FAST RESUME");
        else if (expect_ver != *ver)
          WARNF(
              "Different AFL++ version or feature usage, cannot perform FAST "
              "RESUME");
        else {

          OKF("Will perform FAST RESUME");
          fast_resume = 1;

        }

      } else {

        ACTF("fastresume.bin not found, cannot perform FAST RESUME!");

      }

      // If the fast resume file is not valid we will be unable to start, so
      // we remove the file but keep the file descriptor open.
      unlink(fn);

    }

  }

  read_testcases(afl, NULL);

  pivot_inputs(afl);

  if (!afl->timeout_given) { find_timeout(afl); }  // only for resumes!

  if (afl->afl_env.afl_tmpdir && !afl->in_place_resume) {

    char tmpfile[PATH_MAX];

    if (afl->file_extension) {

      snprintf(tmpfile, PATH_MAX, "%s/.cur_input.%s", afl->tmp_dir,
               afl->file_extension);

    } else {

      snprintf(tmpfile, PATH_MAX, "%s/.cur_input", afl->tmp_dir);

    }

    /* there is still a race condition here, but well ... */
    if (access(tmpfile, F_OK) != -1) {

      FATAL(
          "AFL_TMPDIR already has an existing temporary input file: %s - if "
          "this is not from another instance, then just remove the file.",
          tmpfile);

    }

  }

  // read_foreign_testcases(afl, 1); for the moment dont do this
  OKF("Loaded a total of %u seeds.", afl->queued_items);

  /* If we don't have a file name chosen yet, use a safe default. */

  if (!afl->fsrv.out_file) {

    u32 j = optind + 1;
    while (argv[j]) {

      u8 *aa_loc = strstr(argv[j], "@@");

      if (aa_loc && !afl->fsrv.out_file) {

        afl->fsrv.use_stdin = 0;
        default_output = 0;

        if (afl->file_extension) {

          afl->fsrv.out_file = alloc_printf("%s/.cur_input.%s", afl->tmp_dir,
                                            afl->file_extension);

        } else {

          afl->fsrv.out_file = alloc_printf("%s/.cur_input", afl->tmp_dir);

        }

        detect_file_args(argv + optind + 1, afl->fsrv.out_file,
                         &afl->fsrv.use_stdin);
        break;

      }

      ++j;

    }

  }

  if (!afl->fsrv.out_file) { setup_stdio_file(afl); }

  if (afl->cmplog_binary) {

    if (afl->unicorn_mode) {

      FATAL("CmpLog and Unicorn mode are not compatible at the moment, sorry");

    }

    if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->fsrv.cs_mode &&
        !afl->non_instrumented_mode) {

      check_binary(afl, afl->cmplog_binary);

    }

  }

  #ifdef AFL_PERSISTENT_RECORD
  if (unlikely(afl->fsrv.persistent_record)) {

    if (!getenv(PERSIST_ENV_VAR) && !getenv("AFL_FRIDA_PERSISTENT_ADDR") &&
        !getenv("AFL_QEMU_PERSISTENT_ADDR")) {

      FATAL(
          "Target binary is not compiled/run in persistent mode, "
          "AFL_PERSISTENT_RECORD makes no sense.");

    }

    afl->fsrv.persistent_record_dir = alloc_printf("%s", afl->out_dir);

  }

  #endif

  if (afl->shmem_testcase_mode) { setup_testcase_shmem(afl); }

  afl->start_time = get_cur_time();

  if (afl->fsrv.qemu_mode) {

    if (afl->use_wine) {

      use_argv = get_wine_argv(argv[0], &afl->fsrv.target_path, argc - optind,
                               argv + optind);

    } else {

      use_argv = get_qemu_argv(argv[0], &afl->fsrv.target_path, argc - optind,
                               argv + optind);

    }

  } else if (afl->fsrv.cs_mode) {

    use_argv = get_cs_argv(argv[0], &afl->fsrv.target_path, argc - optind,
                           argv + optind);

  } else {

    use_argv = argv + optind;

  }

  if (afl->non_instrumented_mode || afl->fsrv.qemu_mode ||
      afl->fsrv.frida_mode || afl->fsrv.cs_mode || afl->unicorn_mode) {

    u32 old_map_size = map_size;
    map_size = afl->fsrv.real_map_size = afl->fsrv.map_size = MAP_SIZE;
    afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size);
    afl->virgin_tmout = ck_realloc(afl->virgin_tmout, map_size);
    afl->virgin_crash = ck_realloc(afl->virgin_crash, map_size);
    afl->var_bytes = ck_realloc(afl->var_bytes, map_size);
    afl->top_rated = ck_realloc(afl->top_rated, map_size * sizeof(void *));
    afl->clean_trace = ck_realloc(afl->clean_trace, map_size);
    afl->clean_trace_custom = ck_realloc(afl->clean_trace_custom, map_size);
    afl->first_trace = ck_realloc(afl->first_trace, map_size);
    afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, map_size);

    if (old_map_size < map_size) {

      memset(afl->var_bytes + old_map_size, 0, map_size - old_map_size);
      memset(afl->top_rated + old_map_size, 0, map_size - old_map_size);
      memset(afl->clean_trace + old_map_size, 0, map_size - old_map_size);
      memset(afl->clean_trace_custom + old_map_size, 0,
             map_size - old_map_size);
      memset(afl->first_trace + old_map_size, 0, map_size - old_map_size);
      memset(afl->map_tmp_buf + old_map_size, 0, map_size - old_map_size);

    }

  }

  afl->argv = use_argv;
  afl->fsrv.trace_bits =
      afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode);

  if (!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
      !afl->unicorn_mode && !afl->fsrv.frida_mode && !afl->fsrv.cs_mode &&
      !afl->afl_env.afl_skip_bin_check) {

    if (map_size <= DEFAULT_SHMEM_SIZE) {

      afl->fsrv.map_size = DEFAULT_SHMEM_SIZE;  // dummy temporary value
      char vbuf[16];
      snprintf(vbuf, sizeof(vbuf), "%u", DEFAULT_SHMEM_SIZE);
      setenv("AFL_MAP_SIZE", vbuf, 1);

    }

    u32 new_map_size = afl_fsrv_get_mapsize(
        &afl->fsrv, afl->argv, &afl->stop_soon, afl->afl_env.afl_debug_child);

    // only reinitialize if the map needs to be larger than what we have.
    if (map_size < new_map_size) {

      OKF("Re-initializing maps to %u bytes", new_map_size);

      u32 old_map_size = map_size;
      afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
      afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
      afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
      afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
      afl->top_rated =
          ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
      afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
      afl->clean_trace_custom =
          ck_realloc(afl->clean_trace_custom, new_map_size);
      afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
      afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);

      if (old_map_size < new_map_size) {

        memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size);
        memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size);
        memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size);
        memset(afl->clean_trace_custom + old_map_size, 0,
               new_map_size - old_map_size);
        memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size);
        memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size);

      }

      afl_fsrv_kill(&afl->fsrv);
      afl_shm_deinit(&afl->shm);
      afl->fsrv.map_size = new_map_size;
      afl->fsrv.trace_bits =
          afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
      setenv("AFL_NO_AUTODICT", "1", 1);  // loaded already
      afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
                     afl->afl_env.afl_debug_child);

      map_size = new_map_size;

    }

  }

  if (afl->cmplog_binary) {

    ACTF("Spawning cmplog forkserver");
    afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv);
    // TODO: this is semi-nice
    afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
    afl->cmplog_fsrv.cs_mode = afl->fsrv.cs_mode;
    afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode;
    afl->cmplog_fsrv.frida_mode = afl->fsrv.frida_mode;
    afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary;
    afl->cmplog_fsrv.target_path = afl->fsrv.target_path;
    afl->cmplog_fsrv.init_child_func = cmplog_exec_child;

    if ((map_size <= DEFAULT_SHMEM_SIZE ||
         afl->cmplog_fsrv.map_size < map_size) &&
        !afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
        !afl->fsrv.frida_mode && !afl->unicorn_mode && !afl->fsrv.cs_mode &&
        !afl->afl_env.afl_skip_bin_check) {

      afl->cmplog_fsrv.map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE);
      char vbuf[16];
      snprintf(vbuf, sizeof(vbuf), "%u", afl->cmplog_fsrv.map_size);
      setenv("AFL_MAP_SIZE", vbuf, 1);

    }

    u32 new_map_size =
        afl_fsrv_get_mapsize(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
                             afl->afl_env.afl_debug_child);

    // only reinitialize when it needs to be larger
    if (map_size < new_map_size) {

      OKF("Re-initializing maps to %u bytes due cmplog", new_map_size);

      u32 old_map_size = map_size;
      afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
      afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
      afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
      afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
      afl->top_rated =
          ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
      afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
      afl->clean_trace_custom =
          ck_realloc(afl->clean_trace_custom, new_map_size);
      afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
      afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);

      if (old_map_size < new_map_size) {

        memset(afl->var_bytes + old_map_size, 0, new_map_size - old_map_size);
        memset(afl->top_rated + old_map_size, 0, new_map_size - old_map_size);
        memset(afl->clean_trace + old_map_size, 0, new_map_size - old_map_size);
        memset(afl->clean_trace_custom + old_map_size, 0,
               new_map_size - old_map_size);
        memset(afl->first_trace + old_map_size, 0, new_map_size - old_map_size);
        memset(afl->map_tmp_buf + old_map_size, 0, new_map_size - old_map_size);

      }

      afl_fsrv_kill(&afl->fsrv);
      afl_fsrv_kill(&afl->cmplog_fsrv);
      afl_shm_deinit(&afl->shm);

      afl->cmplog_fsrv.map_size = new_map_size;  // non-cmplog stays the same
      map_size = new_map_size;

      setenv("AFL_NO_AUTODICT", "1", 1);  // loaded already
      afl->fsrv.trace_bits =
          afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
      afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
      afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
                     afl->afl_env.afl_debug_child);
      afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
                     afl->afl_env.afl_debug_child);

    }

    OKF("CMPLOG forkserver successfully started");

  }

  load_auto(afl);

  if (extras_dir_cnt) {

    for (u8 i = 0; i < extras_dir_cnt; i++) {

      load_extras(afl, extras_dir[i]);

    }

  }

  if (afl->fsrv.out_file && afl->fsrv.use_shmem_fuzz) {

    unlink(afl->fsrv.out_file);
    afl->fsrv.out_file = NULL;
    afl->fsrv.use_stdin = 0;
    close(afl->fsrv.out_fd);
    afl->fsrv.out_fd = -1;

    if (!afl->unicorn_mode && !afl->fsrv.use_stdin && !default_output) {

      WARNF(
          "You specified -f or @@ on the command line but the target harness "
          "specified fuzz cases via shmem, switching to shmem!");

    }

  }

  deunicode_extras(afl);
  dedup_extras(afl);
  if (afl->extras_cnt) { OKF("Loaded a total of %u extras.", afl->extras_cnt); }

  if (unlikely(fast_resume)) {

    u64 resume_start = get_cur_time_us();
    // if we get here then we should abort on errors
    ZLIBREAD(fr_fd, afl->virgin_bits, afl->fsrv.map_size, "virgin_bits");
    ZLIBREAD(fr_fd, afl->virgin_tmout, afl->fsrv.map_size, "virgin_tmout");
    ZLIBREAD(fr_fd, afl->virgin_crash, afl->fsrv.map_size, "virgin_crash");
    ZLIBREAD(fr_fd, afl->var_bytes, afl->fsrv.map_size, "var_bytes");

    u8                  res[1] = {0};
    u8                 *o_start = (u8 *)&(afl->queue_buf[0]->colorized);
    u8                 *o_end = (u8 *)&(afl->queue_buf[0]->mother);
    u32                 r = 8 + afl->fsrv.map_size * 4;
    u32                 q_len = o_end - o_start;
    u32                 m_len = (afl->fsrv.map_size >> 3);
    struct queue_entry *q;

    for (u32 i = 0; i < afl->queued_items; i++) {

      q = afl->queue_buf[i];
      ZLIBREAD(fr_fd, (u8 *)&(q->colorized), q_len, "queue data");
      ZLIBREAD(fr_fd, res, 1, "check map");
      if (res[0]) {

        q->trace_mini = ck_alloc(m_len);
        ZLIBREAD(fr_fd, q->trace_mini, m_len, "trace_mini");
        r += q_len + m_len + 1;

      } else {

        r += q_len + 1;

      }

      afl->total_bitmap_size += q->bitmap_size;
      ++afl->total_bitmap_entries;
      update_bitmap_score(afl, q);

      if (q->was_fuzzed) { --afl->pending_not_fuzzed; }

      if (q->disabled) {

        if (!q->was_fuzzed) { --afl->pending_not_fuzzed; }
        --afl->active_items;

      }

      if (q->var_behavior) { ++afl->queued_variable; }
      if (q->favored) {

        ++afl->queued_favored;
        if (!q->was_fuzzed) { ++afl->pending_favored; }

      }

    }

    u8 buf[4];
    if (NZLIBREAD(fr_fd, buf, 3) > 0) {

      FATAL("invalid trailing data in fastresume.bin");

    }

    OKF("Successfully loaded fastresume.bin (%u bytes)!", r);
    ZLIBCLOSE(fr_fd);
    afl->reinit_table = 1;
    update_calibration_time(afl, &resume_start);

  } else {

    // after we have the correct bitmap size we can read the bitmap -B option
    // and set the virgin maps
    if (afl->in_bitmap) {

      read_bitmap(afl->in_bitmap, afl->virgin_bits, afl->fsrv.map_size);

    } else {

      memset(afl->virgin_bits, 255, map_size);

    }

    memset(afl->virgin_tmout, 255, map_size);
    memset(afl->virgin_crash, 255, map_size);

    if (likely(!afl->afl_env.afl_no_startup_calibration)) {

      perform_dry_run(afl);

    } else {

      ACTF("Skipping initial seed calibration due option override!");
      usleep(1000);

    }

  }

  if (afl->q_testcase_max_cache_entries) {

    afl->q_testcase_cache =
        ck_alloc(afl->q_testcase_max_cache_entries * sizeof(size_t));
    if (!afl->q_testcase_cache) { PFATAL("malloc failed for cache entries"); }

  }

  cull_queue(afl);

  // ensure we have at least one seed that is not disabled.
  u32 entry, valid_seeds = 0;
  for (entry = 0; entry < afl->queued_items; ++entry)
    if (!afl->queue_buf[entry]->disabled) { ++valid_seeds; }

  if (!afl->pending_not_fuzzed || !valid_seeds) {

    FATAL("We need at least one valid input seed that does not crash!");

  }

  if (afl->timeout_given == 2) {  // -t ...+ option

    if (valid_seeds == 1) {

      WARNF(
          "Only one valid seed is present, auto-calculating the timeout is "
          "disabled!");
      afl->timeout_given = 1;

    } else {

      u64 max_ms = 0;

      for (entry = 0; entry < afl->queued_items; ++entry)
        if (!afl->queue_buf[entry]->disabled)
          if ((afl->queue_buf[entry]->exec_us / 1000) > max_ms)
            max_ms = afl->queue_buf[entry]->exec_us / 1000;

      // Add 20% as a safety margin, capped to exec_tmout given in -t option
      max_ms *= 1.2;
      if (max_ms > afl->fsrv.exec_tmout) max_ms = afl->fsrv.exec_tmout;

      // Ensure that there is a sensible timeout even for very fast binaries
      if (max_ms < 5) max_ms = 5;

      afl->fsrv.exec_tmout = max_ms;
      afl->timeout_given = 1;

    }

  }

  show_init_stats(afl);

  if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl);

  afl->start_time = get_cur_time();
  if (afl->in_place_resume || afl->afl_env.afl_autoresume) {

    load_stats_file(afl);

  }

  if (!afl->non_instrumented_mode) { write_stats_file(afl, 0, 0, 0, 0); }
  maybe_update_plot_file(afl, 0, 0, 0);
  save_auto(afl);

  if (afl->stop_soon) { goto stop_fuzzing; }

  /* Woop woop woop */

  if (!afl->not_on_tty) {

    sleep(1);
    if (afl->stop_soon) { goto stop_fuzzing; }

  }

  // (void)nice(-20);  // does not improve the speed

  #ifdef INTROSPECTION
  u32 prev_saved_crashes = 0, prev_saved_tmouts = 0, stat_prev_queued_items = 0;
  #endif
  u32 prev_queued_items = 0, runs_in_current_cycle = (u32)-1;
  u8  skipped_fuzz;

  #ifdef INTROSPECTION
  char ifn[4096];
  snprintf(ifn, sizeof(ifn), "%s/introspection.txt", afl->out_dir);
  if ((afl->introspection_file = fopen(ifn, "w")) == NULL) {

    PFATAL("could not create '%s'", ifn);

  }

  setvbuf(afl->introspection_file, NULL, _IONBF, 0);
  OKF("Writing mutation introspection to '%s'", ifn);
  #endif

  // real start time, we reset, so this works correctly with -V
  afl->start_time = get_cur_time();

  while (likely(!afl->stop_soon)) {

    cull_queue(afl);

    if (unlikely((!afl->old_seed_selection &&
                  runs_in_current_cycle > afl->queued_items) ||
                 (afl->old_seed_selection && !afl->queue_cur))) {

      if (unlikely((afl->last_sync_cycle < afl->queue_cycle ||
                    (!afl->queue_cycle && afl->afl_env.afl_import_first)) &&
                   afl->sync_id)) {

        if (unlikely(!afl->queue_cycle && afl->afl_env.afl_import_first)) {

          OKF("Syncing queues from other fuzzer instances first ...");

        }

        sync_fuzzers(afl);

      }

      ++afl->queue_cycle;
      if (afl->afl_env.afl_no_ui) {

        ACTF("Entering queue cycle %llu\n", afl->queue_cycle);

      }

      runs_in_current_cycle = (u32)-1;
      afl->cur_skipped_items = 0;

      // 1st april fool joke - enable pizza mode
      // to not waste time on checking the date we only do this when the
      // queue is fully cycled.
      time_t     cursec = time(NULL);
      struct tm *curdate = localtime(&cursec);
      if (unlikely(!afl->afl_env.afl_pizza_mode)) {

        if (unlikely(curdate->tm_mon == 3 && curdate->tm_mday == 1)) {

          afl->pizza_is_served = 1;

        } else {

          afl->pizza_is_served = 0;

        }

      }

      if (unlikely(afl->old_seed_selection)) {

        afl->current_entry = 0;
        while (unlikely(afl->current_entry < afl->queued_items &&
                        afl->queue_buf[afl->current_entry]->disabled)) {

          ++afl->current_entry;

        }

        if (afl->current_entry >= afl->queued_items) { afl->current_entry = 0; }

        afl->queue_cur = afl->queue_buf[afl->current_entry];

        if (unlikely(seek_to)) {

          if (unlikely(seek_to >= afl->queued_items)) {

            // This should never happen.
            FATAL("BUG: seek_to location out of bounds!\n");

          }

          afl->current_entry = seek_to;
          afl->queue_cur = afl->queue_buf[seek_to];
          seek_to = 0;

        }

      }

      /* If we had a full queue cycle with no new finds, try
         recombination strategies next. */

      if (unlikely(afl->queued_items == prev_queued
                   /* FIXME TODO BUG: && (get_cur_time() - afl->start_time) >=
                      3600 */
                   )) {

        if (afl->use_splicing) {

          ++afl->cycles_wo_finds;

          if (unlikely(afl->shm.cmplog_mode &&
                       afl->cmplog_max_filesize < MAX_FILE)) {

            afl->cmplog_max_filesize <<= 4;

          }

          switch (afl->expand_havoc) {

            case 0:
              // this adds extra splicing mutation options to havoc mode
              afl->expand_havoc = 1;
              break;
            case 1:
              // add MOpt mutator
              /*
              if (afl->limit_time_sig == 0 && !afl->custom_only &&
                  !afl->python_only) {

                afl->limit_time_sig = -1;
                afl->limit_time_puppet = 0;

              }

              */
              afl->expand_havoc = 2;
              if (afl->cmplog_lvl && afl->cmplog_lvl < 2) afl->cmplog_lvl = 2;
              break;
            case 2:
              // increase havoc mutations per fuzz attempt
              afl->havoc_stack_pow2++;
              afl->expand_havoc = 3;
              break;
            case 3:
              // further increase havoc mutations per fuzz attempt
              afl->havoc_stack_pow2++;
              afl->expand_havoc = 4;
              break;
            case 4:
              afl->expand_havoc = 5;
              // if (afl->cmplog_lvl && afl->cmplog_lvl < 3) afl->cmplog_lvl =
              // 3;
              break;
            case 5:
              // nothing else currently
              break;

          }

        } else {

  #ifndef NO_SPLICING
          afl->use_splicing = 1;
  #else
          afl->use_splicing = 0;
  #endif

        }

      } else {

        afl->cycles_wo_finds = 0;

      }

  #ifdef INTROSPECTION
      {

        u64 cur_time = get_cur_time();
        fprintf(afl->introspection_file,
                "CYCLE cycle=%llu cycle_wo_finds=%llu time_wo_finds=%llu "
                "expand_havoc=%u queue=%u\n",
                afl->queue_cycle, afl->cycles_wo_finds,
                afl->longest_find_time > cur_time - afl->last_find_time
                    ? afl->longest_find_time / 1000
                    : ((afl->start_time == 0 || afl->last_find_time == 0)
                           ? 0
                           : (cur_time - afl->last_find_time) / 1000),
                afl->expand_havoc, afl->queued_items);

      }

  #endif

      if (afl->cycle_schedules) {

        /* we cannot mix non-AFLfast schedules with others */

        switch (afl->schedule) {

          case EXPLORE:
            afl->schedule = EXPLOIT;
            break;
          case EXPLOIT:
            afl->schedule = MMOPT;
            break;
          case MMOPT:
            afl->schedule = SEEK;
            break;
          case SEEK:
            afl->schedule = EXPLORE;
            break;
          case FAST:
            afl->schedule = COE;
            break;
          case COE:
            afl->schedule = LIN;
            break;
          case LIN:
            afl->schedule = QUAD;
            break;
          case QUAD:
            afl->schedule = RARE;
            break;
          case RARE:
            afl->schedule = FAST;
            break;

        }

        // we must recalculate the scores of all queue entries
        for (u32 i = 0; i < afl->queued_items; i++) {

          if (likely(!afl->queue_buf[i]->disabled)) {

            update_bitmap_score(afl, afl->queue_buf[i]);

          }

        }

      }

      prev_queued = afl->queued_items;

    }

    ++runs_in_current_cycle;

    do {

      if (likely(!afl->old_seed_selection)) {

        if (likely(afl->pending_favored && afl->smallest_favored >= 0)) {

          afl->current_entry = afl->smallest_favored;

          /*

                    } else {

                      for (s32 iter = afl->queued_items - 1; iter >= 0; --iter)
             {

                        if (unlikely(afl->queue_buf[iter]->favored &&
                                     !afl->queue_buf[iter]->was_fuzzed)) {

                          afl->current_entry = iter;
                          break;

                        }

                      }

          */

          afl->queue_cur = afl->queue_buf[afl->current_entry];

        } else {

          if (unlikely(prev_queued_items < afl->queued_items ||
                       afl->reinit_table)) {

            // we have new queue entries since the last run, recreate alias
            // table
            prev_queued_items = afl->queued_items;
            create_alias_table(afl);

          }

          do {

            afl->current_entry = select_next_queue_entry(afl);

          } while (unlikely(afl->current_entry >= afl->queued_items));

          afl->queue_cur = afl->queue_buf[afl->current_entry];

        }

      }

      skipped_fuzz = fuzz_one(afl);
  #ifdef INTROSPECTION
      ++afl->queue_cur->stats_selected;

      if (unlikely(skipped_fuzz)) {

        ++afl->queue_cur->stats_skipped;

      } else {

        if (unlikely(afl->queued_items > stat_prev_queued_items)) {

          afl->queue_cur->stats_finds +=
              afl->queued_items - stat_prev_queued_items;
          stat_prev_queued_items = afl->queued_items;

        }

        if (unlikely(afl->saved_crashes > prev_saved_crashes)) {

          afl->queue_cur->stats_crashes +=
              afl->saved_crashes - prev_saved_crashes;
          prev_saved_crashes = afl->saved_crashes;

        }

        if (unlikely(afl->saved_tmouts > prev_saved_tmouts)) {

          afl->queue_cur->stats_tmouts += afl->saved_tmouts - prev_saved_tmouts;
          prev_saved_tmouts = afl->saved_tmouts;

        }

      }

  #endif

      if (unlikely(!afl->stop_soon && exit_1)) { afl->stop_soon = 2; }

      if (unlikely(afl->old_seed_selection)) {

        while (++afl->current_entry < afl->queued_items &&
               afl->queue_buf[afl->current_entry]->disabled) {};
        if (unlikely(afl->current_entry >= afl->queued_items ||
                     afl->queue_buf[afl->current_entry] == NULL ||
                     afl->queue_buf[afl->current_entry]->disabled)) {

          afl->queue_cur = NULL;

        } else {

          afl->queue_cur = afl->queue_buf[afl->current_entry];

        }

      }

    } while (skipped_fuzz && afl->queue_cur && !afl->stop_soon);

    u64 cur_time = get_cur_time();

    if (likely(afl->switch_fuzz_mode && afl->fuzz_mode == 0 &&
               !afl->non_instrumented_mode) &&
        unlikely(cur_time > (likely(afl->last_find_time) ? afl->last_find_time
                                                         : afl->start_time) +
                                afl->switch_fuzz_mode)) {

      if (afl->afl_env.afl_no_ui) {

        ACTF(
            "No new coverage found for %llu seconds, switching to exploitation "
            "strategy.",
            afl->switch_fuzz_mode / 1000);

      }

      afl->fuzz_mode = 1;

    }

    if (likely(!afl->stop_soon && afl->sync_id)) {

      if (unlikely(afl->is_main_node)) {

        if (unlikely(cur_time > (afl->sync_time >> 1) + afl->last_sync_time)) {

          if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) {

            sync_fuzzers(afl);

          }

        }

      } else {

        if (unlikely(cur_time > afl->sync_time + afl->last_sync_time)) {

          if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); }

        }

      }

    }

  }

stop_fuzzing:

  afl->force_ui_update = 1;  // ensure the screen is reprinted
  afl->stop_soon = 1;        // ensure everything is written
  show_stats(afl);           // print the screen one last time
  write_bitmap(afl);
  save_auto(afl);

  #ifdef __AFL_CODE_COVERAGE
  if (afl->fsrv.persistent_trace_bits) {

    char cfn[4096];
    snprintf(cfn, sizeof(cfn), "%s/covmap.dump", afl->out_dir);

    FILE *cov_fd;
    if ((cov_fd = fopen(cfn, "w")) == NULL) {

      PFATAL("could not create '%s'", cfn);

    }

    // Write the real map size, as the map size must exactly match the pointer
    // map in length.
    fwrite(afl->fsrv.persistent_trace_bits, 1, afl->fsrv.real_map_size, cov_fd);
    fclose(cov_fd);

  }

  #endif

  if (afl->pizza_is_served) {

    SAYF(CURSOR_SHOW cLRD "\n\n+++ Baking aborted %s +++\n" cRST,
         afl->stop_soon == 2 ? "programmatically" : "by the chef");

  } else {

    SAYF(CURSOR_SHOW cLRD "\n\n+++ Testing aborted %s +++\n" cRST,
         afl->stop_soon == 2 ? "programmatically" : "by user");

  }

  if (afl->most_time_key == 2) {

    SAYF(cYEL "[!] " cRST "Time limit was reached\n");

  }

  if (afl->most_execs_key == 2) {

    SAYF(cYEL "[!] " cRST "Execution limit was reached\n");

  }

  /* Running for more than 30 minutes but still doing first cycle? */

  if (afl->queue_cycle == 1 &&
      get_cur_time() - afl->start_time > 30 * 60 * 1000) {

    SAYF("\n" cYEL "[!] " cRST
         "Stopped during the first cycle, results may be incomplete.\n"
         "    (For info on resuming, see %s/README.md)\n",
         doc_path);

  }

  if (afl->not_on_tty) {

    u32 t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
    u8  time_tmp[64];
    u_stringify_time_diff(time_tmp, get_cur_time(), afl->start_time);
    ACTF(
        "Statistics: %u new corpus items found, %.02f%% coverage achieved, "
        "%llu crashes saved, %llu timeouts saved, total runtime %s",
        afl->queued_discovered,
        ((double)t_bytes * 100) / afl->fsrv.real_map_size, afl->saved_crashes,
        afl->saved_hangs, time_tmp);

  }

  #ifdef PROFILING
  SAYF(cYEL "[!] " cRST
            "Profiling information: %llu ms total work, %llu ns/run\n",
       time_spent_working / 1000000,
       time_spent_working / afl->fsrv.total_execs);
  #endif

  if (afl->afl_env.afl_final_sync) {

    SAYF(cYEL "[!] " cRST
              "\nPerforming final sync, this make take some time ...\n");
    sync_fuzzers(afl);
    write_bitmap(afl);
    SAYF(cYEL "[!] " cRST "Done!\n\n");

  }

  if (afl->is_main_node) {

    u8 path[PATH_MAX];
    sprintf(path, "%s/is_main_node", afl->out_dir);
    unlink(path);

  }

  if (frida_afl_preload) { ck_free(frida_afl_preload); }

  fclose(afl->fsrv.plot_file);

  #ifdef INTROSPECTION
  fclose(afl->fsrv.det_plot_file);
  #endif

  if (!afl->afl_env.afl_no_fastresume) {

    /* create fastresume.bin */
    u8 fr[PATH_MAX];
    snprintf(fr, PATH_MAX, "%s/fastresume.bin", afl->out_dir);
    ACTF("Writing %s ...", fr);
  #ifdef HAVE_ZLIB
    if ((fr_fd = ZLIBOPEN(fr, "wb9")) != NULL) {

  #else
    if ((fr_fd = open(fr, O_WRONLY | O_TRUNC | O_CREAT, DEFAULT_PERMISSION)) >=
        0) {

  #endif

      u8   ver_string[8];
      u32  w = 0;
      u64 *ver = (u64 *)ver_string;
      *ver = afl->shm.cmplog_mode + (sizeof(struct queue_entry) << 1);

      ZLIBWRITE(fr_fd, ver_string, sizeof(ver_string), "ver_string");
      ZLIBWRITE(fr_fd, afl->virgin_bits, afl->fsrv.map_size, "virgin_bits");
      ZLIBWRITE(fr_fd, afl->virgin_tmout, afl->fsrv.map_size, "virgin_tmout");
      ZLIBWRITE(fr_fd, afl->virgin_crash, afl->fsrv.map_size, "virgin_crash");
      ZLIBWRITE(fr_fd, afl->var_bytes, afl->fsrv.map_size, "var_bytes");
      w += sizeof(ver_string) + afl->fsrv.map_size * 4;

      u8                  on[1] = {1}, off[1] = {0};
      u8                 *o_start = (u8 *)&(afl->queue_buf[0]->colorized);
      u8                 *o_end = (u8 *)&(afl->queue_buf[0]->mother);
      u32                 q_len = o_end - o_start;
      u32                 m_len = (afl->fsrv.map_size >> 3);
      struct queue_entry *q;

      afl->pending_not_fuzzed = afl->queued_items;
      afl->active_items = afl->queued_items;

      for (u32 i = 0; i < afl->queued_items; i++) {

        q = afl->queue_buf[i];
        ZLIBWRITE(fr_fd, (u8 *)&(q->colorized), q_len, "queue data");
        if (!q->trace_mini) {

          ZLIBWRITE(fr_fd, off, 1, "no_mini");
          w += q_len + 1;

        } else {

          ZLIBWRITE(fr_fd, on, 1, "yes_mini");
          ZLIBWRITE(fr_fd, q->trace_mini, m_len, "trace_mini");
          w += q_len + m_len + 1;

        }

      }

      ZLIBCLOSE(fr_fd);
      afl->var_byte_count = count_bytes(afl, afl->var_bytes);
      OKF("Written fastresume.bin with %u bytes!", w);

    } else {

      WARNF("Could not create fastresume.bin");

    }

  }

  destroy_queue(afl);
  destroy_extras(afl);
  destroy_custom_mutators(afl);
  afl_shm_deinit(&afl->shm);

  if (afl->shm_fuzz) {

    afl_shm_deinit(afl->shm_fuzz);
    ck_free(afl->shm_fuzz);

  }

  afl_fsrv_deinit(&afl->fsrv);

  /* remove tmpfile */
  if (!afl->in_place_resume && afl->fsrv.out_file) {

    (void)unlink(afl->fsrv.out_file);

  }

  if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); }
  ck_free(afl->fsrv.target_path);
  ck_free(afl->fsrv.out_file);
  ck_free(afl->sync_id);
  if (afl->q_testcase_cache) { ck_free(afl->q_testcase_cache); }
  afl_state_deinit(afl);
  free(afl);                                                 /* not tracked */

  argv_cpy_free(argv);

  alloc_report();

  OKF("We're done here. Have a nice day!\n");

  exit(0);

}

#endif                                                          /* !AFL_LIB */

