|
|
|
@ -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
|
|
|
|
|