diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 04327d7..da5175c 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -71,15 +71,13 @@ # include #endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */ -/* For systems that have sched_setaffinity; right now just Linux, but one - can hope... */ +/* 针对具有 sched_setaffinity 的系统;目前仅限于 Linux,但可以希望... */ #ifdef __linux__ # define HAVE_AFFINITY 1 #endif /* __linux__ */ -/* A toggle to export some variables when building as a library. Not very - useful for the general public. */ +/* 在构建为库时导出一些变量的开关。对公众没有多大用处。 */ #ifdef AFL_LIB # define EXP_ST @@ -87,215 +85,214 @@ # define EXP_ST static #endif /* ^AFL_LIB */ -/* Lots of globals, but mostly for the status UI and other things where it - really makes no sense to haul them around as function parameters. */ - - -EXP_ST u8 *in_dir, /* Input directory with test cases */ - *out_file, /* File to fuzz, if any */ - *out_dir, /* Working & output directory */ - *sync_dir, /* Synchronization directory */ - *sync_id, /* Fuzzer ID */ - *use_banner, /* Display banner */ - *in_bitmap, /* Input bitmap */ - *doc_path, /* Path to documentation dir */ - *target_path, /* Path to target binary */ - *orig_cmdline; /* Original command line */ - -EXP_ST u32 exec_tmout = EXEC_TIMEOUT; /* Configurable exec timeout (ms) */ -static u32 hang_tmout = EXEC_TIMEOUT; /* Timeout used for hang det (ms) */ - -EXP_ST u64 mem_limit = MEM_LIMIT; /* Memory cap for child (MB) */ - -EXP_ST u32 cpu_to_bind = 0; /* id of free CPU core to bind */ - -static u32 stats_update_freq = 1; /* Stats update frequency (execs) */ - -EXP_ST u8 skip_deterministic, /* Skip deterministic stages? */ - force_deterministic, /* Force deterministic stages? */ - use_splicing, /* Recombine input files? */ - dumb_mode, /* Run in non-instrumented mode? */ - score_changed, /* Scoring for favorites changed? */ - kill_signal, /* Signal that killed the child */ - resuming_fuzz, /* Resuming an older fuzzing job? */ - timeout_given, /* Specific timeout given? */ - cpu_to_bind_given, /* Specified cpu_to_bind given? */ - not_on_tty, /* stdout is not a tty */ - term_too_small, /* terminal dimensions too small */ - uses_asan, /* Target uses ASAN? */ - no_forkserver, /* Disable forkserver? */ - crash_mode, /* Crash mode! Yeah! */ - in_place_resume, /* Attempt in-place resume? */ - auto_changed, /* Auto-generated tokens changed? */ - no_cpu_meter_red, /* Feng shui on the status screen */ - no_arith, /* Skip most arithmetic ops */ - shuffle_queue, /* Shuffle input queue? */ - bitmap_changed = 1, /* Time to update bitmap? */ - qemu_mode, /* Running in QEMU mode? */ - skip_requested, /* Skip request, via SIGUSR1 */ - run_over10m, /* Run time over 10 minutes? */ - persistent_mode, /* Running in persistent mode? */ - deferred_mode, /* Deferred forkserver mode? */ - fast_cal; /* Try to calibrate faster? */ - -static s32 out_fd, /* Persistent fd for out_file */ - dev_urandom_fd = -1, /* Persistent fd for /dev/urandom */ - dev_null_fd = -1, /* Persistent fd for /dev/null */ - fsrv_ctl_fd, /* Fork server control pipe (write) */ - fsrv_st_fd; /* Fork server status pipe (read) */ - -static s32 forksrv_pid, /* PID of the fork server */ - child_pid = -1, /* PID of the fuzzed program */ - out_dir_fd = -1; /* FD of the lock file */ - -EXP_ST u8* trace_bits; /* SHM with instrumentation bitmap */ - -EXP_ST u8 virgin_bits[MAP_SIZE], /* Regions yet untouched by fuzzing */ - virgin_tmout[MAP_SIZE], /* Bits we haven't seen in tmouts */ - virgin_crash[MAP_SIZE]; /* Bits we haven't seen in crashes */ - -static u8 var_bytes[MAP_SIZE]; /* Bytes that appear to be variable */ - -static s32 shm_id; /* ID of the SHM region */ - -static volatile u8 stop_soon, /* Ctrl-C pressed? */ - clear_screen = 1, /* Window resized? */ - child_timed_out; /* Traced process timed out? */ - -EXP_ST u32 queued_paths, /* Total number of queued testcases */ - queued_variable, /* Testcases with variable behavior */ - queued_at_start, /* Total number of initial inputs */ - queued_discovered, /* Items discovered during this run */ - queued_imported, /* Items imported via -S */ - queued_favored, /* Paths deemed favorable */ - queued_with_cov, /* Paths with new coverage bytes */ - pending_not_fuzzed, /* Queued but not done yet */ - pending_favored, /* Pending favored paths */ - cur_skipped_paths, /* Abandoned inputs in cur cycle */ - cur_depth, /* Current path depth */ - max_depth, /* Max path depth */ - useless_at_start, /* Number of useless starting paths */ - var_byte_count, /* Bitmap bytes with var behavior */ - current_entry, /* Current queue entry ID */ - havoc_div = 1; /* Cycle count divisor for havoc */ - -EXP_ST u64 total_crashes, /* Total number of crashes */ - unique_crashes, /* Crashes with unique signatures */ - total_tmouts, /* Total number of timeouts */ - unique_tmouts, /* Timeouts with unique signatures */ - unique_hangs, /* Hangs with unique signatures */ - total_execs, /* Total execve() calls */ - slowest_exec_ms, /* Slowest testcase non hang in ms */ - start_time, /* Unix start time (ms) */ - last_path_time, /* Time for most recent path (ms) */ - last_crash_time, /* Time for most recent crash (ms) */ - last_hang_time, /* Time for most recent hang (ms) */ - last_crash_execs, /* Exec counter at last crash */ - queue_cycle, /* Queue round counter */ - cycles_wo_finds, /* Cycles without any new paths */ - trim_execs, /* Execs done to trim input files */ - bytes_trim_in, /* Bytes coming into the trimmer */ - bytes_trim_out, /* Bytes coming outa the trimmer */ - blocks_eff_total, /* Blocks subject to effector maps */ - blocks_eff_select; /* Blocks selected as fuzzable */ - -static u32 subseq_tmouts; /* Number of timeouts in a row */ - -static u8 *stage_name = "init", /* Name of the current fuzz stage */ - *stage_short, /* Short stage name */ - *syncing_party; /* Currently syncing with... */ - -static s32 stage_cur, stage_max; /* Stage progression */ -static s32 splicing_with = -1; /* Splicing with which test case? */ - -static u32 master_id, master_max; /* Master instance job splitting */ - -static u32 syncing_case; /* Syncing with case #... */ - -static s32 stage_cur_byte, /* Byte offset of current stage op */ - stage_cur_val; /* Value used for stage op */ - -static u8 stage_val_type; /* Value type (STAGE_VAL_*) */ - -static u64 stage_finds[32], /* Patterns found per fuzz stage */ - stage_cycles[32]; /* Execs per fuzz stage */ - -static u32 rand_cnt; /* Random number counter */ - -static u64 total_cal_us, /* Total calibration time (us) */ - total_cal_cycles; /* Total calibration cycles */ - -static u64 total_bitmap_size, /* Total bit count for all bitmaps */ - total_bitmap_entries; /* Number of bitmaps counted */ - -static s32 cpu_core_count; /* CPU core count */ +/* 大量全局变量,主要用于状态 UI 和其他地方,在这些地方作为函数参数传递没有意义。 */ + +EXP_ST u8 *in_dir, /* 包含测试用例的输入目录 */ + *out_file, /* 要模糊测试的文件(如果有的话) */ + *out_dir, /* 工作和输出目录 */ + *sync_dir, /* 同步目录 */ + *sync_id, /* 模糊测试器ID */ + *use_banner, /* 显示横幅 */ + *in_bitmap, /* 输入位图 */ + *doc_path, /* 文档目录的路径 */ + *target_path, /* 目标二进制文件的路径 */ + *orig_cmdline; /* 原始命令行 */ + +EXP_ST u32 exec_tmout = EXEC_TIMEOUT; /* 可配置的执行超时(毫秒) */ +static u32 hang_tmout = EXEC_TIMEOUT; /* 用于检测挂起的超时(毫秒) */ + +EXP_ST u64 mem_limit = MEM_LIMIT; /* 子进程的内存限制(MB) */ + +EXP_ST u32 cpu_to_bind = 0; /* 要绑定的空闲CPU核心的ID */ + +static u32 stats_update_freq = 1; /* 统计更新频率(执行次数) */ + +EXP_ST u8 skip_deterministic, /* 是不是跳过确定性阶段? */ + force_deterministic, /* 强制执行确定性阶段? */ + use_splicing, /* 重新组合输入文件? */ + dumb_mode, /* 以非仪器化模式运行? */ + score_changed, /* 喜爱的评分是否改变? */ + kill_signal, /* 杀死子进程的信号 */ + resuming_fuzz, /* 恢复以前的模糊测试作业? */ + timeout_given, /* 是否给定了特定的超时? */ + cpu_to_bind_given, /* 是否给定了指定的 cpu_to_bind? */ + not_on_tty, /* 标准输出不是 tty */ + term_too_small, /* 终端尺寸过小 */ + uses_asan, /* 目标是否使用 ASAN? */ + no_forkserver, /* 是否禁用 forkserver? */ + crash_mode, /* 崩溃模式!是的! */ + in_place_resume, /* 尝试原地恢复? */ + auto_changed, /* 自动生成的标记是否更改? */ + no_cpu_meter_red, /* 状态屏幕的 风水 */ + no_arith, /* 跳过大多数算术操作 */ + shuffle_queue, /* 随机输入队列? */ + bitmap_changed = 1, /* 是否更新位图的时间? */ + qemu_mode, /* 是否在 QEMU 模式下运行? */ + skip_requested, /* 跳过请求,通过 SIGUSR1 发送 */ + run_over10m, /* 运行时间超过 10 分钟? */ + persistent_mode, /* 是否在持久模式下运行? */ + deferred_mode, /* 延迟 forkserver 模式? */ + fast_cal; /* 尝试更快校准? */ + +static s32 out_fd, /* 持久的输出文件描述符 */ + dev_urandom_fd = -1, /* 对 /dev/urandom 的持久文件描述符 */ + dev_null_fd = -1, /* 对 /dev/null 的持久文件描述符 */ + fsrv_ctl_fd, /* Fork 服务器控制管道(写) */ + fsrv_st_fd; /* Fork 服务器状态管道(读) */ + +static s32 forksrv_pid, /* Fork 服务器的 PID */ + child_pid = -1, /* 被模糊测试程序的 PID */ + out_dir_fd = -1; /* 锁文件的文件描述符 */ + +EXP_ST u8* trace_bits; /* 带有仪器的位图的共享内存 */ + +EXP_ST u8 virgin_bits[MAP_SIZE], /* 还未被模糊测试触及的区域 */ + virgin_tmout[MAP_SIZE], /* 我们在超时中未见的位 */ + virgin_crash[MAP_SIZE]; /* 我们在崩溃中未见的位 */ + +static u8 var_bytes[MAP_SIZE]; /* 似乎是可变的字节 */ + +static s32 shm_id; /* 共享内存区域的 ID */ + +static volatile u8 stop_soon, /* 按下了 Ctrl-C? */ + clear_screen = 1, /* 窗口被调整大小? */ + child_timed_out; /* 被跟踪的进程超时? */ + +EXP_ST u32 queued_paths, /* 排队测试用例的总数 */ + queued_variable, /* 具有可变行为的测试用例 */ + queued_at_start, /* 初始输入的总数 */ + queued_discovered, /* 此次运行中发现的项目 */ + queued_imported, /* 通过 -S 导入的项目 */ + queued_favored, /* 被认为是有利的路径 */ + queued_with_cov, /* 带有新覆盖字节的路径 */ + pending_not_fuzzed, /* 排队但尚未完成的测试用例 */ + pending_favored, /* 待处理的有利路径 */ + cur_skipped_paths, /* 当前周期中放弃的输入 */ + cur_depth, /* 当前路径深度 */ + max_depth, /* 最大路径深度 */ + useless_at_start, /* 无用的起始路径的数量 */ + var_byte_count, /* 具有可变行为的位图字节数 */ + current_entry, /* 当前队列条目的 ID */ + havoc_div = 1; /* 恶劣周期计数的除数 */ + +EXP_ST u64 total_crashes, /* 崩溃的总数 */ + unique_crashes, /* 具有唯一签名的崩溃 */ + total_tmouts, /* 超时的总数 */ + unique_tmouts, /* 具有唯一签名的超时 */ + unique_hangs, /* 具有唯一签名的挂起 */ + total_execs, /* 执行 execve() 调用的总数 */ + slowest_exec_ms, /* 非挂起的最慢测试用例(毫秒) */ + start_time, /* Unix 开始时间(毫秒) */ + last_path_time, /* 最近路径的时间(毫秒) */ + last_crash_time, /* 最近崩溃的时间(毫秒) */ + last_hang_time, /* 最近挂起的时间(毫秒) */ + last_crash_execs, /* 最近崩溃时的执行计数 */ + queue_cycle, /* 队列轮次计数 */ + cycles_wo_finds, /* 没有新路径的周期 */ + trim_execs, /* 用于修剪输入文件的执行次数 */ + bytes_trim_in, /* 进入修剪器的字节数 */ + bytes_trim_out, /* 从修剪器输出的字节数 */ + blocks_eff_total, /* 受效应器映射影响的块总数 */ + blocks_eff_select; /* 被选择为模糊测试的块 */ + +static u32 subseq_tmouts; /* 连续超时的次数 */ + +static u8 *stage_name = "init", /* 当前模糊阶段的名称 */ + *stage_short, /* 短阶段名称 */ + *syncing_party; /* 当前正在同步的对象 */ + +static s32 stage_cur, stage_max; /* 阶段进度 */ +static s32 splicing_with = -1; /* 正在与哪个测试用例拼接? */ + +static u32 master_id, master_max; /* 主实例的作业分割 */ + +static u32 syncing_case; /* 正在同步的案例编号... */ + +static s32 stage_cur_byte, /* 当前阶段操作的字节偏移 */ + stage_cur_val; /* 用于阶段操作的值 */ + +static u8 stage_val_type; /* 值的类型(STAGE_VAL_*) */ + +static u64 stage_finds[32], /* 每个模糊阶段找到的模式 */ + stage_cycles[32]; /* 每个模糊阶段的执行次数 */ + +static u32 rand_cnt; /* 随机数计数器 */ + +static u64 total_cal_us, /* 总校准时间(微秒) */ + total_cal_cycles; /* 总校准周期 */ + +static u64 total_bitmap_size, /* 所有位图的总位数 */ + total_bitmap_entries; /* 计数的位图数量 */ + +static s32 cpu_core_count; /* CPU核心数量 */ #ifdef HAVE_AFFINITY -static s32 cpu_aff = -1; /* Selected CPU core */ +static s32 cpu_aff = -1; /* 选定的CPU核心 */ #endif /* HAVE_AFFINITY */ -static FILE* plot_file; /* Gnuplot output file */ +static FILE* plot_file; /* Gnuplot 输出文件 */ struct queue_entry { - u8* fname; /* File name for the test case */ - u32 len; /* Input length */ + u8* fname; /* 测试用例的文件名 */ + u32 len; /* 输入长度 */ - u8 cal_failed, /* Calibration failed? */ - trim_done, /* Trimmed? */ - was_fuzzed, /* Had any fuzzing done yet? */ - passed_det, /* Deterministic stages passed? */ - has_new_cov, /* Triggers new coverage? */ - var_behavior, /* Variable behavior? */ - favored, /* Currently favored? */ - fs_redundant; /* Marked as redundant in the fs? */ + u8 cal_failed, /* 校准失败? */ + trim_done, /* 已修剪? */ + was_fuzzed, /* 是否已进行过模糊测试? */ + passed_det, /* 是否通过了确定性阶段? */ + has_new_cov, /* 是否触发了新的覆盖? */ + var_behavior, /* 是否具有可变行为? */ + favored, /* 当前是否被看作有利? */ + fs_redundant; /* 是否在文件系统中标记为冗余? */ - u32 bitmap_size, /* Number of bits set in bitmap */ - exec_cksum; /* Checksum of the execution trace */ + u32 bitmap_size, /* 位图中设置的位数 */ + exec_cksum; /* 执行跟踪的校验和 */ - u64 exec_us, /* Execution time (us) */ - handicap, /* Number of queue cycles behind */ - depth; /* Path depth */ + u64 exec_us, /* 执行时间(微秒) */ + handicap, /* 排队周期落后的数量 */ + depth; /* 路径深度 */ - u8* trace_mini; /* Trace bytes, if kept */ - u32 tc_ref; /* Trace bytes ref count */ + u8* trace_mini; /* 如果保留的跟踪字节 */ + u32 tc_ref; /* 跟踪字节引用计数 */ - struct queue_entry *next, /* Next element, if any */ - *next_100; /* 100 elements ahead */ + struct queue_entry *next, /* 下一个元素(如果有的话) */ + *next_100; /* 100个元素之前的标记 */ }; -static struct queue_entry *queue, /* Fuzzing queue (linked list) */ - *queue_cur, /* Current offset within the queue */ - *queue_top, /* Top of the list */ - *q_prev100; /* Previous 100 marker */ +static struct queue_entry *queue, /* 模糊测试队列(链表) */ + *queue_cur, /* 当前队列中的偏移 */ + *queue_top, /* 列表的顶部 */ + *q_prev100; /* 前一个100个的标记 */ static struct queue_entry* - top_rated[MAP_SIZE]; /* Top entries for bitmap bytes */ + top_rated[MAP_SIZE]; /* 用于位图字节的顶级条目 */ struct extra_data { - u8* data; /* Dictionary token data */ - u32 len; /* Dictionary token length */ - u32 hit_cnt; /* Use count in the corpus */ + u8* data; /* 字典标记数据 */ + u32 len; /* 字典标记长度 */ + u32 hit_cnt; /* 在语料库中的使用计数 */ }; -static struct extra_data* extras; /* Extra tokens to fuzz with */ -static u32 extras_cnt; /* Total number of tokens read */ +static struct extra_data* extras; /* 用于模糊测试的额外标记 */ +static u32 extras_cnt; /* 读取的标记总数 */ -static struct extra_data* a_extras; /* Automatically selected extras */ -static u32 a_extras_cnt; /* Total number of tokens available */ +static struct extra_data* a_extras; /* 自动选择的额外标记 */ +static u32 a_extras_cnt; /* 可用的额外标记总数 */ static u8* (*post_handler)(u8* buf, u32* len); -/* Interesting values, as per config.h */ +/* 根据 config.h 的有趣值 */ static s8 interesting_8[] = { INTERESTING_8 }; static s16 interesting_16[] = { INTERESTING_8, INTERESTING_16 }; static s32 interesting_32[] = { INTERESTING_8, INTERESTING_16, INTERESTING_32 }; -/* Fuzzing stages */ + +/* 模糊测试阶段 */ enum { /* 00 */ STAGE_FLIP1, @@ -317,7 +314,7 @@ enum { /* 16 */ STAGE_SPLICE }; -/* Stage value types */ +/* 阶段值类型 */ enum { /* 00 */ STAGE_VAL_NONE, @@ -325,7 +322,7 @@ enum { /* 02 */ STAGE_VAL_BE }; -/* Execution status fault codes */ +/* 执行状态故障码 */ enum { /* 00 */ FAULT_NONE, @@ -337,7 +334,7 @@ enum { }; -/* Get unix time in milliseconds */ +/* 获取当前 UNIX 时间(毫秒) */ static u64 get_cur_time(void) { @@ -351,7 +348,7 @@ static u64 get_cur_time(void) { } -/* Get unix time in microseconds */ +/* 获取当前 UNIX 时间(微秒) */ static u64 get_cur_time_us(void) { @@ -365,8 +362,7 @@ static u64 get_cur_time_us(void) { } -/* Generate a random number (from 0 to limit - 1). This may - have slight bias. */ +/* 生成一个随机数(范围从 0 到 limit - 1)。这可能有轻微的偏差。 */ static inline u32 UR(u32 limit) { @@ -386,7 +382,7 @@ static inline u32 UR(u32 limit) { } -/* Shuffle an array of pointers. Might be slightly biased. */ +/* 随机打乱指针数组。可能会有轻微的偏差。 */ static void shuffle_ptrs(void** ptrs, u32 cnt) { @@ -406,8 +402,8 @@ static void shuffle_ptrs(void** ptrs, u32 cnt) { #ifdef HAVE_AFFINITY -/* Build a list of processes bound to specific cores. Returns -1 if nothing - can be found. Assumes an upper bound of 4k CPUs. */ +/* 构建一个绑定到特定核心的进程列表。如果找不到返回 -1。 + 假设最多 4k 个 CPU。 */ static void bind_to_free_cpu(void) { @@ -422,7 +418,7 @@ static void bind_to_free_cpu(void) { if (getenv("AFL_NO_AFFINITY")) { - WARNF("Not binding to a CPU core (AFL_NO_AFFINITY set)."); + WARNF("未绑定到 CPU 核心(设置了 AFL_NO_AFFINITY)。"); return; } @@ -431,22 +427,20 @@ static void bind_to_free_cpu(void) { if (!d) { - WARNF("Unable to access /proc - can't scan for free CPU cores."); + WARNF("无法访问 /proc - 无法扫描空闲 CPU 核心。"); return; } - ACTF("Checking CPU core loadout..."); + ACTF("检查 CPU 核心负载..."); - /* Introduce some jitter, in case multiple AFL tasks are doing the same - thing at the same time... */ + /* 引入一些抖动,以防多个 AFL 任务同时执行相同的操作... */ usleep(R(1000) * 250); - /* Scan all /proc//status entries, checking for Cpus_allowed_list. - Flag all processes bound to a specific CPU using cpu_used[]. This will - fail for some exotic binding setups, but is likely good enough in almost - all real-world use cases. */ + /* 扫描所有 /proc//status 条目,检查 Cpus_allowed_list。 + 使用 cpu_used[] 标记所有绑定到特定 CPU 的进程。这对某些特殊绑定设置可能失败, + 但在几乎所有真实世界的用例中都可能足够好。 */ while ((de = readdir(d))) { @@ -468,7 +462,7 @@ static void bind_to_free_cpu(void) { u32 hval; - /* Processes without VmSize are probably kernel tasks. */ + /* 没有 VmSize 的进程可能是内核任务。 */ if (!strncmp(tmp, "VmSize:\t", 8)) has_vmsize = 1; @@ -493,10 +487,10 @@ static void bind_to_free_cpu(void) { if (cpu_to_bind_given) { if (cpu_to_bind >= cpu_core_count) - FATAL("The CPU core id to bind should be between 0 and %u", cpu_core_count - 1); + FATAL("要绑定的 CPU 核心 ID 应该在 0 到 %u 之间", cpu_core_count - 1); if (cpu_used[cpu_to_bind]) - FATAL("The CPU core #%u to bind is not free!", cpu_to_bind); + FATAL("要绑定的 CPU 核心 #%u 不可用!", cpu_to_bind); i = cpu_to_bind; @@ -509,17 +503,16 @@ static void bind_to_free_cpu(void) { if (i == cpu_core_count) { SAYF("\n" cLRD "[-] " cRST - "Uh-oh, looks like all %u CPU cores on your system are allocated to\n" - " other instances of afl-fuzz (or similar CPU-locked tasks). Starting\n" - " another fuzzer on this machine is probably a bad plan, but if you are\n" - " absolutely sure, you can set AFL_NO_AFFINITY and try again.\n", + "糟糕,似乎系统上所有 %u 个 CPU 核心都分配给了\n" + " 其他的 afl-fuzz 实例(或类似的 CPU 锁定任务)。在此机器上启动\n" + " 另一个模糊测试器可能是个坏主意,但如果您绝对确定,可以设置 AFL_NO_AFFINITY 并重试。\n", cpu_core_count); - FATAL("No more free CPU cores"); + FATAL("没有更多空闲的 CPU 核心"); } - OKF("Found a free CPU core, binding to #%u.", i); + OKF("找到一个空闲的 CPU 核心,绑定到 #%u。", i); cpu_aff = i; @@ -527,7 +520,7 @@ static void bind_to_free_cpu(void) { CPU_SET(i, &c); if (sched_setaffinity(0, sizeof(c), &c)) - PFATAL("sched_setaffinity failed"); + PFATAL("sched_setaffinity 失败"); } @@ -535,8 +528,8 @@ static void bind_to_free_cpu(void) { #ifndef IGNORE_FINDS -/* Helper function to compare buffers; returns first and last differing offset. We - use this to find reasonable locations for splicing two files. */ +/* 辅助函数用于比较缓冲区;返回第一个和最后一个不同的偏移量。 + 我们用这个来找到拼接两个文件的合理位置。 */ static void locate_diffs(u8* ptr1, u8* ptr2, u32 len, s32* first, s32* last) { @@ -565,9 +558,9 @@ static void locate_diffs(u8* ptr1, u8* ptr2, u32 len, s32* first, s32* last) { #endif /* !IGNORE_FINDS */ -/* Describe integer. Uses 12 cyclic static buffers for return values. The value - returned should be five characters or less for all the integers we reasonably - expect to see. */ + +/* 描述整数。使用 12 个循环的静态缓冲区来返回值。 + 返回的值对于我们合理预期看到的所有整数应不超过五个字符。 */ static u8* DI(u64 val) { @@ -610,7 +603,7 @@ static u8* DI(u64 val) { /* 100G - 999G */ CHK_FORMAT(1000LL * 1000 * 1000, 1000, "%lluG", u64); - /* 1.00T - 9.99G */ + /* 1.00T - 9.99T */ CHK_FORMAT(1000LL * 1000 * 1000 * 1000, 9.995, "%0.02fT", double); /* 10.0T - 99.9T */ @@ -623,8 +616,7 @@ static u8* DI(u64 val) { } -/* Describe float. Similar to the above, except with a single - static buffer. */ +/* 描述浮点数。与上述类似,只是使用单个静态缓冲区。 */ static u8* DF(double val) { @@ -645,7 +637,7 @@ static u8* DF(double val) { } -/* Describe integer as memory size. */ +/* 将整数描述为内存大小。 */ static u8* DMS(u64 val) { @@ -681,7 +673,7 @@ static u8* DMS(u64 val) { /* 100G - 999G */ CHK_FORMAT(1024LL * 1024 * 1024, 1000, "%llu GB", u64); - /* 1.00T - 9.99G */ + /* 1.00T - 9.99T */ CHK_FORMAT(1024LL * 1024 * 1024 * 1024, 9.995, "%0.02f TB", double); /* 10.0T - 99.9T */ @@ -696,7 +688,7 @@ static u8* DMS(u64 val) { } -/* Describe time delta. Returns one static buffer, 34 chars of less. */ +/* 描述时间间隔。返回一个静态缓冲区,最多 34 个字符。 */ static u8* DTD(u64 cur_ms, u64 event_ms) { @@ -704,7 +696,7 @@ static u8* DTD(u64 cur_ms, u64 event_ms) { u64 delta; s32 t_d, t_h, t_m, t_s; - if (!event_ms) return "none seen yet"; + if (!event_ms) return "尚未看到任何"; delta = cur_ms - event_ms; @@ -713,15 +705,14 @@ static u8* DTD(u64 cur_ms, u64 event_ms) { t_m = (delta / 1000 / 60) % 60; t_s = (delta / 1000) % 60; - sprintf(tmp, "%s days, %u hrs, %u min, %u sec", DI(t_d), t_h, t_m, t_s); + sprintf(tmp, "%s 天, %u 小时, %u 分, %u 秒", DI(t_d), t_h, t_m, t_s); return tmp; } -/* Mark deterministic checks as done for a particular queue entry. We use the - .state file to avoid repeating deterministic fuzzing when resuming aborted - scans. */ +/* 为特定队列项标记确定性检查为完成。我们使用 .state 文件来避免 + 在恢复中断扫描时重复执行确定性模糊。 */ static void mark_as_det_done(struct queue_entry* q) { @@ -731,7 +722,7 @@ static void mark_as_det_done(struct queue_entry* q) { fn = alloc_printf("%s/queue/.state/deterministic_done/%s", out_dir, fn + 1); fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (fd < 0) PFATAL("Unable to create '%s'", fn); + if (fd < 0) PFATAL("无法创建 '%s'", fn); close(fd); ck_free(fn); @@ -741,8 +732,7 @@ static void mark_as_det_done(struct queue_entry* q) { } -/* Mark as variable. Create symlinks if possible to make it easier to examine - the files. */ +/* 标记为变量。如果可能,创建符号链接以便于检查文件。 */ static void mark_as_variable(struct queue_entry* q) { @@ -754,7 +744,7 @@ static void mark_as_variable(struct queue_entry* q) { if (symlink(ldest, fn)) { s32 fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (fd < 0) PFATAL("Unable to create '%s'", fn); + if (fd < 0) PFATAL("无法创建 '%s'", fn); close(fd); } @@ -767,8 +757,8 @@ static void mark_as_variable(struct queue_entry* q) { } -/* Mark / unmark as redundant (edge-only). This is not used for restoring state, - but may be useful for post-processing datasets. */ +/* 标记/取消标记为冗余(仅边缘)。这不用于恢复状态, + 但可能对于后处理数据集有用。 */ static void mark_as_redundant(struct queue_entry* q, u8 state) { @@ -785,12 +775,12 @@ static void mark_as_redundant(struct queue_entry* q, u8 state) { if (state) { fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (fd < 0) PFATAL("Unable to create '%s'", fn); + if (fd < 0) PFATAL("无法创建 '%s'", fn); close(fd); } else { - if (unlink(fn)) PFATAL("Unable to remove '%s'", fn); + if (unlink(fn)) PFATAL("无法删除 '%s'", fn); } @@ -799,7 +789,7 @@ static void mark_as_redundant(struct queue_entry* q, u8 state) { } -/* Append new test case to the queue. */ +/* 将新的测试用例追加到队列中。 */ static void add_to_queue(u8* fname, u32 len, u8 passed_det) { @@ -824,7 +814,7 @@ static void add_to_queue(u8* fname, u32 len, u8 passed_det) { cycles_wo_finds = 0; - /* Set next_100 pointer for every 100th element (index 0, 100, etc) to allow faster iteration. */ + /* 为每第 100 个元素设置 next_100 指针(索引 0、100 等),以便更快的迭代。 */ if ((queued_paths - 1) % 100 == 0 && queued_paths > 1) { q_prev100->next_100 = q; @@ -837,7 +827,7 @@ static void add_to_queue(u8* fname, u32 len, u8 passed_det) { } -/* Destroy the entire queue. */ +/* 销毁整个队列。 */ EXP_ST void destroy_queue(void) { @@ -855,7 +845,6 @@ EXP_ST void destroy_queue(void) { } - /* Write bitmap to file. The bitmap is useful mostly for the secret -B option, to focus a separate fuzzing session on a particular interesting input without rediscovering all the others. */ @@ -7775,7 +7764,6 @@ static void save_cmdline(u32 argc, char** argv) { /* Main entry point */ -// 主函数,程序的入口点 int main(int argc, char** argv) { s32 opt; @@ -7789,114 +7777,94 @@ int main(int argc, char** argv) { struct timeval tv; struct timezone tz; - SAYF(cCYA "afl-fuzz " cBRI VERSION cRST " by \n"); -} + SAYF(cCYA "afl-fuzz " cBRI VERSION cRST " by \n"); + + doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; + + gettimeofday(&tv, &tz); + srandom(tv.tv_sec ^ tv.tv_usec ^ getpid()); + + // argv 处理 + while ((opt = getopt(argc, argv, "+i:o:f:m:b:t:T:dnCB:S:M:x:QV")) > 0) + + switch (opt) { + + case 'i': /* input dir */ + + // 初始 corpus 目录 + if (in_dir) FATAL("Multiple -i options not supported"); + in_dir = optarg; + + // 若使用 "-i -",则表示 in-place resume + if (!strcmp(in_dir, "-")) in_place_resume = 1; + + break; + + case 'o': /* output dir */ + + if (out_dir) FATAL("Multiple -o options not supported"); + out_dir = optarg; + break; + + case 'M': { /* master sync ID */ + + u8* c; + + if (sync_id) FATAL("Multiple -S or -M options not supported"); + sync_id = ck_strdup(optarg); + + if ((c = strchr(sync_id, ':'))) { + + *c = 0; + + if (sscanf(c + 1, "%u/%u", &master_id, &master_max) != 2 || + !master_id || !master_max || master_id > master_max || + master_max > 1000000) FATAL("Bogus master ID passed to -M"); - /*************************************************************** - * 函数/方法: 主程序的参数处理 - * 描述: 该段代码负责解析命令行参数,并对输入输出目录、文件、同步ID以及超时等选项进行处理和验证。 - ***************************************************************/ - - doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; - - gettimeofday(&tv, &tz); - srandom(tv.tv_sec ^ tv.tv_usec ^ getpid()); - - // argv 处理 - while ((opt = getopt(argc, argv, "+i:o:f:m:b:t:T:dnCB:S:M:x:QV")) > 0) - - switch (opt) { - - case 'i': /* input dir */ - - // 初始 corpus 目录 - if (in_dir) FATAL("Multiple -i options not supported"); - in_dir = optarg; - - // 若使用 "-i -",则表示 in-place resume - if (!strcmp(in_dir, "-")) in_place_resume = 1; - - break; - - /* 处理输出目录的命令行选项 */ - case 'o': /* output dir */ - - if (out_dir) FATAL("Multiple -o options not supported"); - out_dir = optarg; - break; - - case 'M': { /* master sync ID */ - // 处理选项 'M',用于设定主同步 ID - - u8* c; - - if (sync_id) FATAL("Multiple -S or -M options not supported"); - sync_id = ck_strdup(optarg); - - if ((c = strchr(sync_id, ':'))) { - // 解析同步ID中的主ID和最大ID - - *c = 0; - - if (sscanf(c + 1, "%u/%u", &master_id, &master_max) != 2 || - !master_id || !master_max || master_id > master_max || - master_max > 1000000) FATAL("Bogus master ID passed to -M"); - - } - - force_deterministic = 1; - // 强制使用确定性执行 - } - + + force_deterministic = 1; + + } + + break; + + case 'S': + + if (sync_id) FATAL("Multiple -S or -M options not supported"); + sync_id = ck_strdup(optarg); + break; + + case 'f': /* target file */ + + if (out_file) FATAL("Multiple -f options not supported"); + out_file = optarg; + break; + + case 'x': /* dictionary */ + + if (extras_dir) FATAL("Multiple -x options not supported"); + extras_dir = optarg; + break; + + case 't': { /* timeout */ + + u8 suffix = 0; + + if (timeout_given) FATAL("Multiple -t options not supported"); + + if (sscanf(optarg, "%u%c", &exec_tmout, &suffix) < 1 || + optarg[0] == '-') FATAL("Bad syntax used for -t"); + + if (exec_tmout < 5) FATAL("Dangerously low value of -t"); + + if (suffix == '+') timeout_given = 2; else timeout_given = 1; + break; - - // 处理-S选项的代码逻辑 - /************************************************************************************ - * 该代码处理不同命令行选项的解析,包括同步ID、目标文件和字典目录等。 * - * 当检测到重复的选项时,程序会调用FATAL函数报错。 * - ************************************************************************************/ - case 'S': - - if (sync_id) FATAL("Multiple -S or -M options not supported"); - sync_id = ck_strdup(optarg); - break; - - case 'f': /* target file */ - - if (out_file) FATAL("Multiple -f options not supported"); - out_file = optarg; - break; - - case 'x': /* dictionary */ - - if (extras_dir) FATAL("Multiple -x options not supported"); - extras_dir = optarg; - break; - - /************************************** - * 处理命令行选项中与超时相关的参数 - * 支持-t选项,用于设置执行超时时间 - **************************************/ - case 't': { /* timeout */ - - u8 suffix = 0; - - if (timeout_given) FATAL("Multiple -t options not supported"); - - if (sscanf(optarg, "%u%c", &exec_tmout, &suffix) < 1 || - optarg[0] == '-') FATAL("Bad syntax used for -t"); - - if (exec_tmout < 5) FATAL("Dangerously low value of -t"); - - if (suffix == '+') timeout_given = 2; else timeout_given = 1; - - break; - - } + + } case 'm': { /* mem limit */ - // 处理内存限制选项的相关逻辑 u8 suffix = 'M'; @@ -7904,16 +7872,15 @@ int main(int argc, char** argv) { mem_limit_given = 1; if (!strcmp(optarg, "none")) { - // 如果选项参数为"none",则将内存限制设置为0 + mem_limit = 0; break; + } - // 解析命令行参数,获取内存限制和单位后缀 if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 || optarg[0] == '-') FATAL("Bad syntax used for -m"); - // 根据单位后缀调整内存限制的值 switch (suffix) { case 'T': mem_limit *= 1024 * 1024; break; @@ -7925,10 +7892,8 @@ int main(int argc, char** argv) { } - // 检查内存限制值是否低于安全阈值 if (mem_limit < 5) FATAL("Dangerously low value of -m"); - // 在32位系统上检查内存限制的范围 if (sizeof(rlim_t) == 4 && mem_limit > 2000) FATAL("Value of -m out of range on 32-bit systems"); @@ -7937,11 +7902,10 @@ int main(int argc, char** argv) { break; case 'b': { /* bind CPU core */ - // 处理 CPU 绑定选项,确保只能使用一次 + if (cpu_to_bind_given) FATAL("Multiple -b options not supported"); cpu_to_bind_given = 1; - // 解析用户输入的 CPU 核心编号,检查输入合法性 if (sscanf(optarg, "%u", &cpu_to_bind) < 1 || optarg[0] == '-') FATAL("Bad syntax used for -b"); @@ -7949,7 +7913,6 @@ int main(int argc, char** argv) { } - /* 处理命令行参数,选择跳过确定性测试的选项 */ case 'd': /* skip deterministic */ if (skip_deterministic) FATAL("Multiple -d options not supported"); @@ -7958,19 +7921,24 @@ int main(int argc, char** argv) { break; case 'B': /* load bitmap */ - /* - 该代码段处理加载位图的选项。 - 位图功能是一个未文档化的选项,适用于在正常模糊测试过程中找到有趣的测试用例后,进行变异而不重新发现先前运行中已找到的测试用例。 - 使用此模式时,需要将 -B 指向之前运行相同二进制文件生成的 fuzz_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 (in_bitmap) FATAL("Multiple -B options not supported"); in_bitmap = optarg; read_bitmap(in_bitmap); break; - /* 处理命令行参数选项 'C',用于设置崩溃模式 */ case 'C': /* crash mode */ if (crash_mode) FATAL("Multiple -C options not supported"); @@ -7978,34 +7946,27 @@ int main(int argc, char** argv) { break; case 'n': /* dumb mode */ - // 处理-dumb模式的选项,当程序收到'-n'时触发 - + if (dumb_mode) FATAL("Multiple -n options not supported"); if (getenv("AFL_DUMB_FORKSRV")) dumb_mode = 2; else dumb_mode = 1; break; - /* 处理命令行选项 */ case 'T': /* banner */ - /* 检查是否支持多个 -T 选项 */ if (use_banner) FATAL("Multiple -T options not supported"); use_banner = optarg; break; - // 处理QEMU模式的代码段 - // 如果启用QEMU模式,检查是否已指定多个-Q选项 - // 如果未指定内存限制,则使用默认的QEMU内存限制 - // 在处理完成后退出switch语句 - case 'Q': /* QEMU mode */ - - if (qemu_mode) FATAL("Multiple -Q options not supported"); - qemu_mode = 1; - - if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU; - - break; - /* 处理选项 'V' 的情况,显示版本号 */ + case 'Q': /* QEMU mode */ + + if (qemu_mode) FATAL("Multiple -Q options not supported"); + qemu_mode = 1; + + if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU; + + break; + case 'V': /* Show version number */ /* Version number has been printed already, just quit. */ @@ -8017,57 +7978,44 @@ int main(int argc, char** argv) { } - // 检查命令行参数以及输入输出目录是否有效,若无效则显示使用方法 - if (optind == argc || !in_dir || !out_dir) usage(argv[0]); - - // 设置信号处理函数 - setup_signal_handlers(); - // 检查地址卫生选项 - check_asan_opts(); - - // 处理同步ID和目录检查的逻辑 - // 该段代码主要用于验证输入输出目录及模式的有效性 - // 在不同的运行模式下进行相应的错误处理 - - if (sync_id) fix_up_sync(); - - if (!strcmp(in_dir, out_dir)) - FATAL("Input and output directories can't be the same"); - - if (dumb_mode) { - - if (crash_mode) FATAL("-C and -n are mutually exclusive"); - if (qemu_mode) FATAL("-Q and -n are mutually exclusive"); - - } + if (optind == argc || !in_dir || !out_dir) usage(argv[0]); - // 该代码段用于读取环境变量并根据其值设置相应的标志和超时值 - // 主要功能是启动时配置这些参数以调整程序的行为 - if (getenv("AFL_NO_FORKSRV")) no_forkserver = 1; - if (getenv("AFL_NO_CPU_RED")) no_cpu_meter_red = 1; - if (getenv("AFL_NO_ARITH")) no_arith = 1; - if (getenv("AFL_SHUFFLE_QUEUE")) shuffle_queue = 1; - if (getenv("AFL_FAST_CAL")) fast_cal = 1; - - if (getenv("AFL_HANG_TMOUT")) { - hang_tmout = atoi(getenv("AFL_HANG_TMOUT")); - if (!hang_tmout) FATAL("Invalid value of AFL_HANG_TMOUT"); - } + setup_signal_handlers(); + check_asan_opts(); - // 此函数用于检查环境变量和启动模式的合法性 - // 如果在不支持的模式下使用互斥选项,则会引发致命错误 - // 处理环境变量以确保正确的库加载 - - if (dumb_mode == 2 && no_forkserver) - FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive"); - - if (getenv("AFL_PRELOAD")) { - setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); - setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); - } - - if (getenv("AFL_LD_PRELOAD")) - FATAL("Use AFL_PRELOAD instead of AFL_LD_PRELOAD"); + if (sync_id) fix_up_sync(); + + if (!strcmp(in_dir, out_dir)) + FATAL("Input and output directories can't be the same"); + + if (dumb_mode) { + + if (crash_mode) FATAL("-C and -n are mutually exclusive"); + if (qemu_mode) FATAL("-Q and -n are mutually exclusive"); + + } + + if (getenv("AFL_NO_FORKSRV")) no_forkserver = 1; + if (getenv("AFL_NO_CPU_RED")) no_cpu_meter_red = 1; + if (getenv("AFL_NO_ARITH")) no_arith = 1; + if (getenv("AFL_SHUFFLE_QUEUE")) shuffle_queue = 1; + if (getenv("AFL_FAST_CAL")) fast_cal = 1; + + if (getenv("AFL_HANG_TMOUT")) { + hang_tmout = atoi(getenv("AFL_HANG_TMOUT")); + if (!hang_tmout) FATAL("Invalid value of AFL_HANG_TMOUT"); + } + + if (dumb_mode == 2 && no_forkserver) + FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive"); + + if (getenv("AFL_PRELOAD")) { + setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); + setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); + } + + if (getenv("AFL_LD_PRELOAD")) + FATAL("Use AFL_PRELOAD instead of AFL_LD_PRELOAD"); save_cmdline(argc, argv); @@ -8078,142 +8026,104 @@ int main(int argc, char** argv) { get_core_count(); #ifdef HAVE_AFFINITY - // 将当前进程绑定到一个空闲的CPU上,以优化性能 bind_to_free_cpu(); #endif /* HAVE_AFFINITY */ -/* 检查崩溃处理机制 */ check_crash_handling(); -/* 检查CPU调节器设置 */ check_cpu_governor(); -/* 设置后处理操作 */ setup_post(); -/* 设置共享内存 */ setup_shm(); -/* 初始化计数类16 */ init_count_class16(); -/* 设置目录和文件描述符 */ setup_dirs_fds(); -/* 读取测试用例 */ read_testcases(); -/* 加载自动化设置 */ load_auto(); -/* 处理输入的转换 */ pivot_inputs(); - // 此代码段为 afl-fuzz.c 文件中的初始化和参数处理部分 - // 主要功能是配置执行环境并检查传入的文件参数 - // 包括加载额外目录、查找超时、检测文件参数、设置输出文件、检查二进制文件及获取当前时间 - - if (extras_dir) load_extras(extras_dir); - - if (!timeout_given) find_timeout(); - - detect_file_args(argv + optind + 1); - - if (!out_file) setup_stdio_file(); - - check_binary(argv[optind]); - - start_time = get_cur_time(); - - if (qemu_mode) - use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind); - else - use_argv = argv + optind; - /* - * 此函数实现了模糊测试的初始步骤,包括执行干运行、清理队列、 - * 显示初始化统计信息、寻找起始位置并写入统计文件。 - */ - perform_dry_run(use_argv); - - cull_queue(); - - show_init_stats(); - - seek_to = find_start_position(); - - write_stats_file(0, 0, 0); - save_auto(); - - /* - * 如果状态指示测试需要停止,则跳转到停止模糊测试的标签。 - */ + if (extras_dir) load_extras(extras_dir); + + if (!timeout_given) find_timeout(); + + detect_file_args(argv + optind + 1); + + if (!out_file) setup_stdio_file(); + + check_binary(argv[optind]); + + start_time = get_cur_time(); + + if (qemu_mode) + use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind); + else + use_argv = argv + optind; + + perform_dry_run(use_argv); + + cull_queue(); + + show_init_stats(); + + seek_to = find_start_position(); + + write_stats_file(0, 0, 0); + save_auto(); + + if (stop_soon) goto stop_fuzzing; + + /* Woop woop woop */ + + if (!not_on_tty) { + sleep(4); + start_time += 4000; if (stop_soon) goto stop_fuzzing; - - /* Woop woop woop */ - - /* - * 如果不是在终端上运行,则暂停4秒,增加开始时间。 - */ - if (!not_on_tty) { - sleep(4); - start_time += 4000; - /* - * 再次检查是否需要停止模糊测试。 - */ - if (stop_soon) goto stop_fuzzing; - } + } - // 该段代码实现了一个持续循环,处理模糊测试队列中的条目。 while (1) { - - u8 skipped_fuzz; - - // 清理当前模糊测试队列 - cull_queue(); - - if (!queue_cur) { - - // 如果当前队列为空,增加队列周期计数 - queue_cycle++; - current_entry = 0; - cur_skipped_paths = 0; - queue_cur = queue; - - // 根据指定的跳过路径数量,定位到队列中的特定条目 - while (seek_to) { - current_entry++; - seek_to--; - queue_cur = queue_cur->next; - } - - // 显示当前状态统计 - show_stats(); - - if (not_on_tty) { - // 在非终端模式下,输出当前队列周期信息 - ACTF("Entering queue cycle %llu.", queue_cycle); - fflush(stdout); - } + + u8 skipped_fuzz; + + cull_queue(); + + if (!queue_cur) { + + queue_cycle++; + current_entry = 0; + cur_skipped_paths = 0; + queue_cur = queue; + + while (seek_to) { + current_entry++; + seek_to--; + queue_cur = queue_cur->next; + } + + show_stats(); + + if (not_on_tty) { + ACTF("Entering queue cycle %llu.", queue_cycle); + fflush(stdout); + } /* If we had a full queue cycle with no new finds, try recombination strategies next. */ - // 检查当前队列路径是否与前一个队列路径相同 if (queued_paths == prev_queued) { - // 根据是否使用拼接,决定增加无发现循环次数或启用拼接 if (use_splicing) cycles_wo_finds++; else use_splicing = 1; } else cycles_wo_finds = 0; - // 更新前一个队列路径值 prev_queued = queued_paths; - // 检查同步ID,队列循环和环境变量以同步模糊测试器 if (sync_id && queue_cycle == 1 && getenv("AFL_IMPORT_FIRST")) sync_fuzzers(use_argv); } - // 执行模糊测试 skipped_fuzz = fuzz_one(use_argv); - // 如果没有停止标志且没有跳过模糊测试,根据同步间隔决定是否同步 if (!stop_soon && sync_id && !skipped_fuzz) { if (!(sync_interval_cnt++ % SYNC_INTERVAL)) @@ -8221,47 +8131,38 @@ int main(int argc, char** argv) { } - // 如果没有停止标志且 exit_1 为真,则设置停止标志 if (!stop_soon && exit_1) stop_soon = 2; - // 如果设置了停止标志,则跳出循环 if (stop_soon) break; - // 更新当前队列指针和当前条目计数 - queue_cur = queue_cur->next; - current_entry++; + queue_cur = queue_cur->next; + current_entry++; } - /* - * 该段代码用于处理程序终止的情况,包括被程序控制的终止和手动终止。 - * 在终止时会杀死子进程和forkserver,并等待forkserver获取资源使用统计信息。 - * 此外,还会写入位图和统计文件以保存当前状态。 - */ - if (queue_cur) show_stats(); - - /* If we stopped programmatically, we kill the forkserver and the current runner. - If we stopped manually, this is done by the signal handler. */ - if (stop_soon == 2) { - if (child_pid > 0) kill(child_pid, SIGKILL); - if (forksrv_pid > 0) kill(forksrv_pid, SIGKILL); - } - /* Now that we've killed the forkserver, we wait for it to be able to get rusage stats. */ - if (waitpid(forksrv_pid, NULL, 0) <= 0) { - WARNF("error waitpid\n"); - } - - write_bitmap(); - write_stats_file(0, 0, 0); - save_auto(); + if (queue_cur) show_stats(); + + /* If we stopped programmatically, we kill the forkserver and the current runner. + If we stopped manually, this is done by the signal handler. */ + if (stop_soon == 2) { + if (child_pid > 0) kill(child_pid, SIGKILL); + if (forksrv_pid > 0) kill(forksrv_pid, SIGKILL); + } + /* Now that we've killed the forkserver, we wait for it to be able to get rusage stats. */ + if (waitpid(forksrv_pid, NULL, 0) <= 0) { + WARNF("error waitpid\n"); + } + + write_bitmap(); + write_stats_file(0, 0, 0); + save_auto(); -/* 停止模糊测试的函数 */ stop_fuzzing: SAYF(CURSOR_SHOW cLRD "\n\n+++ Testing aborted %s +++\n" cRST, stop_soon == 2 ? "programmatically" : "by user"); - /* 运行超过30分钟但仍在进行第一次周期? */ + /* Running for more than 30 minutes but still doing first cycle? */ if (queue_cycle == 1 && get_cur_time() - start_time > 30 * 60 * 1000) { @@ -8286,3 +8187,4 @@ stop_fuzzing: } #endif /* !AFL_LIB */ +