develop_ShangShuo
yangguangmamama 2 months ago
parent 8705567f0a
commit f5ebd5554b

@ -1551,141 +1551,115 @@ static int compare_extras_use_d(const void* p1, const void* p2) {
/* Read extras from a file, sort by size. */
static void load_extras_file(u8* fname, u32* min_len, u32* max_len,
u32 dict_level) {
FILE* f;
u8 buf[MAX_LINE];
u8 *lptr;
u32 cur_line = 0;
// 定义一个函数,用于加载额外的数据文件
static void load_extras_file(u8* fname, u32* min_len, u32* max_len, u32 dict_level) {
FILE* f; // 文件指针
u8 buf[MAX_LINE]; // 用于存储每行数据的缓冲区
u8 *lptr; // 指向当前行数据的指针
u32 cur_line = 0; // 当前行号
// 尝试打开文件,如果失败则打印错误信息并退出
f = fopen(fname, "r");
if (!f) PFATAL("Unable to open '%s'", fname);
// 逐行读取文件内容
while ((lptr = fgets(buf, MAX_LINE, f))) {
u8 *rptr, *wptr; // 指向行数据的指针
u32 klen = 0; // 关键词长度
u8 *rptr, *wptr;
u32 klen = 0;
cur_line++;
/* Trim on left and right. */
cur_line++; // 行号增加
// 去除行首的空白字符
while (isspace(*lptr)) lptr++;
// 去除行尾的空白字符,并找到行尾的结束符
rptr = lptr + strlen(lptr) - 1;
while (rptr >= lptr && isspace(*rptr)) rptr--;
rptr++;
*rptr = 0;
/* Skip empty lines and comments. */
// 跳过空行和注释行
if (!*lptr || *lptr == '#') continue;
/* All other lines must end with '"', which we can consume. */
// 检查行尾是否有双引号,如果没有则报错
rptr--;
if (rptr < lptr || *rptr != '"')
FATAL("Malformed name=\"value\" pair in line %u.", cur_line);
*rptr = 0;
/* Skip alphanumerics and dashes (label). */
*rptr = 0; // 去除行尾的双引号
// 跳过字母数字和下划线(标签)
while (isalnum(*lptr) || *lptr == '_') lptr++;
/* If @number follows, parse that. */
// 如果标签后跟有@数字,则解析该数字
if (*lptr == '@') {
lptr++;
if (atoi(lptr) > dict_level) continue;
while (isdigit(*lptr)) lptr++;
if (atoi(lptr) > dict_level) continue; // 如果数字大于字典级别,则跳过
while (isdigit(*lptr)) lptr++; // 跳过数字
}
/* Skip whitespace and = signs. */
// 跳过空白字符和等号
while (isspace(*lptr) || *lptr == '=') lptr++;
/* Consume opening '"'. */
// 检查等号后是否有双引号,如果没有则报错
if (*lptr != '"')
FATAL("Malformed name=\"keyword\" pair in line %u.", cur_line);
lptr++;
if (!*lptr) FATAL("Empty keyword in line %u.", cur_line);
lptr++; // 跳过双引号
/* Okay, let's allocate memory and copy data between "...", handling
\xNN escaping, \\, and \". */
extras = ck_realloc_block(extras, (extras_cnt + 1) *
sizeof(struct extra_data));
if (!*lptr) FATAL("Empty keyword in line %u.", cur_line); // 检查关键词是否为空
// 分配内存并复制数据,处理转义字符
extras = ck_realloc_block(extras, (extras_cnt + 1) * sizeof(struct extra_data));
wptr = extras[extras_cnt].data = ck_alloc(rptr - lptr);
// 复制数据,处理转义字符
while (*lptr) {
char* hexdigits = "0123456789abcdef";
switch (*lptr) {
case 1 ... 31:
case 128 ... 255:
case 1 ... 31: // 非打印字符
case 128 ... 255: // 非ASCII字符
FATAL("Non-printable characters in line %u.", cur_line);
break;
case '\\':
case '\\': // 处理转义字符
lptr++;
if (*lptr == '\\' || *lptr == '"') {
*(wptr++) = *(lptr++);
*(wptr++) = *(lptr++); // 直接复制转义字符
klen++;
break;
}
if (*lptr != 'x' || !isxdigit(lptr[1]) || !isxdigit(lptr[2]))
FATAL("Invalid escaping (not \\xNN) in line %u.", cur_line);
*(wptr++) =
((strchr(hexdigits, tolower(lptr[1])) - hexdigits) << 4) |
(strchr(hexdigits, tolower(lptr[2])) - hexdigits);
// 处理\xNN形式的转义字符
*(wptr++) = ((strchr(hexdigits, tolower(lptr[1])) - hexdigits) << 4) |
(strchr(hexdigits, tolower(lptr[2])) - hexdigits);
lptr += 3;
klen++;
break;
default:
default: // 复制普通字符
*(wptr++) = *(lptr++);
klen++;
}
}
extras[extras_cnt].len = klen;
extras[extras_cnt].len = klen; // 设置关键词长度
if (extras[extras_cnt].len > MAX_DICT_FILE)
FATAL("Keyword too big in line %u (%s, limit is %s)", cur_line,
DMS(klen), DMS(MAX_DICT_FILE));
DMS(klen), DMS(MAX_DICT_FILE)); // 检查关键词长度是否超过限制
if (*min_len > klen) *min_len = klen;
if (*max_len < klen) *max_len = klen;
extras_cnt++;
if (*min_len > klen) *min_len = klen; // 更新最小长度
if (*max_len < klen) *max_len = klen; // 更新最大长度
extras_cnt++; // 增加额外数据计数
}
fclose(f);
fclose(f); // 关闭文件
}
/* Read extras from the extras directory and sort them by size. */
static void load_extras(u8* dir) {
@ -2573,158 +2547,152 @@ static void show_stats(void);
//start_us, stop_us;
//保存了一些旧的状态值,以便在函数执行完毕后恢复。
// 定义一个用于校准测试用例的函数
static u8 calibrate_case(char** argv, struct queue_entry* q, u8* use_mem,
u32 handicap, u8 from_queue) {
// 定义一个静态数组用于存储第一次执行时的trace bits
static u8 first_trace[MAP_SIZE];
// 定义一些局部变量
u8 fault = 0, new_bits = 0, var_detected = 0, hnb = 0,
first_run = (q->exec_cksum == 0);
// 定义变量用于计时
u64 start_us, stop_us;
// 保存旧的阶段状态
s32 old_sc = stage_cur, old_sm = stage_max;
u32 use_tmout = exec_tmout;
u8* old_sn = stage_name;
/* Be a bit more generous about timeouts when resuming sessions, or when
trying to calibrate already-added finds. This helps avoid trouble due
to intermittent latency. */
//如果是在恢复会话或校准已经添加的测试用例时,会放宽超时限制。
/* 如果是在恢复会话或校准已经添加的测试用例时,会放宽超时限制。
*/
if (!from_queue || resuming_fuzz)
use_tmout = MAX(exec_tmout + CAL_TMOUT_ADD,
exec_tmout * CAL_TMOUT_PERC / 100);
// 增加校准失败计数
q->cal_failed++;
//设置当前阶段为“calibration”并根据是否快速校准设置阶段最大值。
// 设置当前阶段为“calibration”并根据是否快速校准设置阶段最大值
stage_name = "calibration";
stage_max = fast_cal ? 3 : CAL_CYCLES;
/* Make sure the forkserver is up before we do anything, and let's not
count its spin-up time toward binary calibration. */
//如果没有运行在“dumb”模式并且没有使用fork服务器那么初始化fork服务器。
/* 确保在执行任何操作之前fork服务器已经启动并且不将其启动时间计入二进制校准。 */
// 如果没有运行在“dumb”模式并且没有使用fork服务器那么初始化fork服务器
if (dumb_mode != 1 && !no_forkserver && !forksrv_pid)
init_forkserver(argv);
// 如果队列条目已经有执行校验和那么将第一次执行的trace bits复制到first_trace
if (q->exec_cksum) {
//如果队列条目已经有执行校验和那么将第一次执行的trace bits复制到first_trace。
memcpy(first_trace, trace_bits, MAP_SIZE);
hnb = has_new_bits(virgin_bits);
if (hnb > new_bits) new_bits = hnb;
}
start_us = get_cur_time_us();//计时
// 计时开始
start_us = get_cur_time_us();
// 校准循环
for (stage_cur = 0; stage_cur < stage_max; stage_cur++) {
u32 cksum;
// 如果不是第一次运行并且到了更新频率,显示统计信息
if (!first_run && !(stage_cur % stats_update_freq)) show_stats();
//如果不是第一次运行并且到了更新频率,显示统计信息。
write_to_testcase(use_mem, q->len);//将测试用例数据写入文件。
fault = run_target(argv, use_tmout);//运行目标程序并获取执行结果。
// 将测试用例数据写入文件
write_to_testcase(use_mem, q->len);
// 运行目标程序并获取执行结果
fault = run_target(argv, use_tmout);
/* stop_soon is set by the handler for Ctrl+C. When it's pressed,
we want to bail out quickly. */
if (stop_soon || fault != crash_mode) goto abort_calibration;//如果用户请求停止或者执行结果不是崩溃模式,则跳到校准中止。
/* 如果用户按下Ctrl+Cstop_soon会被设置我们希望快速退出。 */
if (stop_soon || fault != crash_mode) goto abort_calibration;
// 如果不是“dumb”模式并且是第一次校准并且没有新的代码覆盖则设置错误为FAULT_NOINST
if (!dumb_mode && !stage_cur && !count_bytes(trace_bits)) {
//如果不是“dumb”模式并且是第一次校准并且没有新的代码覆盖则设置错误为FAULT_NOINST并跳到校准中止。
fault = FAULT_NOINST;
goto abort_calibration;
}
cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST);//计算当前trace bits的哈希值并与队列条目的执行校验和比较
// 计算当前trace bits的哈希值并与队列条目的执行校验和比较
cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST);
if (q->exec_cksum != cksum) {
//如果有新的bits被设置则更新new_bits
// 如果有新的bits被设置则更新new_bits
hnb = has_new_bits(virgin_bits);
if (hnb > new_bits) new_bits = hnb;
if (q->exec_cksum) {//如果队列条目之前有执行校验和,则检查变量字节
// 如果队列条目之前有执行校验和,则检查变量字节
if (q->exec_cksum) {
u32 i;
//对于每个不同的字节,将其标记为变量字节,并增加校准周期
// 对于每个不同的字节,将其标记为变量字节,并增加校准周期
for (i = 0; i < MAP_SIZE; i++) {
if (!var_bytes[i] && first_trace[i] != trace_bits[i]) {
var_bytes[i] = 1;
stage_max = CAL_CYCLES_LONG;
}
}
var_detected = 1;
//如果队列条目之前没有执行校验和则更新其执行校验和并复制当前trace bits。
} else {
// 如果队列条目之前没有执行校验和则更新其执行校验和并复制当前trace bits
q->exec_cksum = cksum;
memcpy(first_trace, trace_bits, MAP_SIZE);
}
}
}
// 计时结束
stop_us = get_cur_time_us();
total_cal_us += stop_us - start_us;//更新总校准时间和周期。
// 更新总校准时间和周期
total_cal_us += stop_us - start_us;
total_cal_cycles += stage_max;
/* OK, let's collect some stats about the performance of this test case.
This is used for fuzzing air time calculations in calculate_score(). */
//更新队列条目的执行时间、位图大小和校准失败计数
/* 收集一些关于这个测试用例性能的统计数据。
calculate_score()fuzzing */
// 更新队列条目的执行时间、位图大小和校准失败计数
q->exec_us = (stop_us - start_us) / stage_max;
q->bitmap_size = count_bytes(trace_bits);
q->handicap = handicap;
q->cal_failed = 0;
total_bitmap_size += q->bitmap_size;//更新总位图大小和条目数
// 更新总位图大小和条目数
total_bitmap_size += q->bitmap_size;
total_bitmap_entries++;
// 更新位图得分
update_bitmap_score(q);
/* If this case didn't result in new output from the instrumentation, tell
parent. This is a non-critical problem, but something to warn the user
about. */
/* 如果这个案例没有产生新的来自仪器的输出,告诉父进程。
*/
if (!dumb_mode && first_run && !fault && !new_bits) fault = FAULT_NOBITS;
abort_calibration:
//如果有新的bits被设置并且队列条目之前没有新覆盖则更新队列条目的新覆盖标志
// 如果有新的bits被设置并且队列条目之前没有新覆盖则更新队列条目的新覆盖标志
if (new_bits == 2 && !q->has_new_cov) {
q->has_new_cov = 1;
queued_with_cov++;
}
/* Mark variable paths. */
/* 标记可变路径。 */
if (var_detected) {
//如果检测到变量行为,则标记队列条目
// 如果检测到变量行为,则标记队列条目
var_byte_count = count_bytes(var_bytes);
if (!q->var_behavior) {
mark_as_variable(q);
queued_variable++;
}
}
//恢复旧的状态值
// 恢复旧的状态值
stage_name = old_sn;
stage_cur = old_sc;
stage_max = old_sm;
if (!first_run) show_stats();//如果校准中止,则跳到函数末尾。
// 如果校准中止,则跳到函数末尾
if (!first_run) show_stats();
// 返回错误代码
return fault;
}

Loading…
Cancel
Save