From 3d0d161d4e5bbac9ffe394dec12af8ef7422ac40 Mon Sep 17 00:00:00 2001 From: Satori5ama <1242330740@qq.com> Date: Thu, 9 Jan 2025 08:29:27 +0800 Subject: [PATCH 1/2] afl-fuzz.c 4500 --- src/afl-fuzz.c | 249 +++++++++++++++++++++++-------------------------- 1 file changed, 118 insertions(+), 131 deletions(-) diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index ff147b5..5b849a9 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -4514,291 +4514,278 @@ static u32 next_p2(u32 val) { static u8 trim_case(char** argv, struct queue_entry* q, u8* in_buf) { - static u8 tmp[64]; - static u8 clean_trace[MAP_SIZE]; + static u8 tmp[64]; // 用于存储临时字符串 + static u8 clean_trace[MAP_SIZE]; // 用于存储干净的trace数据 - u8 needs_write = 0, fault = 0; - u32 trim_exec = 0; - u32 remove_len; - u32 len_p2; + u8 needs_write = 0, fault = 0; // needs_write标记是否需要写入文件,fault标记是否发生错误 + u32 trim_exec = 0; // 记录trim操作的执行次数 + u32 remove_len; // 每次删除的字节长度 + u32 len_p2; // 输入长度的下一个2的幂次方 - /* Although the trimmer will be less useful when variable behavior is - detected, it will still work to some extent, so we don't check for - this. */ + /* 虽然当检测到可变行为时,trimmer的用处会减少,但它仍然会在一定程度上起作用,因此我们不检查这一点。 */ - if (q->len < 5) return 0; + if (q->len < 5) return 0; // 如果输入长度小于5,直接返回,不进行trim操作 - stage_name = tmp; - bytes_trim_in += q->len; + stage_name = tmp; // 设置当前阶段名称为trim + bytes_trim_in += q->len; // 累加输入的总字节数 - /* Select initial chunk len, starting with large steps. */ + /* 选择初始的删除长度,从较大的步长开始。 */ - len_p2 = next_p2(q->len); + len_p2 = next_p2(q->len); // 计算输入长度的下一个2的幂次方 - remove_len = MAX(len_p2 / TRIM_START_STEPS, TRIM_MIN_BYTES); + remove_len = MAX(len_p2 / TRIM_START_STEPS, TRIM_MIN_BYTES); // 计算初始删除长度 - /* Continue until the number of steps gets too high or the stepover - gets too small. */ + /* 继续直到步数过高或步长过小。 */ while (remove_len >= MAX(len_p2 / TRIM_END_STEPS, TRIM_MIN_BYTES)) { - u32 remove_pos = remove_len; + u32 remove_pos = remove_len; // 删除的起始位置 - sprintf(tmp, "trim %s/%s", DI(remove_len), DI(remove_len)); + sprintf(tmp, "trim %s/%s", DI(remove_len), DI(remove_len)); // 格式化阶段名称 - stage_cur = 0; - stage_max = q->len / remove_len; + stage_cur = 0; // 当前阶段执行的次数 + stage_max = q->len / remove_len; // 当前阶段的最大执行次数 - while (remove_pos < q->len) { + while (remove_pos < q->len) { // 遍历输入数据 - u32 trim_avail = MIN(remove_len, q->len - remove_pos); - u32 cksum; + u32 trim_avail = MIN(remove_len, q->len - remove_pos); // 计算实际可删除的字节数 + u32 cksum; // 用于存储trace的校验和 - write_with_gap(in_buf, q->len, remove_pos, trim_avail); + write_with_gap(in_buf, q->len, remove_pos, trim_avail); // 写入带有删除部分的数据 - fault = run_target(argv, exec_tmout); - trim_execs++; + fault = run_target(argv, exec_tmout); // 运行目标程序 + trim_execs++; // 增加trim操作的执行次数 - if (stop_soon || fault == FAULT_ERROR) goto abort_trimming; + if (stop_soon || fault == FAULT_ERROR) goto abort_trimming; // 如果发生错误或停止信号,跳转到abort_trimming - /* Note that we don't keep track of crashes or hangs here; maybe TODO? */ + /* 注意,我们这里不跟踪崩溃或挂起;也许TODO? */ - cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST); // 计算trace的校验和 - /* If the deletion had no impact on the trace, make it permanent. This - isn't perfect for variable-path inputs, but we're just making a - best-effort pass, so it's not a big deal if we end up with false - negatives every now and then. */ + /* 如果删除操作对trace没有影响,则将其永久化。对于可变路径输入,这并不完美,但我们只是尽力而为, + 所以偶尔出现假阴性也没关系。 */ - if (cksum == q->exec_cksum) { + if (cksum == q->exec_cksum) { // 如果校验和与之前的相同 - u32 move_tail = q->len - remove_pos - trim_avail; + u32 move_tail = q->len - remove_pos - trim_avail; // 计算需要移动的尾部字节数 - q->len -= trim_avail; - len_p2 = next_p2(q->len); + q->len -= trim_avail; // 更新输入长度 + len_p2 = next_p2(q->len); // 重新计算下一个2的幂次方 memmove(in_buf + remove_pos, in_buf + remove_pos + trim_avail, - move_tail); + move_tail); // 移动数据,覆盖删除的部分 - /* Let's save a clean trace, which will be needed by - update_bitmap_score once we're done with the trimming stuff. */ + /* 保存一个干净的trace,以便在trim操作完成后更新bitmap_score。 */ - if (!needs_write) { + if (!needs_write) { // 如果还没有保存过干净的trace - needs_write = 1; - memcpy(clean_trace, trace_bits, MAP_SIZE); + needs_write = 1; // 标记需要写入文件 + memcpy(clean_trace, trace_bits, MAP_SIZE); // 保存当前的trace } - } else remove_pos += remove_len; + } else remove_pos += remove_len; // 如果校验和不同,继续下一个删除位置 - /* Since this can be slow, update the screen every now and then. */ + /* 由于这个过程可能很慢,所以每隔一段时间更新屏幕显示。 */ - if (!(trim_exec++ % stats_update_freq)) show_stats(); - stage_cur++; + if (!(trim_exec++ % stats_update_freq)) show_stats(); // 更新统计信息 + stage_cur++; // 增加当前阶段的执行次数 } - remove_len >>= 1; + remove_len >>= 1; // 将删除长度减半 } - /* If we have made changes to in_buf, we also need to update the on-disk - version of the test case. */ + /* 如果对in_buf进行了修改,还需要更新磁盘上的测试用例文件。 */ - if (needs_write) { + if (needs_write) { // 如果需要写入文件 s32 fd; - unlink(q->fname); /* ignore errors */ + unlink(q->fname); /* 忽略错误 */ // 删除旧文件 - fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600); + fd = open(q->fname, O_WRONLY | O_CREAT | O_EXCL, 0600); // 创建新文件 - if (fd < 0) PFATAL("Unable to create '%s'", q->fname); + if (fd < 0) PFATAL("Unable to create '%s'", q->fname); // 如果创建失败,报错 - ck_write(fd, in_buf, q->len, q->fname); - close(fd); + ck_write(fd, in_buf, q->len, q->fname); // 写入数据 + close(fd); // 关闭文件 - memcpy(trace_bits, clean_trace, MAP_SIZE); - update_bitmap_score(q); + memcpy(trace_bits, clean_trace, MAP_SIZE); // 恢复干净的trace + update_bitmap_score(q); // 更新bitmap_score } abort_trimming: - bytes_trim_out += q->len; - return fault; + bytes_trim_out += q->len; // 累加输出的总字节数 + return fault; // 返回错误状态 } -/* Write a modified test case, run program, process results. Handle - error conditions, returning 1 if it's time to bail out. This is - a helper function for fuzz_one(). */ +/* 写入修改后的测试用例,运行程序,处理结果。处理错误条件,如果应该退出则返回1。 + 这是fuzz_one()的辅助函数。 */ EXP_ST u8 common_fuzz_stuff(char** argv, u8* out_buf, u32 len) { u8 fault; - if (post_handler) { + if (post_handler) { // 如果有后处理函数 - out_buf = post_handler(out_buf, &len); - if (!out_buf || !len) return 0; + out_buf = post_handler(out_buf, &len); // 调用后处理函数 + if (!out_buf || !len) return 0; // 如果处理后数据为空,返回0 } - write_to_testcase(out_buf, len); + write_to_testcase(out_buf, len); // 写入测试用例 - fault = run_target(argv, exec_tmout); + fault = run_target(argv, exec_tmout); // 运行目标程序 - if (stop_soon) return 1; + if (stop_soon) return 1; // 如果收到停止信号,返回1 - if (fault == FAULT_TMOUT) { + if (fault == FAULT_TMOUT) { // 如果发生超时 - if (subseq_tmouts++ > TMOUT_LIMIT) { - cur_skipped_paths++; - return 1; + if (subseq_tmouts++ > TMOUT_LIMIT) { // 如果连续超时次数超过限制 + cur_skipped_paths++; // 增加跳过的路径数 + return 1; // 返回1 } - } else subseq_tmouts = 0; + } else subseq_tmouts = 0; // 否则重置连续超时次数 - /* Users can hit us with SIGUSR1 to request the current input - to be abandoned. */ + /* 用户可以通过SIGUSR1信号请求放弃当前输入。 */ - if (skip_requested) { + if (skip_requested) { // 如果收到跳过请求 - skip_requested = 0; - cur_skipped_paths++; - return 1; + skip_requested = 0; // 重置跳过请求 + cur_skipped_paths++; // 增加跳过的路径数 + return 1; // 返回1 } - /* This handles FAULT_ERROR for us: */ + /* 这为我们处理FAULT_ERROR: */ - queued_discovered += save_if_interesting(argv, out_buf, len, fault); + queued_discovered += save_if_interesting(argv, out_buf, len, fault); // 保存有趣的测试用例 - if (!(stage_cur % stats_update_freq) || stage_cur + 1 == stage_max) + if (!(stage_cur % stats_update_freq) || stage_cur + 1 == stage_max) // 更新统计信息 show_stats(); - return 0; + return 0; // 返回0 } + /* Helper to choose random block len for block operations in fuzz_one(). Doesn't return zero, provided that max_len is > 0. */ static u32 choose_block_len(u32 limit) { u32 min_value, max_value; - u32 rlim = MIN(queue_cycle, 3); + u32 rlim = MIN(queue_cycle, 3); // 限制随机选择的范围,最大为3 - if (!run_over10m) rlim = 1; + if (!run_over10m) rlim = 1; // 如果运行时间未超过10分钟,限制随机选择的范围为1 - switch (UR(rlim)) { + switch (UR(rlim)) { // 根据随机数选择块长度的范围 - case 0: min_value = 1; - max_value = HAVOC_BLK_SMALL; + case 0: min_value = 1; // 最小值为1 + max_value = HAVOC_BLK_SMALL; // 最大值为HAVOC_BLK_SMALL break; - case 1: min_value = HAVOC_BLK_SMALL; - max_value = HAVOC_BLK_MEDIUM; + case 1: min_value = HAVOC_BLK_SMALL; // 最小值为HAVOC_BLK_SMALL + max_value = HAVOC_BLK_MEDIUM; // 最大值为HAVOC_BLK_MEDIUM break; default: - if (UR(10)) { + if (UR(10)) { // 90%的概率选择中等大小的块 - min_value = HAVOC_BLK_MEDIUM; - max_value = HAVOC_BLK_LARGE; + min_value = HAVOC_BLK_MEDIUM; // 最小值为HAVOC_BLK_MEDIUM + max_value = HAVOC_BLK_LARGE; // 最大值为HAVOC_BLK_LARGE - } else { + } else { // 10%的概率选择大块 - min_value = HAVOC_BLK_LARGE; - max_value = HAVOC_BLK_XL; + min_value = HAVOC_BLK_LARGE; // 最小值为HAVOC_BLK_LARGE + max_value = HAVOC_BLK_XL; // 最大值为HAVOC_BLK_XL } } - if (min_value >= limit) min_value = 1; + if (min_value >= limit) min_value = 1; // 如果最小值超过限制,则重置为1 - return min_value + UR(MIN(max_value, limit) - min_value + 1); + return min_value + UR(MIN(max_value, limit) - min_value + 1); // 返回在[min_value, max_value]范围内的随机长度 } -/* Calculate case desirability score to adjust the length of havoc fuzzing. - A helper function for fuzz_one(). Maybe some of these constants should - go into config.h. */ +/* 计算案例的期望得分,以调整havoc fuzzing的长度。 + 这是fuzz_one()的辅助函数。也许其中一些常量应该放在config.h中。 */ static u32 calculate_score(struct queue_entry* q) { - u32 avg_exec_us = total_cal_us / total_cal_cycles; - u32 avg_bitmap_size = total_bitmap_size / total_bitmap_entries; - u32 perf_score = 100; + u32 avg_exec_us = total_cal_us / total_cal_cycles; // 计算平均执行时间 + u32 avg_bitmap_size = total_bitmap_size / total_bitmap_entries; // 计算平均位图大小 + u32 perf_score = 100; // 初始得分为100 - /* Adjust score based on execution speed of this path, compared to the - global average. Multiplier ranges from 0.1x to 3x. Fast inputs are - less expensive to fuzz, so we're giving them more air time. */ + /* 根据路径的执行速度调整得分,与全局平均速度相比。乘数范围从0.1x到3x。 + 执行速度快的输入fuzz成本较低,因此我们给予它们更多的执行时间。 */ - if (q->exec_us * 0.1 > avg_exec_us) perf_score = 10; + if (q->exec_us * 0.1 > avg_exec_us) perf_score = 10; // 如果执行时间远高于平均,得分降低 else if (q->exec_us * 0.25 > avg_exec_us) perf_score = 25; else if (q->exec_us * 0.5 > avg_exec_us) perf_score = 50; else if (q->exec_us * 0.75 > avg_exec_us) perf_score = 75; - else if (q->exec_us * 4 < avg_exec_us) perf_score = 300; + else if (q->exec_us * 4 < avg_exec_us) perf_score = 300; // 如果执行时间远低于平均,得分增加 else if (q->exec_us * 3 < avg_exec_us) perf_score = 200; else if (q->exec_us * 2 < avg_exec_us) perf_score = 150; - /* Adjust score based on bitmap size. The working theory is that better - coverage translates to better targets. Multiplier from 0.25x to 3x. */ + /* 根据位图大小调整得分。理论是更好的覆盖率意味着更好的目标。乘数从0.25x到3x。 */ - if (q->bitmap_size * 0.3 > avg_bitmap_size) perf_score *= 3; + if (q->bitmap_size * 0.3 > avg_bitmap_size) perf_score *= 3; // 如果位图大小远高于平均,得分增加 else if (q->bitmap_size * 0.5 > avg_bitmap_size) perf_score *= 2; else if (q->bitmap_size * 0.75 > avg_bitmap_size) perf_score *= 1.5; - else if (q->bitmap_size * 3 < avg_bitmap_size) perf_score *= 0.25; + else if (q->bitmap_size * 3 < avg_bitmap_size) perf_score *= 0.25; // 如果位图大小远低于平均,得分降低 else if (q->bitmap_size * 2 < avg_bitmap_size) perf_score *= 0.5; else if (q->bitmap_size * 1.5 < avg_bitmap_size) perf_score *= 0.75; - /* Adjust score based on handicap. Handicap is proportional to how late - in the game we learned about this path. Latecomers are allowed to run - for a bit longer until they catch up with the rest. */ + /* 根据handicap调整得分。handicap与我们在游戏中了解到此路径的时间成正比。 + 后来者被允许运行更长时间,直到他们赶上其他人。 */ - if (q->handicap >= 4) { + if (q->handicap >= 4) { // 如果handicap大于等于4,得分增加4倍 perf_score *= 4; q->handicap -= 4; - } else if (q->handicap) { + } else if (q->handicap) { // 如果handicap大于0,得分增加2倍 perf_score *= 2; q->handicap--; } - /* Final adjustment based on input depth, under the assumption that fuzzing - deeper test cases is more likely to reveal stuff that can't be - discovered with traditional fuzzers. */ + /* 根据输入深度进行最终调整,假设fuzzing更深的测试用例更有可能揭示传统fuzzer无法发现的内容。 */ switch (q->depth) { - case 0 ... 3: break; - case 4 ... 7: perf_score *= 2; break; - case 8 ... 13: perf_score *= 3; break; - case 14 ... 25: perf_score *= 4; break; - default: perf_score *= 5; + case 0 ... 3: break; // 深度为0到3时不调整得分 + case 4 ... 7: perf_score *= 2; break; // 深度为4到7时得分增加2倍 + case 8 ... 13: perf_score *= 3; break; // 深度为8到13时得分增加3倍 + case 14 ... 25: perf_score *= 4; break; // 深度为14到25时得分增加4倍 + default: perf_score *= 5; // 深度大于25时得分增加5倍 } - /* Make sure that we don't go over limit. */ + /* 确保得分不超过限制。 */ - if (perf_score > HAVOC_MAX_MULT * 100) perf_score = HAVOC_MAX_MULT * 100; + if (perf_score > HAVOC_MAX_MULT * 100) perf_score = HAVOC_MAX_MULT * 100; // 如果得分超过最大限制,则设置为最大限制 - return perf_score; + return perf_score; // 返回最终得分 } + /* Helper function to see if a particular change (xor_val = old ^ new) could be a product of deterministic bit flips with the lengths and stepovers attempted by afl-fuzz. This is used to avoid dupes in some of the -- 2.34.1 From c825f975dde292fe6c2b43e4fc455b9c81b95770 Mon Sep 17 00:00:00 2001 From: Satori5ama <1242330740@qq.com> Date: Thu, 9 Jan 2025 08:32:04 +0800 Subject: [PATCH 2/2] 3500-4500 --- src/.vscode/settings.json | 5 +- src/afl-fuzz.c | 452 ++++++++++++++++++-------------------- 2 files changed, 215 insertions(+), 242 deletions(-) diff --git a/src/.vscode/settings.json b/src/.vscode/settings.json index db0a9aa..717327f 100644 --- a/src/.vscode/settings.json +++ b/src/.vscode/settings.json @@ -11,6 +11,9 @@ "alloc-inl.h": "c", "debug.h": "c", "android-ashmem.h": "c", - "limits": "c" + "limits": "c", + "stdio.h": "c", + "file.h": "c", + "config.h": "c" } } \ No newline at end of file diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 5b849a9..ed45a09 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -3508,14 +3508,17 @@ static void write_stats_file(double bitmap_cvg, double stability, double eps) { static void maybe_update_plot_file(double bitmap_cvg, double eps) { + // 静态变量,用于存储上一次的状态值 static u32 prev_qp, prev_pf, prev_pnf, prev_ce, prev_md; static u64 prev_qc, prev_uc, prev_uh; + // 如果当前状态与上一次状态相同,则直接返回,避免重复更新 if (prev_qp == queued_paths && prev_pf == pending_favored && prev_pnf == pending_not_fuzzed && prev_ce == current_entry && prev_qc == queue_cycle && prev_uc == unique_crashes && prev_uh == unique_hangs && prev_md == max_depth) return; + // 更新上一次的状态值为当前状态值 prev_qp = queued_paths; prev_pf = pending_favored; prev_pnf = pending_not_fuzzed; @@ -3525,56 +3528,25 @@ static void maybe_update_plot_file(double bitmap_cvg, double eps) { prev_uh = unique_hangs; prev_md = max_depth; - /* Fields in the file: - + /* 文件中的字段: unix_time, cycles_done, cur_path, paths_total, paths_not_fuzzed, favored_not_fuzzed, unique_crashes, unique_hangs, max_depth, execs_per_sec */ + // 将当前状态写入绘图文件 fprintf(plot_file, "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f\n", get_cur_time() / 1000, queue_cycle - 1, current_entry, queued_paths, pending_not_fuzzed, pending_favored, bitmap_cvg, unique_crashes, - unique_hangs, max_depth, eps); /* ignore errors */ + unique_hangs, max_depth, eps); /* 忽略错误 */ + // 刷新文件缓冲区,确保数据写入文件 fflush(plot_file); } -/* A helper function for maybe_delete_out_dir(), deleting all prefixed - files in a directory. */ - -static u8 delete_files(u8* path, u8* prefix) { - - DIR* d; - struct dirent* d_ent; - - d = opendir(path); - - if (!d) return 0; - - while ((d_ent = readdir(d))) { - - if (d_ent->d_name[0] != '.' && (!prefix || - !strncmp(d_ent->d_name, prefix, strlen(prefix)))) { - - u8* fname = alloc_printf("%s/%s", path, d_ent->d_name); - if (unlink(fname)) PFATAL("Unable to delete '%s'", fname); - ck_free(fname); - - } - - } - - closedir(d); - - return !!rmdir(path); - -} - - /* Get the number of runnable processes, with some simple smoothing. */ static double get_runnable_processes(void) { @@ -3587,7 +3559,7 @@ static double get_runnable_processes(void) { number of runnable processes; the 1-minute load average can be a semi-decent approximation, though. */ - if (getloadavg(&res, 1) != 1) return 0; + if (getloadavg(&res, 1) != 1) return 0; // 获取1分钟的负载平均值,如果失败则返回0 #else @@ -3595,74 +3567,74 @@ static double get_runnable_processes(void) { computed in funny ways and sometimes don't reflect extremely short-lived processes well. */ - FILE* f = fopen("/proc/stat", "r"); - u8 tmp[1024]; - u32 val = 0; + FILE* f = fopen("/proc/stat", "r"); // 打开/proc/stat文件以读取系统统计信息 + u8 tmp[1024]; // 用于存储读取的每一行内容 + u32 val = 0; // 用于存储当前运行或阻塞的进程数 - if (!f) return 0; + if (!f) return 0; // 如果文件打开失败,返回0 - while (fgets(tmp, sizeof(tmp), f)) { + while (fgets(tmp, sizeof(tmp), f)) { // 逐行读取文件内容 - if (!strncmp(tmp, "procs_running ", 14) || - !strncmp(tmp, "procs_blocked ", 14)) val += atoi(tmp + 14); + if (!strncmp(tmp, "procs_running ", 14) || // 如果行以"procs_running "开头 + !strncmp(tmp, "procs_blocked ", 14)) val += atoi(tmp + 14); // 或者以"procs_blocked "开头,提取数值并累加 } - fclose(f); + fclose(f); // 关闭文件 - if (!res) { + if (!res) { // 如果res为0(即第一次计算) - res = val; + res = val; // 直接将当前值赋给res - } else { + } else { // 否则,进行平滑处理 - res = res * (1.0 - 1.0 / AVG_SMOOTHING) + + res = res * (1.0 - 1.0 / AVG_SMOOTHING) + // 使用平滑公式计算新的res值 ((double)val) * (1.0 / AVG_SMOOTHING); } #endif /* ^(__APPLE__ || __FreeBSD__ || __OpenBSD__) */ - return res; + return res; // 返回计算得到的res值 } /* Delete the temporary directory used for in-place session resume. */ -static void nuke_resume_dir(void) { +static void nuke_resume_dir(void) { // 删除用于恢复会话的临时目录 - u8* fn; + u8* fn; // 用于存储文件路径 - fn = alloc_printf("%s/_resume/.state/deterministic_done", out_dir); - if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; - ck_free(fn); + fn = alloc_printf("%s/_resume/.state/deterministic_done", out_dir); // 构建文件路径 + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; // 删除文件,如果失败则跳转到清理失败处理 + ck_free(fn); // 释放内存 - fn = alloc_printf("%s/_resume/.state/auto_extras", out_dir); - if (delete_files(fn, "auto_")) goto dir_cleanup_failed; - ck_free(fn); + fn = alloc_printf("%s/_resume/.state/auto_extras", out_dir); // 构建文件路径 + if (delete_files(fn, "auto_")) goto dir_cleanup_failed; // 删除文件,如果失败则跳转到清理失败处理 + ck_free(fn); // 释放内存 - fn = alloc_printf("%s/_resume/.state/redundant_edges", out_dir); - if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; - ck_free(fn); + fn = alloc_printf("%s/_resume/.state/redundant_edges", out_dir); // 构建文件路径 + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; // 删除文件,如果失败则跳转到清理失败处理 + ck_free(fn); // 释放内存 - fn = alloc_printf("%s/_resume/.state/variable_behavior", out_dir); - if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; - ck_free(fn); + fn = alloc_printf("%s/_resume/.state/variable_behavior", out_dir); // 构建文件路径 + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; // 删除文件,如果失败则跳转到清理失败处理 + ck_free(fn); // 释放内存 - fn = alloc_printf("%s/_resume/.state", out_dir); - if (rmdir(fn) && errno != ENOENT) goto dir_cleanup_failed; - ck_free(fn); + fn = alloc_printf("%s/_resume/.state", out_dir); // 构建文件路径 + if (rmdir(fn) && errno != ENOENT) goto dir_cleanup_failed; // 删除目录,如果失败且错误不是目录不存在则跳转到清理失败处理 + ck_free(fn); // 释放内存 - fn = alloc_printf("%s/_resume", out_dir); - if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; - ck_free(fn); + fn = alloc_printf("%s/_resume", out_dir); // 构建文件路径 + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; // 删除文件,如果失败则跳转到清理失败处理 + ck_free(fn); // 释放内存 - return; + return; // 成功完成清理,返回 -dir_cleanup_failed: +dir_cleanup_failed: // 清理失败处理 - FATAL("_resume directory cleanup failed"); + FATAL("_resume directory cleanup failed"); // 输出致命错误信息并终止程序 } @@ -3670,51 +3642,52 @@ dir_cleanup_failed: /* Delete fuzzer output directory if we recognize it as ours, if the fuzzer is not currently running, and if the last run time isn't too great. */ -static void maybe_delete_out_dir(void) { +static void maybe_delete_out_dir(void) { // 可能删除fuzzer输出目录 - FILE* f; - u8 *fn = alloc_printf("%s/fuzzer_stats", out_dir); + FILE* f; // 文件指针 + u8 *fn = alloc_printf("%s/fuzzer_stats", out_dir); // 构建文件路径 /* See if the output directory is locked. If yes, bail out. If not, create a lock that will persist for the lifetime of the process (this requires leaving the descriptor open).*/ - out_dir_fd = open(out_dir, O_RDONLY); - if (out_dir_fd < 0) PFATAL("Unable to open '%s'", out_dir); + out_dir_fd = open(out_dir, O_RDONLY); // 打开输出目录 + if (out_dir_fd < 0) PFATAL("Unable to open '%s'", out_dir); // 如果打开失败,输出致命错误信息并终止程序 -#ifndef __sun - if (flock(out_dir_fd, LOCK_EX | LOCK_NB) && errno == EWOULDBLOCK) { +#ifndef __sun // 如果不是在SunOS系统上 - SAYF("\n" cLRD "[-] " cRST + if (flock(out_dir_fd, LOCK_EX | LOCK_NB) && errno == EWOULDBLOCK) { // 尝试对输出目录文件描述符加锁,如果锁被占用且错误码为EWOULDBLOCK + + SAYF("\n" cLRD "[-] " cRST // 输出错误信息 "Looks like the job output directory is being actively used by another\n" " instance of afl-fuzz. You will need to choose a different %s\n" " or stop the other process first.\n", - sync_id ? "fuzzer ID" : "output location"); + sync_id ? "fuzzer ID" : "output location"); // 根据sync_id选择输出不同的提示信息 - FATAL("Directory '%s' is in use", out_dir); + FATAL("Directory '%s' is in use", out_dir); // 输出致命错误信息并退出 } -#endif /* !__sun */ +#endif /* !__sun */ // 结束条件编译 - f = fopen(fn, "r"); + f = fopen(fn, "r"); // 打开文件fn以读取 - if (f) { + if (f) { // 如果文件成功打开 - u64 start_time, last_update; + u64 start_time, last_update; // 定义两个64位无符号整数变量 - if (fscanf(f, "start_time : %llu\n" + if (fscanf(f, "start_time : %llu\n" // 从文件中读取start_time和last_update "last_update : %llu\n", &start_time, &last_update) != 2) - FATAL("Malformed data in '%s'", fn); + FATAL("Malformed data in '%s'", fn); // 如果读取失败,输出致命错误信息并退出 - fclose(f); + fclose(f); // 关闭文件 - /* Let's see how much work is at stake. */ + /* Let's see how much work is at stake. */ // 检查是否有大量工作数据 - if (!in_place_resume && last_update - start_time > OUTPUT_GRACE * 60) { + if (!in_place_resume && last_update - start_time > OUTPUT_GRACE * 60) { // 如果不是原地恢复模式且时间差超过OUTPUT_GRACE分钟 - SAYF("\n" cLRD "[-] " cRST + SAYF("\n" cLRD "[-] " cRST // 输出警告信息 "The job output directory already exists and contains the results of more\n" " than %u minutes worth of fuzzing. To avoid data loss, afl-fuzz will *NOT*\n" " automatically delete this data for you.\n\n" @@ -3724,94 +3697,94 @@ static void maybe_delete_out_dir(void) { " session, put '-' as the input directory in the command line ('-i -') and\n" " try again.\n", OUTPUT_GRACE); - FATAL("At-risk data found in '%s'", out_dir); + FATAL("At-risk data found in '%s'", out_dir); // 输出致命错误信息并退出 } } - ck_free(fn); + ck_free(fn); // 释放fn的内存 /* The idea for in-place resume is pretty simple: we temporarily move the old queue/ to a new location that gets deleted once import to the new queue/ is finished. If _resume/ already exists, the current queue/ may be incomplete due to an earlier abort, so we want to use the old _resume/ - dir instead, and we let rename() fail silently. */ + dir instead, and we let rename() fail silently. */ // 原地恢复的逻辑 - if (in_place_resume) { + if (in_place_resume) { // 如果是原地恢复模式 - u8* orig_q = alloc_printf("%s/queue", out_dir); + u8* orig_q = alloc_printf("%s/queue", out_dir); // 分配内存并格式化字符串 - in_dir = alloc_printf("%s/_resume", out_dir); + in_dir = alloc_printf("%s/_resume", out_dir); // 分配内存并格式化字符串 - rename(orig_q, in_dir); /* Ignore errors */ + rename(orig_q, in_dir); /* Ignore errors */ // 将orig_q重命名为in_dir,忽略错误 - OKF("Output directory exists, will attempt session resume."); + OKF("Output directory exists, will attempt session resume."); // 输出成功信息 - ck_free(orig_q); + ck_free(orig_q); // 释放orig_q的内存 - } else { + } else { // 如果不是原地恢复模式 - OKF("Output directory exists but deemed OK to reuse."); + OKF("Output directory exists but deemed OK to reuse."); // 输出成功信息 } - ACTF("Deleting old session data..."); + ACTF("Deleting old session data..."); // 输出动作信息 /* Okay, let's get the ball rolling! First, we need to get rid of the entries - in /.synced/.../id:*, if any are present. */ + in /.synced/.../id:*, if any are present. */ // 开始清理旧会话数据 - if (!in_place_resume) { + if (!in_place_resume) { // 如果不是原地恢复模式 - fn = alloc_printf("%s/.synced", out_dir); - if (delete_files(fn, NULL)) goto dir_cleanup_failed; - ck_free(fn); + fn = alloc_printf("%s/.synced", out_dir); // 分配内存并格式化字符串 + if (delete_files(fn, NULL)) goto dir_cleanup_failed; // 删除文件,如果失败则跳转到dir_cleanup_failed + ck_free(fn); // 释放fn的内存 } + /* Next, we need to clean up /queue/.state/ subdirectories: */ fn = alloc_printf("%s/queue/.state/deterministic_done", out_dir); - if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; // 删除确定性测试完成标志文件 ck_free(fn); fn = alloc_printf("%s/queue/.state/auto_extras", out_dir); - if (delete_files(fn, "auto_")) goto dir_cleanup_failed; + if (delete_files(fn, "auto_")) goto dir_cleanup_failed; // 删除自动生成的额外文件 ck_free(fn); fn = alloc_printf("%s/queue/.state/redundant_edges", out_dir); - if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; // 删除冗余边文件 ck_free(fn); fn = alloc_printf("%s/queue/.state/variable_behavior", out_dir); - if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; // 删除变量行为文件 ck_free(fn); - /* Then, get rid of the .state subdirectory itself (should be empty by now) - and everything matching /queue/id:*. */ + /* 然后,删除.state子目录本身(此时应该为空) + 并删除所有匹配/queue/id:*的文件。 */ fn = alloc_printf("%s/queue/.state", out_dir); - if (rmdir(fn) && errno != ENOENT) goto dir_cleanup_failed; + if (rmdir(fn) && errno != ENOENT) goto dir_cleanup_failed; // 删除.state目录 ck_free(fn); fn = alloc_printf("%s/queue", out_dir); - if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; // 删除queue目录下的文件 ck_free(fn); - /* All right, let's do /crashes/id:* and /hangs/id:*. */ + /* 接下来,处理/crashes/id:*和/hangs/id:*。 */ if (!in_place_resume) { fn = alloc_printf("%s/crashes/README.txt", out_dir); - unlink(fn); /* Ignore errors */ + unlink(fn); /* 忽略错误 */ // 删除crashes目录下的README.txt文件 ck_free(fn); } fn = alloc_printf("%s/crashes", out_dir); - /* Make backup of the crashes directory if it's not empty and if we're - doing in-place resume. */ + /* 如果crashes目录不为空且正在进行原地恢复,则备份crashes目录。 */ if (in_place_resume && rmdir(fn)) { @@ -3832,17 +3805,17 @@ static void maybe_delete_out_dir(void) { #endif /* ^!SIMPLE_FILES */ - rename(fn, nfn); /* Ignore errors. */ + rename(fn, nfn); /* 忽略错误。 */ // 重命名crashes目录以备份 ck_free(nfn); } - if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; // 删除crashes目录下的文件 ck_free(fn); fn = alloc_printf("%s/hangs", out_dir); - /* Backup hangs, too. */ + /* 同样备份hangs目录。 */ if (in_place_resume && rmdir(fn)) { @@ -3863,53 +3836,49 @@ static void maybe_delete_out_dir(void) { #endif /* ^!SIMPLE_FILES */ - rename(fn, nfn); /* Ignore errors. */ + rename(fn, nfn); /* 忽略错误。 */ // 重命名hangs目录以备份 ck_free(nfn); } - if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; // 删除hangs目录下的文件 ck_free(fn); - /* And now, for some finishing touches. */ + /* 现在,进行一些收尾工作。 */ fn = alloc_printf("%s/.cur_input", out_dir); - if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; + if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; // 删除当前输入文件 ck_free(fn); fn = alloc_printf("%s/fuzz_bitmap", out_dir); - if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; + if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; // 删除fuzz位图文件 ck_free(fn); if (!in_place_resume) { fn = alloc_printf("%s/fuzzer_stats", out_dir); - if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; + if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; // 删除fuzzer统计文件 ck_free(fn); } fn = alloc_printf("%s/plot_data", out_dir); - if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; + if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; // 删除绘图数据文件 ck_free(fn); - OKF("Output dir cleanup successful."); + OKF("Output dir cleanup successful."); // 输出目录清理成功 - /* Wow... is that all? If yes, celebrate! */ + /* 哇...这就完了吗?如果是,庆祝一下! */ return; dir_cleanup_failed: SAYF("\n" cLRD "[-] " cRST - "Whoops, the fuzzer tried to reuse your output directory, but bumped into\n" - " some files that shouldn't be there or that couldn't be removed - so it\n" - " decided to abort! This happened while processing this path:\n\n" + "哎呀,fuzzer试图重用你的输出目录,但遇到了一些不应该存在的文件或无法删除的文件 - 所以它决定中止!这发生在处理以下路径时:\n\n" " %s\n\n" - " Please examine and manually delete the files, or specify a different\n" - " output location for the tool.\n", fn); - - FATAL("Output directory cleanup failed"); + " 请检查并手动删除这些文件,或为工具指定一个不同的输出位置。\n", fn); // 输出目录清理失败的错误信息 + FATAL("Output directory cleanup failed"); // 输出目录清理失败 } @@ -3921,148 +3890,137 @@ static void check_term_size(void); static void show_stats(void) { - static u64 last_stats_ms, last_plot_ms, last_ms, last_execs; - static double avg_exec; - double t_byte_ratio, stab_ratio; - - u64 cur_ms; - u32 t_bytes, t_bits; + static u64 last_stats_ms, last_plot_ms, last_ms, last_execs; // 上一次统计时间、绘图时间、UI更新时间、执行次数 + static double avg_exec; // 平均执行速度 + double t_byte_ratio, stab_ratio; // 字节覆盖率和稳定性比率 - u32 banner_len, banner_pad; - u8 tmp[256]; + u64 cur_ms; // 当前时间 + u32 t_bytes, t_bits; // 非255字节数和非255位数 - cur_ms = get_cur_time(); + u32 banner_len, banner_pad; // 横幅长度和填充 + u8 tmp[256]; // 临时缓冲区 - /* If not enough time has passed since last UI update, bail out. */ + cur_ms = get_cur_time(); // 获取当前时间 + /* 如果距离上一次UI更新的时间不足,直接返回 */ if (cur_ms - last_ms < 1000 / UI_TARGET_HZ) return; - /* Check if we're past the 10 minute mark. */ - + /* 检查是否已经运行超过10分钟 */ if (cur_ms - start_time > 10 * 60 * 1000) run_over10m = 1; - /* Calculate smoothed exec speed stats. */ - + /* 计算平滑的执行速度统计 */ if (!last_execs) { - avg_exec = ((double)total_execs) * 1000 / (cur_ms - start_time); + avg_exec = ((double)total_execs) * 1000 / (cur_ms - start_time); // 初始平均执行速度 } else { double cur_avg = ((double)(total_execs - last_execs)) * 1000 / - (cur_ms - last_ms); - - /* If there is a dramatic (5x+) jump in speed, reset the indicator - more quickly. */ + (cur_ms - last_ms); // 当前平均执行速度 + /* 如果速度有显著变化(5倍以上),快速重置指示器 */ if (cur_avg * 5 < avg_exec || cur_avg / 5 > avg_exec) avg_exec = cur_avg; avg_exec = avg_exec * (1.0 - 1.0 / AVG_SMOOTHING) + - cur_avg * (1.0 / AVG_SMOOTHING); + cur_avg * (1.0 / AVG_SMOOTHING); // 平滑处理 } - last_ms = cur_ms; - last_execs = total_execs; - - /* Tell the callers when to contact us (as measured in execs). */ + last_ms = cur_ms; // 更新上一次UI更新时间 + last_execs = total_execs; // 更新上一次执行次数 + /* 告诉调用者何时联系我们(以执行次数衡量) */ stats_update_freq = avg_exec / (UI_TARGET_HZ * 10); if (!stats_update_freq) stats_update_freq = 1; - /* Do some bitmap stats. */ - - t_bytes = count_non_255_bytes(virgin_bits); - t_byte_ratio = ((double)t_bytes * 100) / MAP_SIZE; + /* 计算一些位图统计 */ + t_bytes = count_non_255_bytes(virgin_bits); // 计算非255字节数 + t_byte_ratio = ((double)t_bytes * 100) / MAP_SIZE; // 计算字节覆盖率 if (t_bytes) - stab_ratio = 100 - ((double)var_byte_count) * 100 / t_bytes; + stab_ratio = 100 - ((double)var_byte_count) * 100 / t_bytes; // 计算稳定性比率 else stab_ratio = 100; - /* Roughly every minute, update fuzzer stats and save auto tokens. */ - + /* 大约每分钟更新一次fuzzer统计并保存自动生成的token */ if (cur_ms - last_stats_ms > STATS_UPDATE_SEC * 1000) { last_stats_ms = cur_ms; - write_stats_file(t_byte_ratio, stab_ratio, avg_exec); - save_auto(); - write_bitmap(); + write_stats_file(t_byte_ratio, stab_ratio, avg_exec); // 写入统计文件 + save_auto(); // 保存自动生成的token + write_bitmap(); // 写入位图 } - /* Every now and then, write plot data. */ - + /* 每隔一段时间,写入绘图数据 */ if (cur_ms - last_plot_ms > PLOT_UPDATE_SEC * 1000) { last_plot_ms = cur_ms; - maybe_update_plot_file(t_byte_ratio, avg_exec); + maybe_update_plot_file(t_byte_ratio, avg_exec); // 更新绘图文件 } - /* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */ - + /* 处理AFL_EXIT_WHEN_DONE和AFL_BENCH_UNTIL_CRASH环境变量 */ if (!dumb_mode && cycles_wo_finds > 100 && !pending_not_fuzzed && getenv("AFL_EXIT_WHEN_DONE")) stop_soon = 2; if (total_crashes && getenv("AFL_BENCH_UNTIL_CRASH")) stop_soon = 2; - /* If we're not on TTY, bail out. */ - + /* 如果不是在TTY上运行,直接返回 */ if (not_on_tty) return; - /* Compute some mildly useful bitmap stats. */ - - t_bits = (MAP_SIZE << 3) - count_bits(virgin_bits); - - /* Now, for the visuals... */ + /* 计算一些有用的位图统计 */ + t_bits = (MAP_SIZE << 3) - count_bits(virgin_bits); // 计算非255位数 + /* 现在,处理视觉效果... */ if (clear_screen) { - SAYF(TERM_CLEAR CURSOR_HIDE); + SAYF(TERM_CLEAR CURSOR_HIDE); // 清屏并隐藏光标 clear_screen = 0; - check_term_size(); + check_term_size(); // 检查终端大小 } - SAYF(TERM_HOME); - if (term_too_small) { + SAYF(TERM_HOME); // 将光标移动到终端窗口的左上角 + + if (term_too_small) { // 检查终端窗口是否太小 SAYF(cBRI "Your terminal is too small to display the UI.\n" - "Please resize terminal window to at least 80x25.\n" cRST); + "Please resize terminal window to at least 80x25.\n" cRST); // 输出提示信息,要求用户调整终端窗口大小 - return; + return; // 如果终端窗口太小,直接返回,不继续绘制UI } - /* Let's start by drawing a centered banner. */ + /* Let's start by drawing a centered banner. */ // 开始绘制居中的横幅 - banner_len = (crash_mode ? 24 : 22) + strlen(VERSION) + strlen(use_banner); - banner_pad = (80 - banner_len) / 2; - memset(tmp, ' ', banner_pad); + banner_len = (crash_mode ? 24 : 22) + strlen(VERSION) + strlen(use_banner); // 计算横幅的总长度,根据是否处于crash_mode调整基础长度 + banner_pad = (80 - banner_len) / 2; // 计算横幅两侧的填充空格数,使横幅居中 + memset(tmp, ' ', banner_pad); // 在tmp数组的前banner_pad个位置填充空格 sprintf(tmp + banner_pad, "%s " cLCY VERSION cLGN " (%s)", crash_mode ? cPIN "peruvian were-rabbit" : - cYEL "american fuzzy lop", use_banner); + cYEL "american fuzzy lop", use_banner); // 格式化横幅内容,包含版本号和banner信息,根据crash_mode选择不同的显示文本 - SAYF("\n%s\n\n", tmp); + SAYF("\n%s\n\n", tmp); // 输出横幅内容,前后添加换行符 - /* "Handy" shortcuts for drawing boxes... */ + /* "Handy" shortcuts for drawing boxes... */ // 定义绘制框的快捷方式 -#define bSTG bSTART cGRA -#define bH2 bH bH -#define bH5 bH2 bH2 bH -#define bH10 bH5 bH5 -#define bH20 bH10 bH10 -#define bH30 bH20 bH10 -#define SP5 " " -#define SP10 SP5 SP5 -#define SP20 SP10 SP10 +#define bSTG bSTART cGRA // 定义bSTG为bSTART和cGRA的组合,用于绘制框的起始部分 +#define bH2 bH bH // 定义bH2为两个bH的组合,用于绘制水平线 +#define bH5 bH2 bH2 bH // 定义bH5为两个bH2和一个bH的组合,用于绘制更长的水平线 +#define bH10 bH5 bH5 // 定义bH10为两个bH5的组合,用于绘制更长的水平线 +#define bH20 bH10 bH10 // 定义bH20为两个bH10的组合,用于绘制更长的水平线 +#define bH30 bH20 bH10 // 定义bH30为一个bH20和一个bH10的组合,用于绘制更长的水平线 +#define SP5 " " // 定义SP5为5个空格,用于填充空白 +#define SP10 SP5 SP5 // 定义SP10为两个SP5的组合,用于填充更多空白 +#define SP20 SP10 SP10 // 定义SP20为两个SP10的组合,用于填充更多空白 + + /* Lord, forgive me this. */ // 注释:主啊,请原谅我这样做(可能是开发者对代码复杂性的调侃) - /* Lord, forgive me this. */ SAYF(SET_G1 bSTG bLT bH bSTOP cCYA " process timing " bSTG bH30 bH5 bH2 bHB bH bSTOP cCYA " overall results " bSTG bH5 bRT "\n"); @@ -4394,42 +4352,51 @@ static void show_stats(void) { static void show_init_stats(void) { - struct queue_entry* q = queue; - u32 min_bits = 0, max_bits = 0; - u64 min_us = 0, max_us = 0; - u64 avg_us = 0; - u32 max_len = 0; + struct queue_entry* q = queue; // 指向队列的当前条目 + u32 min_bits = 0, max_bits = 0; // 最小和最大位图大小 + u64 min_us = 0, max_us = 0; // 最小和最大执行时间(微秒) + u64 avg_us = 0; // 平均执行时间(微秒) + u32 max_len = 0; // 最大测试用例长度 + // 计算平均执行时间 if (total_cal_cycles) avg_us = total_cal_us / total_cal_cycles; + // 遍历队列中的所有条目 while (q) { + // 更新最小执行时间 if (!min_us || q->exec_us < min_us) min_us = q->exec_us; + // 更新最大执行时间 if (q->exec_us > max_us) max_us = q->exec_us; + // 更新最小位图大小 if (!min_bits || q->bitmap_size < min_bits) min_bits = q->bitmap_size; + // 更新最大位图大小 if (q->bitmap_size > max_bits) max_bits = q->bitmap_size; + // 更新最大测试用例长度 if (q->len > max_len) max_len = q->len; - q = q->next; + q = q->next; // 移动到下一个队列条目 } - SAYF("\n"); + SAYF("\n"); // 输出换行符 + // 如果平均执行时间较长,发出警告 if (avg_us > (qemu_mode ? 50000 : 10000)) WARNF(cLRD "The target binary is pretty slow! See %s/perf_tips.txt.", doc_path); - /* Let's keep things moving with slow binaries. */ - + /* 根据平均执行时间调整 havoc_div 的值,以保持测试的进度 */ if (avg_us > 50000) havoc_div = 10; /* 0-19 execs/sec */ else if (avg_us > 20000) havoc_div = 5; /* 20-49 execs/sec */ else if (avg_us > 10000) havoc_div = 2; /* 50-100 execs/sec */ + // 如果不是恢复模式,检查并发出相关警告 if (!resuming_fuzz) { + // 如果测试用例过大,发出警告 if (max_len > 50 * 1024) WARNF(cLRD "Some test cases are huge (%s) - see %s/perf_tips.txt!", DMS(max_len), doc_path); @@ -4437,9 +4404,11 @@ static void show_init_stats(void) { WARNF("Some test cases are big (%s) - see %s/perf_tips.txt.", DMS(max_len), doc_path); + // 如果初始测试用例无用,发出警告 if (useless_at_start && !in_bitmap) WARNF(cLRD "Some test cases look useless. Consider using a smaller set."); + // 如果输入文件过多,发出警告 if (queued_paths > 100) WARNF(cLRD "You probably have far too many input files! Consider trimming down."); else if (queued_paths > 20) @@ -4447,6 +4416,7 @@ static void show_init_stats(void) { } + // 输出有用的统计信息 OKF("Here are some useful stats:\n\n" cGRA " Test case count : " cRST "%u favored, %u variable, %u total\n" @@ -4456,58 +4426,58 @@ static void show_init_stats(void) { ((double)total_bitmap_size) / (total_bitmap_entries ? total_bitmap_entries : 1), DI(min_us), DI(max_us), DI(avg_us)); + // 如果没有指定超时时间,计算并设置默认超时时间 if (!timeout_given) { - /* Figure out the appropriate timeout. The basic idea is: 5x average or - 1x max, rounded up to EXEC_TM_ROUND ms and capped at 1 second. + /* 计算适当的超时时间。基本思路是:5倍平均时间或1倍最大时间, + 向上取整到 EXEC_TM_ROUND 毫秒,并限制在1秒内。 - If the program is slow, the multiplier is lowered to 2x or 3x, because - random scheduler jitter is less likely to have any impact, and because - our patience is wearing thin =) */ + 如果程序较慢,乘数降低到2倍或3倍,因为随机调度抖动不太可能产生影响, + 而且我们的耐心已经不足了 =) */ - if (avg_us > 50000) exec_tmout = avg_us * 2 / 1000; - else if (avg_us > 10000) exec_tmout = avg_us * 3 / 1000; - else exec_tmout = avg_us * 5 / 1000; + if (avg_us > 50000) exec_tmout = avg_us * 2 / 1000; // 如果平均时间大于50000微秒,设置超时为2倍平均时间 + else if (avg_us > 10000) exec_tmout = avg_us * 3 / 1000; // 如果平均时间大于10000微秒,设置超时为3倍平均时间 + else exec_tmout = avg_us * 5 / 1000; // 否则设置超时为5倍平均时间 - exec_tmout = MAX(exec_tmout, max_us / 1000); - exec_tmout = (exec_tmout + EXEC_TM_ROUND) / EXEC_TM_ROUND * EXEC_TM_ROUND; + exec_tmout = MAX(exec_tmout, max_us / 1000); // 取最大值,确保超时时间不小于最大执行时间 + exec_tmout = (exec_tmout + EXEC_TM_ROUND) / EXEC_TM_ROUND * EXEC_TM_ROUND; // 向上取整到 EXEC_TM_ROUND 毫秒 - if (exec_tmout > EXEC_TIMEOUT) exec_tmout = EXEC_TIMEOUT; + if (exec_tmout > EXEC_TIMEOUT) exec_tmout = EXEC_TIMEOUT; // 限制超时时间不超过1秒 ACTF("No -t option specified, so I'll use exec timeout of %u ms.", - exec_tmout); + exec_tmout); // 输出设置的超时时间 - timeout_given = 1; + timeout_given = 1; // 标记超时时间已设置 } else if (timeout_given == 3) { - ACTF("Applying timeout settings from resumed session (%u ms).", exec_tmout); + ACTF("Applying timeout settings from resumed session (%u ms).", exec_tmout); // 应用恢复会话中的超时设置 } - /* In dumb mode, re-running every timing out test case with a generous time - limit is very expensive, so let's select a more conservative default. */ + /* 在 dumb 模式下,重新运行每个超时的测试用例非常昂贵, + 因此选择一个更保守的默认值。 */ if (dumb_mode && !getenv("AFL_HANG_TMOUT")) - hang_tmout = MIN(EXEC_TIMEOUT, exec_tmout * 2 + 100); + hang_tmout = MIN(EXEC_TIMEOUT, exec_tmout * 2 + 100); // 设置 hang_tmout 为较小的值 - OKF("All set and ready to roll!"); + OKF("All set and ready to roll!"); // 输出准备就绪信息 } -/* Find first power of two greater or equal to val (assuming val under - 2^31). */ +/* 找到大于或等于 val 的第一个2的幂(假设 val 小于 2^31)。 */ static u32 next_p2(u32 val) { - u32 ret = 1; - while (val > ret) ret <<= 1; - return ret; + u32 ret = 1; // 初始化 ret 为1 + while (val > ret) ret <<= 1; // 左移直到 ret >= val + return ret; // 返回结果 } + /* Trim all new test cases to save cycles when doing deterministic checks. The trimmer uses power-of-two increments somewhere between 1/16 and 1/1024 of file size, to keep the stage short and sweet. */ -- 2.34.1