“18670363079” 2 months ago
commit 0319921f2d

@ -0,0 +1,18 @@
{
"configurations": [
{
"name": "windows-gcc-x86",
"includePath": [
"${workspaceFolder}/**"
],
"compilerPath": "C:/Program Files/MinGW/bin/gcc.exe",
"cStandard": "${default}",
"cppStandard": "${default}",
"intelliSenseMode": "windows-gcc-x86",
"compilerArgs": [
""
]
}
],
"version": 4
}

File diff suppressed because it is too large Load Diff

@ -14,6 +14,8 @@
limitations under the License.
*/
// 这部分是版权声明和许可证信息说明这个文件是在Apache License 2.0下发布的。
/*
american fuzzy lop - wrapper for GCC and clang
----------------------------------------------
@ -38,7 +40,7 @@
specify its location via AFL_CC or AFL_CXX.
*/
// 这部分是注释,提供了关于这个程序的概述和使用说明。
#define AFL_MAIN
#include "config.h"
@ -51,6 +53,8 @@
#include <stdlib.h>
#include <string.h>
// 这些是包含的头文件其中一些是AFL自己的头文件其他的是C标准库的头文件
static u8* as_path; /* Path to the AFL 'as' wrapper */
static u8** cc_params; /* Parameters passed to the real CC */
static u32 cc_par_cnt = 1; /* Param count, including argv0 */
@ -58,11 +62,14 @@ static u8 be_quiet, /* Quiet mode */
clang_mode; /* Invoked as afl-clang*? */
// 这些是全局变量声明。`as_path`存储AFL汇编器的路径`cc_params`存储传递给实际编译器的参数,`cc_par_cnt`是参数计数器,`be_quiet`用于控制
// 是否静默模式,`clang_mode`指示是否以`afl-clang`或`afl-clang++`模式调用。
/* Try to find our "fake" GNU assembler in AFL_PATH or at the location derived
from argv[0]. If that fails, abort. */
static void find_as(u8* argv0) {
// 这个函数尝试在AFL_PATH环境变量指定的路径或从argv[0]派生的路径中找到AFL的“假”GNU汇编器。如果找不到程序将终止。
u8 *afl_path = getenv("AFL_PATH");
u8 *slash, *tmp;
@ -116,31 +123,32 @@ static void find_as(u8* argv0) {
/* Copy argv to cc_params, making the necessary edits. */
static void edit_params(u32 argc, char** argv) {
//定义了一个函数edit_params它接受两个参数argc是参数的数量argv是参数的数组。
u8 fortify_set = 0, asan_set = 0;
u8 *name;
u8 fortify_set = 0, asan_set = 0;//声明两个变量fortify_set和asan_set用于跟踪是否已经设置了FORTIFY_SOURCE和address sanitizerASan标志
u8 *name;//用于存储程序的名称
#if defined(__FreeBSD__) && defined(__x86_64__)
u8 m32_set = 0;
#endif
cc_params = ck_alloc((argc + 128) * sizeof(u8*));
cc_params = ck_alloc((argc + 128) * sizeof(u8*));//分配内存以存储修改后的参数列表大小为argc + 128个u8*类型的指针。
name = strrchr(argv[0], '/');
if (!name) name = argv[0]; else name++;
name = strrchr(argv[0], '/');//找到argv[0](程序的路径)中最后一个'/'字符,这通常用于获取程序的名称。
if (!name) name = argv[0]; else name++;//如果name为NULL即argv[0]中没有'/'则name指向argv[0]的开始。否则name向前移动一个字符跳过'/'。
if (!strncmp(name, "afl-clang", 9)) {
clang_mode = 1;
clang_mode = 1;//检查程序名称是否以"afl-clang"开头如果是设置clang_mode标志为1
setenv(CLANG_ENV_VAR, "1", 1);
setenv(CLANG_ENV_VAR, "1", 1);//设置环境变量CLANG_ENV_VAR为"1"这可能用于通知其他部分的AFL工具链正在使用Clang。
if (!strcmp(name, "afl-clang++")) {
u8* alt_cxx = getenv("AFL_CXX");
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++";
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"clang++";//如果AFL_CXX设置将其值作为第一个参数否则使用"clang++"。
} else {
u8* alt_cc = getenv("AFL_CC");
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang";
cc_params[0] = alt_cc ? alt_cc : (u8*)"clang";//否则尝试获取环境变量AFL_CC的值。
}
} else {
@ -152,13 +160,13 @@ static void edit_params(u32 argc, char** argv) {
binaries. Meh. */
#ifdef __APPLE__
//在Apple系统上根据程序名称设置不同的编译器。如果AFL_CXX、AFL_GCJ或AFL_CC环境变量设置使用它们的值否则使用默认的编译器名称
if (!strcmp(name, "afl-g++")) cc_params[0] = getenv("AFL_CXX");
else if (!strcmp(name, "afl-gcj")) cc_params[0] = getenv("AFL_GCJ");
else cc_params[0] = getenv("AFL_CC");
if (!cc_params[0]) {
//输出错误信息指出在MacOS X上需要设置AFL_CC或AFL_CXX环境变量。
SAYF("\n" cLRD "[-] " cRST
"On Apple systems, 'gcc' is usually just a wrapper for clang. Please use the\n"
" 'afl-clang' utility instead of 'afl-gcc'. If you really have GCC installed,\n"
@ -169,7 +177,7 @@ static void edit_params(u32 argc, char** argv) {
}
#else
//对于非Apple系统根据程序名称设置不同的编译器。如果相应的环境变量设置使用它们的值否则使用默认的编译器名称。
if (!strcmp(name, "afl-g++")) {
u8* alt_cxx = getenv("AFL_CXX");
cc_params[0] = alt_cxx ? alt_cxx : (u8*)"g++";
@ -188,27 +196,27 @@ static void edit_params(u32 argc, char** argv) {
while (--argc) {
u8* cur = *(++argv);
if (!strncmp(cur, "-B", 2)) {
if (!strncmp(cur, "-B", 2)) {//如果当前参数以"-B"开头,输出警告信息,并跳过后续参数(如果当前参数后面紧跟着的是编译器的路径)。
if (!be_quiet) WARNF("-B is already set, overriding");
if (!be_quiet) WARNF("-B is already set, overriding");//如果程序不在静默模式,输出警告信息。
if (!cur[2] && argc > 1) { argc--; argv++; }
if (!cur[2] && argc > 1) { argc--; argv++; }//如果-B后面紧跟着的是编译器的路径跳过这个路径。
continue;
}
if (!strcmp(cur, "-integrated-as")) continue;
if (!strcmp(cur, "-integrated-as")) continue;//如果参数是"-integrated-as",跳过它。
if (!strcmp(cur, "-pipe")) continue;
if (!strcmp(cur, "-pipe")) continue;//如果参数是"-pipe",跳过它。
#if defined(__FreeBSD__) && defined(__x86_64__)
if (!strcmp(cur, "-m32")) m32_set = 1;
#endif
if (!strcmp(cur, "-fsanitize=address") ||
!strcmp(cur, "-fsanitize=memory")) asan_set = 1;
!strcmp(cur, "-fsanitize=memory")) asan_set = 1;//如果参数是"-fsanitize=address"或"-fsanitize=memory"设置asan_set标志。
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;//如果参数包含"FORTIFY_SOURCE"设置fortify_set标志。
cc_params[cc_par_cnt++] = cur;
@ -216,9 +224,11 @@ static void edit_params(u32 argc, char** argv) {
cc_params[cc_par_cnt++] = "-B";
cc_params[cc_par_cnt++] = as_path;
//向参数列表中添加"-B"和AFL汇编器的路径。
if (clang_mode)
cc_params[cc_par_cnt++] = "-no-integrated-as";
cc_params[cc_par_cnt++] = "-no-integrated-as";//如果clang_mode标志设置向参数列表中添加`"-no-integrated-as"
if (getenv("AFL_HARDEN")) {
@ -229,38 +239,38 @@ static void edit_params(u32 argc, char** argv) {
}
if (asan_set) {
if (asan_set) {//检查是否设置了asan_set标志。
/* Pass this on to afl-as to adjust map density. */
setenv("AFL_USE_ASAN", "1", 1);
setenv("AFL_USE_ASAN", "1", 1);//如果设置设置环境变量AFL_USE_ASAN为"1"
} else if (getenv("AFL_USE_ASAN")) {
} else if (getenv("AFL_USE_ASAN")) {//如果asan_set标志未设置但设置了环境变量AFL_USE_ASAN。
if (getenv("AFL_USE_MSAN"))
FATAL("ASAN and MSAN are mutually exclusive");
FATAL("ASAN and MSAN are mutually exclusive");//如果同时设置了AFL_USE_MSAN输出错误信息并终止程序。
if (getenv("AFL_HARDEN"))
FATAL("ASAN and AFL_HARDEN are mutually exclusive");
FATAL("ASAN and AFL_HARDEN are mutually exclusive");//如果同时设置了AFL_HARDEN输出错误信息并终止程序。
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
cc_params[cc_par_cnt++] = "-fsanitize=address";
cc_params[cc_par_cnt++] = "-fsanitize=address";//向参数列表中添加"-U_FORTIFY_SOURCE"和"-fsanitize=address"。
} else if (getenv("AFL_USE_MSAN")) {
if (getenv("AFL_USE_ASAN"))
FATAL("ASAN and MSAN are mutually exclusive");
FATAL("ASAN and MSAN are mutually exclusive");//如果同时设置了AFL_USE_ASAN输出错误信息并终止程序。
if (getenv("AFL_HARDEN"))
FATAL("MSAN and AFL_HARDEN are mutually exclusive");
FATAL("MSAN and AFL_HARDEN are mutually exclusive");//如果同时设置了AFL_HARDEN输出错误信息并终止程序。
cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
cc_params[cc_par_cnt++] = "-fsanitize=memory";
cc_params[cc_par_cnt++] = "-fsanitize=memory";//向参数列表中添加"-U_FORTIFY_SOURCE"和"-fsanitize=memory"。
}
if (!getenv("AFL_DONT_OPTIMIZE")) {
if (!getenv("AFL_DONT_OPTIMIZE")) {//检查是否设置了环境变量AFL_DONT_OPTIMIZE。
#if defined(__FreeBSD__) && defined(__x86_64__)
@ -269,22 +279,23 @@ static void edit_params(u32 argc, char** argv) {
that bug. */
if (!clang_mode || !m32_set)
cc_params[cc_par_cnt++] = "-g";
cc_params[cc_par_cnt++] = "-g";//如果不是Clang模式或没有设置m32_set标志向参数列表中添加"-g"。
#else
cc_params[cc_par_cnt++] = "-g";
#endif
#endif//结束#if defined(__FreeBSD__) && defined(__x86_64__)条件编译块。
cc_params[cc_par_cnt++] = "-O3";
cc_params[cc_par_cnt++] = "-funroll-loops";
cc_params[cc_par_cnt++] = "-funroll-loops";//向参数列表中添加"-O3"和"-funroll-loops",这些是优化选项。
/* Two indicators that you're building for fuzzing; one of them is
AFL-specific, the other is shared with libfuzzer. */
cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";
//向参数列表中添加两个宏定义,这些宏定义指示编译器代码将用于模糊测试。
}
@ -297,7 +308,7 @@ static void edit_params(u32 argc, char** argv) {
cc_params[cc_par_cnt++] = "-fno-builtin-memcmp";
cc_params[cc_par_cnt++] = "-fno-builtin-strstr";
cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr";
//如果设置,向参数列表中添加一系列"-fno-builtin-*"选项,这些选项禁用编译器的内置函数。
}
cc_params[cc_par_cnt] = NULL;
@ -306,7 +317,7 @@ static void edit_params(u32 argc, char** argv) {
/* Main entry point */
//最后是函数结束语,结束函数定义。
int main(int argc, char** argv) {
if (isatty(2) && !getenv("AFL_QUIET")) {

@ -54,31 +54,31 @@
#include <sys/types.h>
#include <sys/resource.h>
static s32 child_pid; /* PID of the tested program */
static s32 child_pid; /* 被测试程序的进程 PID */
static u8* trace_bits; /* SHM with instrumentation bitmap */
static u8* trace_bits; /* 用于存储插桩信息的共享内存 */
static u8 *out_file, /* Trace output file */
*doc_path, /* Path to docs */
*target_path, /* Path to target binary */
*at_file; /* Substitution string for @@ */
static u8 *out_file, /* 输出文件路径 */
*doc_path, /* 文档目录路径 */
*target_path, /* 被测目标程序的路径 */
*at_file; /* `@@` 的替换字符串,用于输入文件 */
static u32 exec_tmout; /* Exec timeout (ms) */
static u32 exec_tmout; /* 测试程序的执行超时时间 (毫秒) */
static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
static u64 mem_limit = MEM_LIMIT; /* 测试程序的内存限制 (MB) */
static s32 shm_id; /* ID of the SHM region */
static s32 shm_id; /* 共享内存 (SHM) 的标识符 */
static u8 quiet_mode, /* Hide non-essential messages? */
edges_only, /* Ignore hit counts? */
cmin_mode, /* Generate output in afl-cmin mode? */
binary_mode, /* Write output as a binary map */
keep_cores; /* Allow coredumps? */
static u8 quiet_mode, /* 是否隐藏非必要的信息 */
edges_only, /* 是否只关心边覆盖率 */
cmin_mode, /* 是否以 `afl-cmin` 模式生成输出 */
binary_mode, /* 是否以二进制方式输出插桩信息 */
keep_cores; /* A是否允许生成 core dump 文件 */
static volatile u8
stop_soon, /* Ctrl-C pressed? */
child_timed_out, /* Child timed out? */
child_crashed; /* Child crashed? */
stop_soon, /* 是否按下了 Ctrl-C (中止标志) */
child_timed_out, /* 子进程是否超时 */
child_crashed; /* 子进程是否崩溃 */
/* Classify tuple counts. Instead of mapping to individual bits, as in
afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */
@ -95,7 +95,7 @@ static const u8 count_class_human[256] = {
[32 ... 127] = 7,
[128 ... 255] = 8
};
}; // 映射插桩命中计数到 1-8 的更具可读性的区间。0 代表未命中1-3 被保留为原值;其余区间依次分段映射,便于统计分析。
static const u8 count_class_binary[256] = {
@ -109,23 +109,24 @@ static const u8 count_class_binary[256] = {
[32 ... 127] = 64,
[128 ... 255] = 128
};
}; // 将插桩计数按指数方式映射到二进制值,便于程序进一步处理。
static void classify_counts(u8* mem, const u8* map) {
static void classify_counts(u8* mem, const u8* map) {//对插桩命中计数 (mem) 进行分类处理,基于全局变量 edges_only 的值选择分类模式。
//u8* mem插桩数据的内存指针。const u8* map分类映射表
u32 i = MAP_SIZE;
if (edges_only) {
while (i--) {
if (*mem) *mem = 1;
if (*mem) *mem = 1;// 只关心边的覆盖情况,命中计数直接归一
mem++;
}
} else {
while (i--) {
*mem = map[*mem];
*mem = map[*mem];// 使用提供的映射表对命中计数进行分类
mem++;
}
@ -134,95 +135,105 @@ static void classify_counts(u8* mem, const u8* map) {
}
/* Get rid of shared memory (atexit handler). */
/* 删除共享内存 (atexit 处理程序). */
static void remove_shm(void) {
static void remove_shm(void) {//释放分配的共享内存。
shmctl(shm_id, IPC_RMID, NULL);
shmctl(shm_id, IPC_RMID, NULL); //使用 shmctl 函数删除共享内存区域
//IPC_RMID 标志用于标记共享内存为 "移除",在无其他进程访问后会自动释放。
//通过 atexit 注册,在程序退出时自动调用,确保清理资源。
}
/* Configure shared memory. */
/* 配置共享内存 */
static void setup_shm(void) {
static void setup_shm(void) {// 创建共享内存,分配给 trace_bits 用于记录插桩数据。通过 atexit 注册清理函数,确保资源的释放。
u8* shm_str;
/* 创建一个私有的共享内存区域,大小为 MAP_SIZE */
shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600);
if (shm_id < 0) PFATAL("shmget() failed");
if (shm_id < 0) PFATAL("shmget() failed");/* 创建失败时输出错误并退出 */
atexit(remove_shm);
atexit(remove_shm);/* 注册 atexit 处理程序以在程序退出时删除共享内存 */
/* 将共享内存 ID 转换为字符串并设置环境变量 */
shm_str = alloc_printf("%d", shm_id);
setenv(SHM_ENV_VAR, shm_str, 1);
ck_free(shm_str);
ck_free(shm_str);/* 释放临时字符串内存 */
/* 将共享内存附加到当前进程的地址空间 */
trace_bits = shmat(shm_id, NULL, 0);
if (trace_bits == (void *)-1) PFATAL("shmat() failed");
if (trace_bits == (void *)-1) PFATAL("shmat() failed"); /* 附加失败时退出 */
}
/* Write results. */
<<<<<<< HEAD
/* 写入测试结果 */
=======
/* 配置共享内存。 */
>>>>>>> 31b9bf56f4cc249d8b6bb414203bff28d8cf724a
static u32 write_results(void) {
static u32 write_results(void) { //将插桩结果输出到文件,支持二进制和文本模式。
s32 fd;
u32 i, ret = 0;
s32 fd; /* 文件描述符 */
u32 i, ret = 0; /* 计数器和返回值 */
u8 cco = !!getenv("AFL_CMIN_CRASHES_ONLY"),
caa = !!getenv("AFL_CMIN_ALLOW_ANY");
u8 cco = !!getenv("AFL_CMIN_CRASHES_ONLY"), /* 仅输出崩溃路径? */
caa = !!getenv("AFL_CMIN_ALLOW_ANY"); /* 是否允许所有路径? */
if (!strncmp(out_file, "/dev/", 5)) {
/* 根据输出文件路径的类型处理 */
if (!strncmp(out_file, "/dev/", 5)) { /* 如果是设备文件路径 */
fd = open(out_file, O_WRONLY, 0600);
if (fd < 0) PFATAL("Unable to open '%s'", out_file);
} else if (!strcmp(out_file, "-")) {
} else if (!strcmp(out_file, "-")) { /* 如果是标准输出 */
fd = dup(1);
fd = dup(1); /* 复制标准输出描述符 */
if (fd < 0) PFATAL("Unable to open stdout");
} else {
} else { /* 普通文件路径 */
unlink(out_file); /* Ignore errors */
unlink(out_file); /* 删除已有的同名文件 (忽略错误) */
fd = open(out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0) PFATAL("Unable to create '%s'", out_file);
}
/* 如果以二进制模式输出结果 */
if (binary_mode) {
for (i = 0; i < MAP_SIZE; i++)
if (trace_bits[i]) ret++;
if (trace_bits[i]) ret++;/* 统计非零插桩计数 */
ck_write(fd, trace_bits, MAP_SIZE, out_file);
ck_write(fd, trace_bits, MAP_SIZE, out_file);/* 将插桩数据写入文件 */
close(fd);
} else {
} else { /* 文本模式输出 */
FILE* f = fdopen(fd, "w");
if (!f) PFATAL("fdopen() failed");
/* 遍历插桩数据,按文本格式输出 */
for (i = 0; i < MAP_SIZE; i++) {
if (!trace_bits[i]) continue;
if (!trace_bits[i]) continue;/* 跳过空条目 */
ret++;
if (cmin_mode) {
if (cmin_mode) {/* afl-cmin 模式 */
if (child_timed_out) break;
if (!caa && child_crashed != cco) break;
if (child_timed_out) break; /* 如果子进程超时,停止输出 */
if (!caa && child_crashed != cco) break;/* 根据环境变量条件过滤 */
fprintf(f, "%u%u\n", trace_bits[i], i);
} else fprintf(f, "%06u:%u\n", i, trace_bits[i]);
} else fprintf(f, "%06u:%u\n", i, trace_bits[i]);/* 标准格式 */
}
@ -235,42 +246,54 @@ static u32 write_results(void) {
}
/* Handle timeout signal. */
<<<<<<< HEAD
/* 处理超时信号 */
=======
/* 处理超时信号。 */
>>>>>>> 31b9bf56f4cc249d8b6bb414203bff28d8cf724a
static void handle_timeout(int sig) {
child_timed_out = 1;
if (child_pid > 0) kill(child_pid, SIGKILL);
child_timed_out = 1; /* 设置子进程超时标志 */
if (child_pid > 0) kill(child_pid, SIGKILL); /* 强制杀死子进程 */
}
/* Execute target application. */
<<<<<<< HEAD
/* 执行目标程序 */
=======
/* 执行目标应用程序。 */
/* 运行目标程序并等待其结束。 */
/* 处理超时和信号。 */
>>>>>>> 31b9bf56f4cc249d8b6bb414203bff28d8cf724a
static void run_target(char** argv) {
static struct itimerval it;
static struct itimerval it;/* 定时器结构 */
int status = 0;
if (!quiet_mode)
SAYF("-- Program output begins --\n" cRST);
SAYF("-- Program output begins --\n" cRST);/* 输出调试信息 */
MEM_BARRIER();
MEM_BARRIER(); /* 防止编译器重排内存操作 */
child_pid = fork();
child_pid = fork();/* 创建子进程 */
if (child_pid < 0) PFATAL("fork() failed");
if (child_pid < 0) PFATAL("fork() failed");/* 如果 fork 失败,退出程序 */
if (!child_pid) {
if (!child_pid) { /* 子进程逻辑 */
struct rlimit r;
if (quiet_mode) {
if (quiet_mode) { /* 如果静默模式开启,将子进程输出重定向到 `/dev/null` */
s32 fd = open("/dev/null", O_RDWR);
if (fd < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0) {
*(u32*)trace_bits = EXEC_FAIL_SIG;
*(u32*)trace_bits = EXEC_FAIL_SIG; /* 设置错误标志 */
PFATAL("Descriptor initialization failed");
}
@ -278,35 +301,35 @@ static void run_target(char** argv) {
}
if (mem_limit) {
if (mem_limit) {/* 设置子进程内存限制 */
r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20;
#ifdef RLIMIT_AS
setrlimit(RLIMIT_AS, &r); /* Ignore errors */
setrlimit(RLIMIT_AS, &r); /* 设置内存限制 (按地址空间限制),忽略错误 */
#else
setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
setrlimit(RLIMIT_DATA, &r); /* 设置内存限制 (按数据段大小限制),忽略错误 */
#endif /* ^RLIMIT_AS */
}
// 根据平台使用适当的资源限制类型 (RLIMIT_AS 或 RLIMIT_DATA) 限制子进程的内存使用。
if (!keep_cores) r.rlim_max = r.rlim_cur = 0; /* 禁止 core dump */
// 控制是否允许子进程生成 core dump 文件。
else r.rlim_max = r.rlim_cur = RLIM_INFINITY; /* 允许无限 core dump */
if (!keep_cores) r.rlim_max = r.rlim_cur = 0;
else r.rlim_max = r.rlim_cur = RLIM_INFINITY;
setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
setrlimit(RLIMIT_CORE, &r); /* 设置 core dump 限制,忽略错误 */
if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0);
if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0); // 强制目标程序加载动态库时立即绑定符号,避免延迟加载可能引发的问题。
setsid();
setsid(); /* 创建一个新会话,隔离子进程 */
execv(target_path, argv);
execv(target_path, argv);/* 替换当前进程镜像为目标程序 */
*(u32*)trace_bits = EXEC_FAIL_SIG;
exit(0);
*(u32*)trace_bits = EXEC_FAIL_SIG; /* 如果 execv 返回,则标记执行失败 */
exit(0);/* 终止子进程 */
}
@ -320,9 +343,9 @@ static void run_target(char** argv) {
}
setitimer(ITIMER_REAL, &it, NULL);
setitimer(ITIMER_REAL, &it, NULL);/* 配置超时定时器 */
if (waitpid(child_pid, &status, 0) <= 0) FATAL("waitpid() failed");
if (waitpid(child_pid, &status, 0) <= 0) FATAL("waitpid() failed"); /* 等待子进程结束 */
child_pid = 0;
it.it_value.tv_sec = 0;
@ -338,7 +361,7 @@ static void run_target(char** argv) {
classify_counts(trace_bits, binary_mode ?
count_class_binary : count_class_human);
/* 将 trace_bits 中的插桩命中数据分类为二进制或人类可读格式 */
if (!quiet_mode)
SAYF(cRST "-- Program output ends --\n");
@ -362,11 +385,11 @@ static void run_target(char** argv) {
/* Handle Ctrl-C and the like. */
static void handle_stop_sig(int sig) {
static void handle_stop_sig(int sig) {//捕获停止信号 (SIGHUP, SIGINT, SIGTERM) 并设置全局停止标志。终止子进程以确保程序退出。
stop_soon = 1;
stop_soon = 1;/* 设置标志,通知主程序停止 */
if (child_pid > 0) kill(child_pid, SIGKILL);
if (child_pid > 0) kill(child_pid, SIGKILL);/* 强制杀死子进程 */
}
@ -374,7 +397,7 @@ static void handle_stop_sig(int sig) {
/* Do basic preparations - persistent fds, filenames, etc. */
static void set_up_environment(void) {
// 设置环境变量,配置 AddressSanitizer (ASAN) 和 MemorySanitizer (MSAN) 行为:禁用内存泄漏检测 (detect_leaks=0)。禁用符号化输出 (symbolize=0)。配置错误退出行为 (abort_on_error=1)。
setenv("ASAN_OPTIONS", "abort_on_error=1:"
"detect_leaks=0:"
"symbolize=0:"
@ -385,7 +408,7 @@ static void set_up_environment(void) {
"abort_on_error=1:"
"allocator_may_return_null=1:"
"msan_track_origins=0", 0);
// 如果存在 AFL_PRELOAD 环境变量,将其设置为动态库预加载路径。
if (getenv("AFL_PRELOAD")) {
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
@ -407,32 +430,34 @@ static void setup_signal_handlers(void) {
sigemptyset(&sa.sa_mask);
/* Various ways of saying "stop". */
sa.sa_handler = handle_stop_sig;
// 为停止信号 (SIGHUP, SIGINT, SIGTERM) 注册处理函数 handle_stop_sig。
sa.sa_handler = handle_stop_sig; /* 设置停止信号的处理函数 */
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
/* Exec timeout notifications. */
sa.sa_handler = handle_timeout;
sa.sa_handler = handle_timeout;/* 设置超时信号的处理函数 */
sigaction(SIGALRM, &sa, NULL);
}
/* Detect @@ in args. */
/* 检测@@在参数中。 */
/* 检测并替换@@参数。 */
/* 用于处理传递给目标程序的文件路径参数。 */
static void detect_file_args(char** argv) {
// 获取当前工作目录,用于构造绝对路径。
u32 i = 0;
u8* cwd = getcwd(NULL, 0);
u8* cwd = getcwd(NULL, 0);/* 获取当前工作目录 */
if (!cwd) PFATAL("getcwd() failed");
while (argv[i]) {
u8* aa_loc = strstr(argv[i], "@@");
u8* aa_loc = strstr(argv[i], "@@");/* 查找命令行参数中的 @@ */
if (aa_loc) {
@ -442,13 +467,13 @@ static void detect_file_args(char** argv) {
/* Be sure that we're always using fully-qualified paths. */
if (at_file[0] == '/') aa_subst = at_file;
else aa_subst = alloc_printf("%s/%s", cwd, at_file);
if (at_file[0] == '/') aa_subst = at_file;/* 如果是绝对路径,直接使用 */
else aa_subst = alloc_printf("%s/%s", cwd, at_file);/* 构造绝对路径 */
/* Construct a replacement argv value. */
*aa_loc = 0;
n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);
n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);/* 替换 @@ */
argv[i] = n_arg;
*aa_loc = '@';
@ -465,20 +490,25 @@ static void detect_file_args(char** argv) {
}
<<<<<<< HEAD
/* Show banner. */
// 打印工具的名称和版本信息。
=======
>>>>>>> 31b9bf56f4cc249d8b6bb414203bff28d8cf724a
static void show_banner(void) {
SAYF(cCYA "afl-showmap " cBRI VERSION cRST " by <lcamtuf@google.com>\n");
}
/* Display usage hints. */
/* 显示使用提示。 */
static void usage(u8* argv0) {
show_banner();
// 显示工具的用法说明,包括参数和选项说明。
SAYF("\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
"Required parameters:\n\n"
@ -492,7 +522,7 @@ static void usage(u8* argv0) {
" -Q - use binary-only instrumentation (QEMU mode)\n\n"
"Other settings:\n\n"
// 描述可用的执行控制选项,包括超时时间和内存限制。
" -q - sink program's output and don't show messages\n"
" -e - show edge coverage only, ignore hit counts\n"
" -c - allow core dumps\n"
@ -508,17 +538,23 @@ static void usage(u8* argv0) {
}
<<<<<<< HEAD
/* Find binary. */
// 找到目标程序的可执行文件路径 (target_path)。
=======
/* 查找二进制文件。 */
/* 查找并验证二进制文件。 */
/* 如果二进制文件不存在或不可执行,则打印错误信息并退出。 */
>>>>>>> 31b9bf56f4cc249d8b6bb414203bff28d8cf724a
static void find_binary(u8* fname) {
// fname目标程序的文件名。如果 fname 包含斜杠(表明是路径)或没有设置 PATH 环境变量,则直接检查 fname 是否是一个可执行文件。否则,遍历 PATH 环境变量中定义的路径,尝试找到 fname。
u8* env_path = 0;
struct stat st;
if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
// 如果 fname 是路径(包含斜杠),直接检查其合法性。
target_path = ck_strdup(fname);
// 如果 PATH 环境变量未设置,同样直接检查 fname。
if (stat(target_path, &st) || !S_ISREG(st.st_mode) ||
!(st.st_mode & 0111) || st.st_size < 4)
FATAL("Program '%s' not found or not executable", fname);
@ -538,14 +574,14 @@ static void find_binary(u8* fname) {
} else cur_elem = ck_strdup(env_path);
env_path = delim;
// 按冒号分隔符解析 PATH 环境变量,依次检查每个路径是否包含目标文件。
if (cur_elem[0])
target_path = alloc_printf("%s/%s", cur_elem, fname);
else
target_path = ck_strdup(fname);
ck_free(cur_elem);
// 将文件名与路径组合成完整路径。检查文件是否存在、是否是普通文件、是否可执行且文件大小合理。如果找到符合条件的文件路径,则退出循环。
if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
(st.st_mode & 0111) && st.st_size >= 4) break;
@ -553,7 +589,7 @@ static void find_binary(u8* fname) {
target_path = 0;
}
// 如果遍历完所有路径后仍未找到目标文件,则程序退出。
if (!target_path) FATAL("Program '%s' not found or not executable", fname);
}
@ -561,24 +597,33 @@ static void find_binary(u8* fname) {
}
<<<<<<< HEAD
/* Fix up argv for QEMU. */
// 为在 QEMU 模式下执行目标程序,调整参数列表 argv。
=======
/*修正argv以用于QEMU*/
/* 为QEMU模式修正参数*/
/* 返回新的参数数组*/
>>>>>>> 31b9bf56f4cc249d8b6bb414203bff28d8cf724a
static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
// own_loc当前程序的路径用于寻找 afl-qemu-trace。argv原始参数列表。argc参数个数。
char** new_argv = ck_alloc(sizeof(char*) * (argc + 4));
u8 *tmp, *cp, *rsl, *own_copy;
/* Workaround for a QEMU stability glitch. */
/* 设置 QEMU 的环境变量 QEMU_LOG禁用链式日志。 */
setenv("QEMU_LOG", "nochain", 1);
memcpy(new_argv + 3, argv + 1, sizeof(char*) * argc);
// 为新参数列表分配空间。
// 将原始参数 argv 复制到新参数列表的合适位置。
// 添加必要的 QEMU 参数 -- 和 target_path。
new_argv[2] = target_path;
new_argv[1] = "--";
/* Now we need to actually find qemu for argv[0]. */
// 检查 AFL_PATH 环境变量是否指向 afl-qemu-trace并验证其是否可执行。
tmp = getenv("AFL_PATH");
if (tmp) {
@ -592,7 +637,7 @@ static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
return new_argv;
}
// 使用当前程序的路径 own_loc 尝试找到 afl-qemu-trace。
own_copy = ck_strdup(own_loc);
rsl = strrchr(own_copy, '/');
@ -611,40 +656,48 @@ static char** get_qemu_argv(u8* own_loc, char** argv, int argc) {
}
} else ck_free(own_copy);
// 检查预定义路径 BIN_PATH 下是否存在 afl-qemu-trace。
if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
target_path = new_argv[0] = BIN_PATH "/afl-qemu-trace";
return new_argv;
}
// 如果未找到 afl-qemu-trace程序退出并报错。
FATAL("Unable to find 'afl-qemu-trace'.");
}
/* Main entry point */
/*解析命令行参数并执行目标程序 */
/*根据参数执行不同的操作 */
int main(int argc, char** argv) {
//opt用于存储当前解析的命令行选项。
//mem_limit_given标志是否设置了内存限制选项。
//timeout_given标志是否设置了超时选项。
//qemu_mode标志是否启用了 QEMU 模式。
//tcnt存储记录的插桩数据元组计数。
//use_argv用于执行目标程序的参数列表。
s32 opt;
u8 mem_limit_given = 0, timeout_given = 0, qemu_mode = 0;
u32 tcnt;
char** use_argv;
// 检查 DOC_PATH 是否存在,如果不存在则回退到默认路径 "docs"。
doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
// 使用 getopt 解析命令行选项,支持的选项包括:
while ((opt = getopt(argc,argv,"+o:m:t:A:eqZQbcV")) > 0)
switch (opt) {
// -o指定输出文件。
case 'o':
if (out_file) FATAL("Multiple -o options not supported");
out_file = optarg;
break;
// -m设置内存限制。
case 'm': {
u8 suffix = 'M';
@ -681,7 +734,7 @@ int main(int argc, char** argv) {
}
break;
// -t设置超时时间。
case 't':
if (timeout_given) FATAL("Multiple -t options not supported");
@ -696,19 +749,19 @@ int main(int argc, char** argv) {
}
break;
// -e只关注边覆盖率。
case 'e':
if (edges_only) FATAL("Multiple -e options not supported");
edges_only = 1;
break;
// -q静默模式不显示多余信息。
case 'q':
if (quiet_mode) FATAL("Multiple -q options not supported");
quiet_mode = 1;
break;
// -Z启用 afl-cmin 模式,内部使用,设置 cmin_mode 和 quiet_mode。
case 'Z':
/* This is an undocumented option to write data in the syntax expected
@ -717,13 +770,13 @@ int main(int argc, char** argv) {
cmin_mode = 1;
quiet_mode = 1;
break;
// -A设置 @@ 替换文件路径。
case 'A':
/* Another afl-cmin specific feature. */
at_file = optarg;
break;
// -Q启用 QEMU 模式,如果未指定内存限制,使用默认值 MEM_LIMIT_QEMU。
case 'Q':
if (qemu_mode) FATAL("Multiple -Q options not supported");
@ -731,7 +784,7 @@ int main(int argc, char** argv) {
qemu_mode = 1;
break;
// -b启用二进制输出模式设置全局变量 binary_mode = 1。
case 'b':
/* Secret undocumented mode. Writes output in raw binary format
@ -739,13 +792,13 @@ int main(int argc, char** argv) {
binary_mode = 1;
break;
// -c允许生成核心转储文件设置全局变量 keep_cores = 1。
case 'c':
if (keep_cores) FATAL("Multiple -c options not supported");
keep_cores = 1;
break;
// -V显示版本号并退出程序。
case 'V':
show_banner();
@ -757,39 +810,40 @@ int main(int argc, char** argv) {
}
if (optind == argc || !out_file) usage(argv[0]);
if (optind == argc || !out_file) usage(argv[0]); //如果未指定目标程序路径或输出文件,则显示用法说明并退出。
setup_shm();
setup_signal_handlers();
setup_shm();// 调用 setup_shm 函数,配置用于插桩数据存储的共享内存。
setup_signal_handlers();// 注册信号处理函数处理程序停止SIGINT、SIGTERM或超时SIGALRM等事件。
set_up_environment();
set_up_environment();// 配置环境变量,例如 ASAN_OPTIONS 和 MSAN_OPTIONS。
find_binary(argv[optind]);
find_binary(argv[optind]);//使用 find_binary 函数查找目标程序的可执行文件路径,并存储到全局变量 target_path。
if (!quiet_mode) {
if (!quiet_mode) {// 如果未启用静默模式,显示工具信息和目标程序路径。
show_banner();
ACTF("Executing '%s'...\n", target_path);
}
detect_file_args(argv + optind);
detect_file_args(argv + optind); //检测命令行参数中的 @@ 并将其替换为指定的文件路径。
if (qemu_mode)
if (qemu_mode) //如果启用了 QEMU 模式,调用 get_qemu_argv 函数为 QEMU 准备参数列表。
use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
else
else // 否则直接使用原始参数。
use_argv = argv + optind;
run_target(use_argv);
tcnt = write_results();
tcnt = write_results(); // 调用 write_results 函数,将插桩数据写入指定的输出文件。
if (!quiet_mode) {
if (!tcnt) FATAL("No instrumentation detected" cRST);
OKF("Captured %u tuples in '%s'." cRST, tcnt, out_file);
if (!tcnt) FATAL("No instrumentation detected" cRST); //如果没有捕获插桩数据,显示错误并退出。
OKF("Captured %u tuples in '%s'." cRST, tcnt, out_file); // 否则显示捕获的元组数量和输出文件路径。
}
exit(child_crashed * 2 + child_timed_out);
// 根据子进程状态退出.如果子进程崩溃:返回 2。如果子进程超时返回 1。正常退出返回 0。
}

@ -36,8 +36,7 @@
#include "types.h"
#include "debug.h"
/* User-facing macro to sprintf() to a dynamically allocated buffer. */
/* 提供给用户使用的宏用于将sprintf()的输出到一个动态分配的缓冲区。 */
#define alloc_printf(_str...) ({ \
u8* _tmp; \
s32 _len = snprintf(NULL, 0, _str); \
@ -47,29 +46,24 @@
_tmp; \
})
/* Macro to enforce allocation limits as a last-resort defense against
integer overflows. */
/* 宏,用于强制执行分配限制,作为防止整数溢出的最后一道防线。 */
#define ALLOC_CHECK_SIZE(_s) do { \
if ((_s) > MAX_ALLOC) \
ABORT("Bad alloc request: %u bytes", (_s)); \
} while (0)
/* Macro to check malloc() failures and the like. */
/* 宏用于检查malloc()失败等情况。 */
#define ALLOC_CHECK_RESULT(_r, _s) do { \
if (!(_r)) \
ABORT("Out of memory: can't allocate %u bytes", (_s)); \
} while (0)
/* Magic tokens used to mark used / freed chunks. */
#define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */
#define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */
#define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */
/* Positions of guard tokens in relation to the user-visible pointer. */
/* 用于标记已使用/已释放块的魔术标记。 */
#define ALLOC_MAGIC_C1 0xFF00FF00 /* 已使用头部(双字) */
#define ALLOC_MAGIC_F 0xFE00FE00 /* 已释放头部(双字) */
#define ALLOC_MAGIC_C2 0xF0 /* 已使用尾部(字节) */
/* 与用户可见指针相关的保护标记的位置。 */
#define ALLOC_C1(_ptr) (((u32*)(_ptr))[-2])
#define ALLOC_S(_ptr) (((u32*)(_ptr))[-1])
#define ALLOC_C2(_ptr) (((u8*)(_ptr))[ALLOC_S(_ptr)])
@ -77,15 +71,13 @@
#define ALLOC_OFF_HEAD 8
#define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
/* Allocator increments for ck_realloc_block(). */
/* ck_realloc_block()的分配器增量。 */
#define ALLOC_BLK_INC 256
/* Sanity-checking macros for pointers. */
/* 用于指针的合理性检查宏。 */
#define CHECK_PTR(_p) do { \
if (_p) { \
if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) {\
if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) { \
if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
ABORT("Use after free."); \
else ABORT("Corrupted head alloc canary."); \
@ -101,246 +93,206 @@
_tmp; \
})
/* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
requests. */
/* 分配一个缓冲区明确不将其清零。对于零大小的请求返回NULL。 */
static inline void* DFL_ck_alloc_nozero(u32 size) {
void* ret;
void* ret;
if (!size) return NULL;
if (!size) return NULL;
ALLOC_CHECK_SIZE(size);
ret = malloc(size + ALLOC_OFF_TOTAL);
ALLOC_CHECK_RESULT(ret, size);
ALLOC_CHECK_SIZE(size);
ret = malloc(size + ALLOC_OFF_TOTAL);
ALLOC_CHECK_RESULT(ret, size);
ret += ALLOC_OFF_HEAD;
ret += ALLOC_OFF_HEAD;
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
return ret;
return ret;
}
/* Allocate a buffer, returning zeroed memory. */
/* 分配一个缓冲区,返回清零后的内存。 */
static inline void* DFL_ck_alloc(u32 size) {
void* mem;
void* mem;
if (!size) return NULL;
mem = DFL_ck_alloc_nozero(size);
if (!size) return NULL;
mem = DFL_ck_alloc_nozero(size);
return memset(mem, 0, size);
return memset(mem, 0, size);
}
/* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
is set, the old memory will be also clobbered with 0xFF. */
/* 释放内存检查是否重复释放和堆损坏。当DEBUG_BUILD被设置时
0xFF */
static inline void DFL_ck_free(void* mem) {
if (!mem) return; /* 如果指针为空,不执行任何操作 */
if (!mem) return;
CHECK_PTR(mem);
#ifdef DEBUG_BUILD
/* Catch pointer issues sooner. */
memset(mem, 0xFF, ALLOC_S(mem));
CHECK_PTR(mem); /* 检查是否重复释放和堆损坏 */
#ifdef DEBUG_BUILD /* 如果是调试构建用0xFF覆盖内存 */
/* 尽早捕捉指针问题。 */
memset(mem, 0xFF, ALLOC_S(mem)); /* 用0xFF覆盖内存 */
#endif /* DEBUG_BUILD */
ALLOC_C1(mem) = ALLOC_MAGIC_F;
free(mem - ALLOC_OFF_HEAD);
ALLOC_C1(mem) = ALLOC_MAGIC_F; /* 标记内存为已释放 */
free(mem - ALLOC_OFF_HEAD); /* 释放内存,调整头偏移 */
}
/* Re-allocate a buffer, checking for issues and zeroing any newly-added tail.
With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the
old memory is clobbered with 0xFF. */
/* 重新分配缓冲区,检查问题并清零任何新添加的尾部。
DEBUG_BUILD0xFF */
static inline void* DFL_ck_realloc(void* orig, u32 size) {
void* ret;
u32 old_size = 0;
void* ret;
u32 old_size = 0;
if (!size) {
DFL_ck_free(orig);
return NULL;
}
if (orig) {
if (!size) {
DFL_ck_free(orig); /* 如果新大小为0释放原始内存 */
return NULL;
}
CHECK_PTR(orig);
if (orig) {
CHECK_PTR(orig); /* 检查是否重复释放和堆损坏 */
#ifndef DEBUG_BUILD
ALLOC_C1(orig) = ALLOC_MAGIC_F;
#ifndef DEBUG_BUILD /* 在非调试构建中,可以重用内存 */
ALLOC_C1(orig) = ALLOC_MAGIC_F; /* 标记内存为已释放 */
#endif /* !DEBUG_BUILD */
old_size = ALLOC_S(orig);
orig -= ALLOC_OFF_HEAD;
ALLOC_CHECK_SIZE(old_size);
}
ALLOC_CHECK_SIZE(size);
#ifndef DEBUG_BUILD
ret = realloc(orig, size + ALLOC_OFF_TOTAL);
ALLOC_CHECK_RESULT(ret, size);
#else
/* Catch pointer issues sooner: force relocation and make sure that the
original buffer is wiped. */
ret = malloc(size + ALLOC_OFF_TOTAL);
ALLOC_CHECK_RESULT(ret, size);
old_size = ALLOC_S(orig); /* 获取原始大小 */
orig -= ALLOC_OFF_HEAD; /* 调整指针以适应头部偏移 */
if (orig) {
memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size));
memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size);
ALLOC_CHECK_SIZE(old_size); /* 检查原始大小是否有效 */
}
ALLOC_C1(orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F;
ALLOC_CHECK_SIZE(size); /* 检查新大小是否有效 */
free(orig);
#ifndef DEBUG_BUILD /* 在非调试构建中,尝试原地调整内存大小 */
ret = realloc(orig, size + ALLOC_OFF_TOTAL); /* 重新分配内存 */
ALLOC_CHECK_RESULT(ret, size); /* 检查重新分配是否成功 */
#else /* 在调试构建中,总是分配新内存并清除旧内存 */
/* 尽早捕捉指针问题:强制重新定位,并确保旧缓冲区被清除。 */
}
ret = malloc(size + ALLOC_OFF_TOTAL); /* 分配新内存 */
ALLOC_CHECK_RESULT(ret, size); /* 检查分配是否成功 */
if (orig) {
memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size)); /* 将数据复制到新内存 */
memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size); /* 用0xFF覆盖旧内存 */
ALLOC_C1(orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F; /* 标记旧内存为已释放 */
free(orig); /* 释放旧内存 */
}
#endif /* ^!DEBUG_BUILD */
ret += ALLOC_OFF_HEAD;
ret += ALLOC_OFF_HEAD; /* 调整指针以适应头部偏移 */
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
ALLOC_C1(ret) = ALLOC_MAGIC_C1; /* 标记内存为已使用 */
ALLOC_S(ret) = size; /* 存储内存块的大小 */
ALLOC_C2(ret) = ALLOC_MAGIC_C2; /* 标记内存块的结尾 */
if (size > old_size)
memset(ret + old_size, 0, size - old_size);
return ret;
if (size > old_size) /* 如果新大小更大,清零新的尾部 */
memset(ret + old_size, 0, size - old_size);
return ret; /* 返回(可能新的)内存块 */
}
/* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up
repeated small reallocs without complicating the user code). */
/* 以ALLOC_BLK_INC的增量重新分配缓冲区用于加速重复的小realloc操作而不需要复杂化用户代码。 */
static inline void* DFL_ck_realloc_block(void* orig, u32 size) {
#ifndef DEBUG_BUILD
if (orig) {
if (orig) {
CHECK_PTR(orig);
CHECK_PTR(orig); /* 检查原始指针是否有效 */
if (ALLOC_S(orig) >= size) return orig;
if (ALLOC_S(orig) >= size) return orig; /* 如果当前大小已满足需求则不进行realloc */
size += ALLOC_BLK_INC;
size += ALLOC_BLK_INC; /* 增加ALLOC_BLK_INC以减少频繁的小realloc操作 */
}
}
#endif /* !DEBUG_BUILD */
return DFL_ck_realloc(orig, size);
return DFL_ck_realloc(orig, size); /* 调用DFL_ck_realloc进行实际的realloc操作 */
}
/* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
/* 创建一个包含字符串副本的缓冲区。对于NULL输入返回NULL。 */
static inline u8* DFL_ck_strdup(u8* str) {
void* ret;
u32 size;
void* ret;
u32 size;
if (!str) return NULL;
if (!str) return NULL; /* 如果输入字符串为空则返回NULL */
size = strlen((char*)str) + 1;
size = strlen((char*)str) + 1; /* 计算字符串长度加1为'\0'留空间) */
ALLOC_CHECK_SIZE(size);
ret = malloc(size + ALLOC_OFF_TOTAL);
ALLOC_CHECK_RESULT(ret, size);
ALLOC_CHECK_SIZE(size); /* 检查分配大小是否超出限制 */
ret = malloc(size + ALLOC_OFF_TOTAL); /* 分配内存 */
ALLOC_CHECK_RESULT(ret, size); /* 检查内存分配是否成功 */
ret += ALLOC_OFF_HEAD;
ret += ALLOC_OFF_HEAD; /* 调整指针以适应头部偏移 */
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
ALLOC_C1(ret) = ALLOC_MAGIC_C1; /* 设置头部魔术标记 */
ALLOC_S(ret) = size; /* 存储分配的大小 */
ALLOC_C2(ret) = ALLOC_MAGIC_C2; /* 设置尾部魔术标记 */
return memcpy(ret, str, size);
return memcpy(ret, str, size); /* 复制字符串并返回新指针 */
}
/* Create a buffer with a copy of a memory block. Returns NULL for zero-sized
or NULL inputs. */
/* 创建一个包含内存块副本的缓冲区。对于零大小或NULL输入返回NULL。 */
static inline void* DFL_ck_memdup(void* mem, u32 size) {
void* ret;
if (!mem || !size) return NULL;
void* ret;
ALLOC_CHECK_SIZE(size);
ret = malloc(size + ALLOC_OFF_TOTAL);
ALLOC_CHECK_RESULT(ret, size);
ret += ALLOC_OFF_HEAD;
if (!mem || !size) return NULL; /* 如果内存块为空或大小为零则返回NULL */
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
ALLOC_CHECK_SIZE(size); /* 检查分配大小是否超出限制 */
ret = malloc(size + ALLOC_OFF_TOTAL); /* 分配内存 */
ALLOC_CHECK_RESULT(ret, size); /* 检查内存分配是否成功 */
return memcpy(ret, mem, size);
ret += ALLOC_OFF_HEAD; /* 调整指针以适应头部偏移 */
}
ALLOC_C1(ret) = ALLOC_MAGIC_C1; /* 设置头部魔术标记 */
ALLOC_S(ret) = size; /* 存储分配的大小 */
ALLOC_C2(ret) = ALLOC_MAGIC_C2; /* 设置尾部魔术标记 */
return memcpy(ret, mem, size); /* 复制内存块并返回新指针 */
/* Create a buffer with a block of text, appending a NUL terminator at the end.
Returns NULL for zero-sized or NULL inputs. */
}
/* 创建一个包含文本块的缓冲区并在末尾追加NUL终止符。对于零大小或NULL输入返回NULL。 */
static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
u8* ret;
u8* ret;
if (!mem || !size) return NULL;
if (!mem || !size) return NULL; /* 如果内存块为空或大小为零则返回NULL */
ALLOC_CHECK_SIZE(size);
ret = malloc(size + ALLOC_OFF_TOTAL + 1);
ALLOC_CHECK_RESULT(ret, size);
ret += ALLOC_OFF_HEAD;
ALLOC_CHECK_SIZE(size); /* 检查分配大小是否超出限制 */
ret = malloc(size + ALLOC_OFF_TOTAL + 1); /* 分配内存,额外+1用于NUL终止符 */
ALLOC_CHECK_RESULT(ret, size); /* 检查内存分配是否成功 */
ALLOC_C1(ret) = ALLOC_MAGIC_C1;
ALLOC_S(ret) = size;
ALLOC_C2(ret) = ALLOC_MAGIC_C2;
ret += ALLOC_OFF_HEAD; /* 调整指针以适应头部偏移 */
memcpy(ret, mem, size);
ret[size] = 0;
ALLOC_C1(ret) = ALLOC_MAGIC_C1; /* 设置头部魔术标记 */
ALLOC_S(ret) = size; /* 存储分配的大小 */
ALLOC_C2(ret) = ALLOC_MAGIC_C2; /* 设置尾部魔术标记 */
return ret;
memcpy(ret, mem, size); /* 复制内存块 */
ret[size] = 0; /* 设置NUL终止符 */
}
return ret; /* 返回新指针 */
}
#ifndef DEBUG_BUILD
/* In non-debug mode, we just do straightforward aliasing of the above functions
to user-visible names such as ck_alloc(). */
/* 在非调试模式下我们直接将上述函数别名为用户可见的名称如ck_alloc()。 */
#define ck_alloc DFL_ck_alloc
#define ck_alloc_nozero DFL_ck_alloc_nozero
@ -355,223 +307,191 @@ static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
#else
/* In debugging mode, we also track allocations to detect memory leaks, and the
flow goes through one more layer of indirection. */
/* 在调试模式下,我们还跟踪内存分配以检测内存泄漏,这个过程会经历更多的间接层。 */
/* Alloc tracking data structures: */
/* 分配跟踪数据结构: */
#define ALLOC_BUCKETS 4096
#define ALLOC_BUCKETS 4096 /* 定义分配桶的数量 */
struct TRK_obj {
void *ptr;
char *file, *func;
u32 line;
void* ptr; /* 指向分配的内存块 */
char* file, * func; /* 分配时的文件名和函数名 */
u32 line; /* 分配时的代码行号 */
};
#ifdef AFL_MAIN
struct TRK_obj* TRK[ALLOC_BUCKETS];
u32 TRK_cnt[ALLOC_BUCKETS];
struct TRK_obj* TRK[ALLOC_BUCKETS]; /* 跟踪分配的内存对象数组 */
u32 TRK_cnt[ALLOC_BUCKETS]; /* 每个桶中跟踪对象的数量 */
# define alloc_report() TRK_report()
# define alloc_report() TRK_report() /* 定义alloc_report宏为TRK_report函数 */
#else
extern struct TRK_obj* TRK[ALLOC_BUCKETS];
extern u32 TRK_cnt[ALLOC_BUCKETS];
extern struct TRK_obj* TRK[ALLOC_BUCKETS]; /* 外部声明跟踪分配的内存对象数组 */
extern u32 TRK_cnt[ALLOC_BUCKETS]; /* 外部声明每个桶中跟踪对象的数量 */
# define alloc_report()
# define alloc_report() /* 在非AFL_MAIN环境下alloc_report宏为空 */
#endif /* ^AFL_MAIN */
/* Bucket-assigning function for a given pointer: */
#define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS)
/* 为给定指针分配桶的函数: */
#define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS) /* 定义桶分配宏 */
/* Add a new entry to the list of allocated objects. */
/* 将新分配的内存对象添加到跟踪列表中。 */
static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func,
u32 line) {
u32 i, bucket;
u32 line) {
u32 i, bucket;
if (!ptr) return;
if (!ptr) return; /* 如果指针为空,则返回 */
bucket = TRKH(ptr);
bucket = TRKH(ptr); /* 获取桶编号 */
/* Find a free slot in the list of entries for that bucket. */
/* 在该桶的条目列表中找到一个空闲位置。 */
for (i = 0; i < TRK_cnt[bucket]; i++)
if (!TRK[bucket][i].ptr) {
TRK[bucket][i].ptr = ptr;
TRK[bucket][i].file = (char*)file;
TRK[bucket][i].func = (char*)func;
TRK[bucket][i].line = line;
return;
}
/* No space available - allocate more. */
for (i = 0; i < TRK_cnt[bucket]; i++)
if (!TRK[bucket][i].ptr) { /* 如果找到空闲位置 */
TRK[bucket][i].ptr = ptr;
TRK[bucket][i].file = (char*)file;
TRK[bucket][i].func = (char*)func;
TRK[bucket][i].line = line;
return;
}
TRK[bucket] = DFL_ck_realloc_block(TRK[bucket],
(TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj));
/* 没有可用空间 - 分配更多空间。 */
TRK[bucket][i].ptr = ptr;
TRK[bucket][i].file = (char*)file;
TRK[bucket][i].func = (char*)func;
TRK[bucket][i].line = line;
TRK[bucket] = DFL_ck_realloc_block(TRK[bucket],
(TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj)); /* 重新分配桶的大小 */
TRK_cnt[bucket]++;
TRK[bucket][i].ptr = ptr;
TRK[bucket][i].file = (char*)file;
TRK[bucket][i].func = (char*)func;
TRK[bucket][i].line = line;
TRK_cnt[bucket]++; /* 更新桶中条目的数量 */
}
/* Remove entry from the list of allocated objects. */
/* 从分配的内存对象列表中移除条目。 */
static inline void TRK_free_buf(void* ptr, const char* file, const char* func,
u32 line) {
u32 i, bucket;
if (!ptr) return;
u32 line) {
u32 i, bucket;
bucket = TRKH(ptr);
if (!ptr) return; /* 如果指针为空,则返回 */
/* Find the element on the list... */
bucket = TRKH(ptr); /* 获取桶编号 */
for (i = 0; i < TRK_cnt[bucket]; i++)
/* 在列表中找到该元素... */
if (TRK[bucket][i].ptr == ptr) {
TRK[bucket][i].ptr = 0;
return;
}
WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)",
func, file, line);
for (i = 0; i < TRK_cnt[bucket]; i++)
if (TRK[bucket][i].ptr == ptr) { /* 如果找到匹配的指针 */
TRK[bucket][i].ptr = 0; /* 将指针设置为NULL */
return;
}
WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)",
func, file, line); /* 警告:尝试释放未分配的内存 */
}
/* Do a final report on all non-deallocated objects. */
/* 对所有未释放的对象进行最终报告。 */
static inline void TRK_report(void) {
u32 i, bucket;
u32 i, bucket;
fflush(0);
for (bucket = 0; bucket < ALLOC_BUCKETS; bucket++)
for (i = 0; i < TRK_cnt[bucket]; i++)
if (TRK[bucket][i].ptr)
WARNF("ALLOC: Memory never freed, created in %s (%s:%u)",
TRK[bucket][i].func, TRK[bucket][i].file, TRK[bucket][i].line);
fflush(0); /* 清空输出缓冲区 */
for (bucket = 0; bucket < ALLOC_BUCKETS; bucket++)
for (i = 0; i < TRK_cnt[bucket]; i++)
if (TRK[bucket][i].ptr) /* 如果指针不为空 */
WARNF("ALLOC: Memory never freed, created in %s (%s:%u)",
TRK[bucket][i].func, TRK[bucket][i].file, TRK[bucket][i].line); /* 警告:内存从未释放 */
}
/* Simple wrappers for non-debugging functions: */
/* 非调试函数的简单包装器: */
static inline void* TRK_ck_alloc(u32 size, const char* file, const char* func,
u32 line) {
void* ret = DFL_ck_alloc(size);
TRK_alloc_buf(ret, file, func, line);
return ret;
u32 line) {
void* ret = DFL_ck_alloc(size); /* 分配内存 */
TRK_alloc_buf(ret, file, func, line); /* 添加到跟踪列表 */
return ret;
}
static inline void* TRK_ck_realloc(void* orig, u32 size, const char* file,
const char* func, u32 line) {
void* ret = DFL_ck_realloc(orig, size);
TRK_free_buf(orig, file, func, line);
TRK_alloc_buf(ret, file, func, line);
return ret;
const char* func, u32 line) {
void* ret = DFL_ck_realloc(orig, size); /* 重新分配内存 */
TRK_free_buf(orig, file, func, line); /* 从跟踪列表中移除 */
TRK_alloc_buf(ret, file, func, line); /* 添加到跟踪列表 */
return ret;
}
/* 重新分配内存块,同时更新跟踪信息。 */
static inline void* TRK_ck_realloc_block(void* orig, u32 size, const char* file,
const char* func, u32 line) {
void* ret = DFL_ck_realloc_block(orig, size);
TRK_free_buf(orig, file, func, line);
TRK_alloc_buf(ret, file, func, line);
return ret;
const char* func, u32 line) {
void* ret = DFL_ck_realloc_block(orig, size); /* 调用DFL_ck_realloc_block重新分配内存 */
TRK_free_buf(orig, file, func, line); /* 从跟踪列表中移除原始内存块 */
TRK_alloc_buf(ret, file, func, line); /* 将新内存块添加到跟踪列表 */
return ret; /* 返回新内存块 */
}
/* 复制字符串并分配内存,同时更新跟踪信息。 */
static inline void* TRK_ck_strdup(u8* str, const char* file, const char* func,
u32 line) {
void* ret = DFL_ck_strdup(str);
TRK_alloc_buf(ret, file, func, line);
return ret;
u32 line) {
void* ret = DFL_ck_strdup(str); /* 调用DFL_ck_strdup复制字符串 */
TRK_alloc_buf(ret, file, func, line); /* 将新内存块添加到跟踪列表 */
return ret; /* 返回新内存块 */
}
/* 复制内存块并分配内存,同时更新跟踪信息。 */
static inline void* TRK_ck_memdup(void* mem, u32 size, const char* file,
const char* func, u32 line) {
void* ret = DFL_ck_memdup(mem, size);
TRK_alloc_buf(ret, file, func, line);
return ret;
const char* func, u32 line) {
void* ret = DFL_ck_memdup(mem, size); /* 调用DFL_ck_memdup复制内存块 */
TRK_alloc_buf(ret, file, func, line); /* 将新内存块添加到跟踪列表 */
return ret; /* 返回新内存块 */
}
/* 复制内存块并添加字符串终止符,同时更新跟踪信息。 */
static inline void* TRK_ck_memdup_str(void* mem, u32 size, const char* file,
const char* func, u32 line) {
void* ret = DFL_ck_memdup_str(mem, size);
TRK_alloc_buf(ret, file, func, line);
return ret;
const char* func, u32 line) {
void* ret = DFL_ck_memdup_str(mem, size); /* 调用DFL_ck_memdup_str复制内存块并添加终止符 */
TRK_alloc_buf(ret, file, func, line); /* 将新内存块添加到跟踪列表 */
return ret; /* 返回新内存块 */
}
/* 释放内存并更新跟踪信息。 */
static inline void TRK_ck_free(void* ptr, const char* file,
const char* func, u32 line) {
TRK_free_buf(ptr, file, func, line);
DFL_ck_free(ptr);
const char* func, u32 line) {
TRK_free_buf(ptr, file, func, line); /* 从跟踪列表中移除内存块 */
DFL_ck_free(ptr); /* 释放内存块 */
}
/* Aliasing user-facing names to tracking functions: */
/* 将用户可见的名称别名为跟踪函数: */
#define ck_alloc(_p1) \
TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_alloc宏为TRK_ck_alloc */
#define ck_alloc_nozero(_p1) \
TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
TRK_ck_alloc_nozero(_p1, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_alloc_nozero宏为TRK_ck_alloc_nozero */
#define ck_realloc(_p1, _p2) \
TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_realloc宏为TRK_ck_realloc */
#define ck_realloc_block(_p1, _p2) \
TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_realloc_block宏为TRK_ck_realloc_block */
#define ck_strdup(_p1) \
TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_strdup宏为TRK_ck_strdup */
#define ck_memdup(_p1, _p2) \
TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_memdup宏为TRK_ck_memdup */
#define ck_memdup_str(_p1, _p2) \
TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_memdup_str宏为TRK_ck_memdup_str */
#define ck_free(_p1) \
TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__) /* 定义ck_free宏为TRK_ck_free */
#endif /* ^!DEBUG_BUILD */
#endif /* ! _HAVE_ALLOC_INL_H */

@ -1,82 +1,88 @@
// 如果是Android平台且尚未定义_ANDROID_ASHMEM_H则定义它
#ifdef __ANDROID__
#ifndef _ANDROID_ASHMEM_H
#define _ANDROID_ASHMEM_H
// 包含所需的头文件
#include <fcntl.h>
#include <linux/ashmem.h>
#include <linux/ashmem.h> // 包含ashmem相关的ioctl操作
#include <linux/shm.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mman.h> // 包含内存映射函数
// 如果Android API级别大于或等于26Android 8.0则使用Bionic的shm*函数
#if __ANDROID_API__ >= 26
#define shmat bionic_shmat
#define shmctl bionic_shmctl
#define shmdt bionic_shmdt
#define shmget bionic_shmget
#endif
#include <sys/shm.h>
#include <sys/shm.h> // 包含标准的共享内存函数
#undef shmat
#undef shmctl
#undef shmdt
#undef shmget
#undef shmget // 取消对Bionic函数的重定义
#include <stdio.h>
// 定义ashmem设备的路径
#define ASHMEM_DEVICE "/dev/ashmem"
static inline int shmctl(int __shmid, int __cmd, struct shmid_ds *__buf) {
int ret = 0;
if (__cmd == IPC_RMID) {
int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL);
struct ashmem_pin pin = {0, length};
ret = ioctl(__shmid, ASHMEM_UNPIN, &pin);
close(__shmid);
}
return ret;
// 定义shmctl函数的封装用于删除共享内存
static inline int shmctl(int __shmid, int __cmd, struct shmid_ds* __buf) {
int ret = 0;
if (__cmd == IPC_RMID) {
int length = ioctl(__shmid, ASHMEM_GET_SIZE, NULL);
struct ashmem_pin pin = { 0, length };
ret = ioctl(__shmid, ASHMEM_UNPIN, &pin);
close(__shmid);
}
return ret;
}
// 定义shmget函数的封装用于创建共享内存
static inline int shmget(key_t __key, size_t __size, int __shmflg) {
(void) __shmflg;
int fd, ret;
char ourkey[11];
(void)__shmflg;
int fd, ret;
char ourkey[11];
fd = open(ASHMEM_DEVICE, O_RDWR);
if (fd < 0)
return fd;
fd = open(ASHMEM_DEVICE, O_RDWR);
if (fd < 0)
return fd;
sprintf(ourkey, "%d", __key);
ret = ioctl(fd, ASHMEM_SET_NAME, ourkey);
if (ret < 0)
goto error;
sprintf(ourkey, "%d", __key);
ret = ioctl(fd, ASHMEM_SET_NAME, ourkey);
if (ret < 0)
goto error;
ret = ioctl(fd, ASHMEM_SET_SIZE, __size);
if (ret < 0)
goto error;
ret = ioctl(fd, ASHMEM_SET_SIZE, __size);
if (ret < 0)
goto error;
return fd;
return fd;
error:
close(fd);
return ret;
close(fd);
return ret;
}
static inline void *shmat(int __shmid, const void *__shmaddr, int __shmflg) {
(void) __shmflg;
int size;
void *ptr;
// 定义shmat函数的封装用于将共享内存附加到进程地址空间
static inline void* shmat(int __shmid, const void* __shmaddr, int __shmflg) {
(void)__shmflg;
int size;
void* ptr;
size = ioctl(__shmid, ASHMEM_GET_SIZE, NULL);
if (size < 0) {
return NULL;
}
size = ioctl(__shmid, ASHMEM_GET_SIZE, NULL);
if (size < 0) {
return NULL;
}
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, __shmid, 0);
if (ptr == MAP_FAILED) {
return NULL;
}
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, __shmid, 0);
if (ptr == MAP_FAILED) {
return NULL;
}
return ptr;
return ptr;
}
#endif /* !_ANDROID_ASHMEM_H */
#endif /* !__ANDROID__ */
#endif /* !__ANDROID__ */

@ -27,8 +27,7 @@
#include "types.h"
/* Version string: */
#define VERSION "2.57b"
#define VERSION "2.57b" // 定义版本号字符串
/******************************************************
* *
@ -36,228 +35,196 @@
* *
******************************************************/
/* Comment out to disable terminal colors (note that this makes afl-analyze
a lot less nice): */
#define USE_COLOR
/* Comment out to disable terminal colors (note that this makes afl-analyze
a lot less nice): */
#define USE_COLOR // 启用终端颜色
/* Comment out to disable fancy ANSI boxes and use poor man's 7-bit UI: */
#define FANCY_BOXES
/* Comment out to disable fancy ANSI boxes and use poor man's 7-bit UI: */
#define FANCY_BOXES // 启用ANSI框绘制
/* Default timeout for fuzzed code (milliseconds). This is the upper bound,
also used for detecting hangs; the actual value is auto-scaled: */
#define EXEC_TIMEOUT 1000 // 默认超时时间(毫秒)
#define EXEC_TIMEOUT 1000
/* Timeout rounding factor when auto-scaling (milliseconds): */
#define EXEC_TM_ROUND 20
/* Timeout rounding factor when auto-scaling (milliseconds): */
#define EXEC_TM_ROUND 20 // 自动缩放时的超时舍入因子(毫秒)
/* 64bit arch MACRO */
#if (defined (__x86_64__) || defined (__arm64__) || defined (__aarch64__))
#define WORD_SIZE_64 1
#define WORD_SIZE_64 1 // 定义64位架构宏
#endif
/* Default memory limit for child process (MB): */
#ifndef WORD_SIZE_64
# define MEM_LIMIT 25
# define MEM_LIMIT 25 // 非64位架构的默认内存限制MB
#else
# define MEM_LIMIT 50
# define MEM_LIMIT 50 // 64位架构的默认内存限制MB
#endif /* ^!WORD_SIZE_64 */
/* Default memory limit when running in QEMU mode (MB): */
#define MEM_LIMIT_QEMU 200
#define MEM_LIMIT_QEMU 200 // QEMU模式下的默认内存限制MB
/* Number of calibration cycles per every new test case (and for test
cases that show variable behavior): */
#define CAL_CYCLES 8 // 每个新测试用例的校准周期数
#define CAL_CYCLES_LONG 40 // 长校准周期数
#define CAL_CYCLES 8
#define CAL_CYCLES_LONG 40
/* Number of subsequent timeouts before abandoning an input file: */
#define TMOUT_LIMIT 250
/* Number of subsequent timeouts before abandoning an input file: */
#define TMOUT_LIMIT 250 // 超时次数限制
/* Maximum number of unique hangs or crashes to record: */
#define KEEP_UNIQUE_HANG 500
#define KEEP_UNIQUE_CRASH 5000
#define KEEP_UNIQUE_HANG 500 // 最大记录的唯一挂起数
#define KEEP_UNIQUE_CRASH 5000 // 最大记录的唯一崩溃数
/* Baseline number of random tweaks during a single 'havoc' stage: */
#define HAVOC_CYCLES 256
#define HAVOC_CYCLES_INIT 1024
#define HAVOC_CYCLES 256 // 'havoc'阶段的随机调整基数
#define HAVOC_CYCLES_INIT 1024 // 'havoc'阶段的初始随机调整数
/* Maximum multiplier for the above (should be a power of two, beware
of 32-bit int overflows): */
#define HAVOC_MAX_MULT 16 // 'havoc'阶段的最大乘数
#define HAVOC_MAX_MULT 16
/* Absolute minimum number of havoc cycles (after all adjustments): */
#define HAVOC_MIN 16
/* Absolute minimum number of havoc cycles (after all adjustments): */
#define HAVOC_MIN 16 // 'havoc'阶段的绝对最小周期数
/* Maximum stacking for havoc-stage tweaks. The actual value is calculated
like this:
like this:
n = random between 1 and HAVOC_STACK_POW2
stacking = 2^n
In other words, the default (n = 7) produces 2, 4, 8, 16, 32, 64, or
128 stacked tweaks: */
#define HAVOC_STACK_POW2 7 // 'havoc'阶段的最大堆叠指数
#define HAVOC_STACK_POW2 7
/* Caps on block sizes for cloning and deletion operations. Each of these
ranges has a 33% probability of getting picked, except for the first
two cycles where smaller blocks are favored: */
#define HAVOC_BLK_SMALL 32
#define HAVOC_BLK_MEDIUM 128
#define HAVOC_BLK_LARGE 1500
/* Caps on block sizes for cloning and deletion operations. Each of these
ranges has a 33% probability of getting picked, except for the first
two cycles where smaller blocks are favored: */
#define HAVOC_BLK_SMALL 32 // 小块大小限制
#define HAVOC_BLK_MEDIUM 128 // 中块大小限制
#define HAVOC_BLK_LARGE 1500 // 大块大小限制
/* Extra-large blocks, selected very rarely (<5% of the time): */
#define HAVOC_BLK_XL 32768
/* Extra-large blocks, selected very rarely (<5% of the time): */
#define HAVOC_BLK_XL 32768 // 特大块大小限制
/* Probabilities of skipping non-favored entries in the queue, expressed as
percentages: */
#define SKIP_TO_NEW_PROB 99 // 跳过非优先队列项的概率(有新的待处理优先项)
#define SKIP_NFAV_OLD_PROB 95 // 跳过非优先队列项的概率(没有新的优先项,当前项已测试)
#define SKIP_NFAV_NEW_PROB 75 // 跳过非优先队列项的概率(没有新的优先项,当前项未测试)
#define SKIP_TO_NEW_PROB 99 /* ...when there are new, pending favorites */
#define SKIP_NFAV_OLD_PROB 95 /* ...no new favs, cur entry already fuzzed */
#define SKIP_NFAV_NEW_PROB 75 /* ...no new favs, cur entry not fuzzed yet */
/* Splicing cycle count: */
#define SPLICE_CYCLES 15
/* Splicing cycle count: */
#define SPLICE_CYCLES 15 // 拼接周期数
/* Nominal per-splice havoc cycle length: */
#define SPLICE_HAVOC 32
#define SPLICE_HAVOC 32 // 每次拼接的'havoc'周期长度
/* Maximum offset for integer addition / subtraction stages: */
#define ARITH_MAX 35
#define ARITH_MAX 35 // 整数加减阶段的最大偏移量
/* Limits for the test case trimmer. The absolute minimum chunk size; and
the starting and ending divisors for chopping up the input file: */
#define TRIM_MIN_BYTES 4 // 测试用例修剪器的最小块大小
#define TRIM_START_STEPS 16 // 测试用例修剪器的起始除数
#define TRIM_END_STEPS 1024 // 测试用例修剪器的结束除数
#define TRIM_MIN_BYTES 4
#define TRIM_START_STEPS 16
#define TRIM_END_STEPS 1024
/* Maximum size of input file, in bytes (keep under 100MB): */
#define MAX_FILE (1 * 1024 * 1024)
/* Maximum size of input file, in bytes (keep under 100MB): */
#define MAX_FILE (1 * 1024 * 1024) // 输入文件的最大大小(字节)
/* The same, for the test case minimizer: */
#define TMIN_MAX_FILE (10 * 1024 * 1024)
#define TMIN_MAX_FILE (10 * 1024 * 1024) // 测试用例最小化器的最大文件大小
/* Block normalization steps for afl-tmin: */
#define TMIN_SET_MIN_SIZE 4
#define TMIN_SET_STEPS 128
#define TMIN_SET_MIN_SIZE 4 // afl-tmin的块归一化最小大小
#define TMIN_SET_STEPS 128 // afl-tmin的块归一化步数
/* Maximum dictionary token size (-x), in bytes: */
#define MAX_DICT_FILE 128
#define MAX_DICT_FILE 128 // 最大字典令牌大小(字节)
/* Length limits for auto-detected dictionary tokens: */
#define MIN_AUTO_EXTRA 3
#define MAX_AUTO_EXTRA 32
#define MIN_AUTO_EXTRA 3 // 自动检测的字典令牌的最小长度
#define MAX_AUTO_EXTRA 32 // 自动检测的字典令牌的最大长度
/* Maximum number of user-specified dictionary tokens to use in deterministic
steps; past this point, the "extras/user" step will be still carried out,
but with proportionally lower odds: */
#define MAX_DET_EXTRAS 200 // 最大用户指定字典令牌数
#define MAX_DET_EXTRAS 200
/* Maximum number of auto-extracted dictionary tokens to actually use in fuzzing
(first value), and to keep in memory as candidates. The latter should be much
higher than the former. */
#define USE_AUTO_EXTRAS 50
#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 10)
/* Scaling factor for the effector map used to skip some of the more
expensive deterministic steps. The actual divisor is set to
2^EFF_MAP_SCALE2 bytes: */
/* Maximum number of auto-extracted dictionary tokens to actually use in fuzzing
(first value), and to keep in memory as candidates. The latter should be much
higher than the former. */
#define USE_AUTO_EXTRAS 50 // 实际用于模糊测试的自动提取字典令牌数
#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 10) // 内存中候选的自动提取字典令牌数
#define EFF_MAP_SCALE2 3
/* Scaling factor for the effector map used to skip some of the more
expensive deterministic steps. The actual divisor is set to
2^EFF_MAP_SCALE2 bytes: */
#define EFF_MAP_SCALE2 3 // 效应器映射的缩放因子
/* Minimum input file length at which the effector logic kicks in: */
#define EFF_MIN_LEN 128
/* Minimum input file length at which the effector logic kicks in: */
#define EFF_MIN_LEN 128 // 效应器逻辑触发的最小输入文件长度
/* Maximum effector density past which everything is just fuzzed
unconditionally (%): */
#define EFF_MAX_PERC 90 // 最大效应器密度(%
#define EFF_MAX_PERC 90
/* UI refresh frequency (Hz): */
#define UI_TARGET_HZ 5
/* UI refresh frequency (Hz): */
#define UI_TARGET_HZ 5 // UI刷新频率Hz
/* Fuzzer stats file and plot update intervals (sec): */
#define STATS_UPDATE_SEC 60
#define PLOT_UPDATE_SEC 5
#define STATS_UPDATE_SEC 60 // 模糊统计文件更新间隔(秒)
#define PLOT_UPDATE_SEC 5 // 模糊统计图表更新间隔(秒)
/* Smoothing divisor for CPU load and exec speed stats (1 - no smoothing). */
#define AVG_SMOOTHING 16
#define AVG_SMOOTHING 16 // CPU负载和执行速度统计的平滑除数
/* Sync interval (every n havoc cycles): */
#define SYNC_INTERVAL 5
#define SYNC_INTERVAL 5 // 同步间隔每n个havoc周期
/* Output directory reuse grace period (minutes): */
#define OUTPUT_GRACE 25
#define OUTPUT_GRACE 25 // 输出目录重用宽限期(分钟)
/* Uncomment to use simple file names (id_NNNNNN): */
// #define SIMPLE_FILES
// #define SIMPLE_FILES // 取消注释以使用简单文件名
/* List of interesting values to use in fuzzing. */
// 定义一系列有趣的值,用于模糊测试
/* 定义一组有趣的8位值用于模糊测试包括边界值和常见缓冲区大小 */
#define INTERESTING_8 \
-128, /* Overflow signed 8-bit when decremented */ \
-1, /* */ \
0, /* */ \
1, /* */ \
16, /* One-off with common buffer size */ \
32, /* One-off with common buffer size */ \
64, /* One-off with common buffer size */ \
100, /* One-off with common buffer size */ \
127 /* Overflow signed 8-bit when incremented */
-128, /* 减1时溢出的有符号8位值 */ \
-1, /* 通用的有趣值 */ \
0, /* 零值,常用于测试 */ \
1, /* 通用的有趣值 */ \
16, /* 常用缓冲区大小的偏移量 */ \
32, /* 常用缓冲区大小的偏移量 */ \
64, /* 常用缓冲区大小的偏移量 */ \
100, /* 常用缓冲区大小的偏移量 */ \
127 /* 加1时溢出的有符号8位值 */
/* 定义一组有趣的16位值用于模糊测试包括边界值和常见缓冲区大小 */
#define INTERESTING_16 \
-32768, /* Overflow signed 16-bit when decremented */ \
-129, /* Overflow signed 8-bit */ \
128, /* Overflow signed 8-bit */ \
255, /* Overflow unsig 8-bit when incremented */ \
256, /* Overflow unsig 8-bit */ \
512, /* One-off with common buffer size */ \
1000, /* One-off with common buffer size */ \
1024, /* One-off with common buffer size */ \
4096, /* One-off with common buffer size */ \
32767 /* Overflow signed 16-bit when incremented */
-32768, /* 减1时溢出的有符号16位值 */ \
-129, /* 溢出的有符号8位值 */ \
128, /* 溢出的有符号8位值 */ \
255, /* 增1时溢出的无符号8位值 */ \
256, /* 溢出的无符号8位值 */ \
512, /* 常用缓冲区大小的偏移量 */ \
1000, /* 常用缓冲区大小的偏移量 */ \
1024, /* 常用缓冲区大小的偏移量 */ \
4096, /* 常用缓冲区大小的偏移量 */ \
32767 /* 加1时溢出的有符号16位值 */
/* 定义一组有趣的32位值用于模糊测试包括边界值和大数值 */
#define INTERESTING_32 \
-2147483648LL, /* Overflow signed 32-bit when decremented */ \
-100663046, /* Large negative number (endian-agnostic) */ \
-32769, /* Overflow signed 16-bit */ \
32768, /* Overflow signed 16-bit */ \
65535, /* Overflow unsig 16-bit when incremented */ \
65536, /* Overflow unsig 16 bit */ \
100663045, /* Large positive number (endian-agnostic) */ \
2147483647 /* Overflow signed 32-bit when incremented */
-2147483648LL, /* 减1时溢出的有符号32位值 */ \
-100663046, /* 大的负数(与字节序无关) */ \
-32769, /* 溢出的有符号16位值 */ \
32768, /* 溢出的有符号16位值 */ \
65535, /* 增1时溢出的无符号16位值 */ \
65536, /* 溢出的无符号16位值 */ \
100663045, /* 大的正数(与字节序无关) */ \
2147483647 /* 加1时溢出的有符号32位值 */
/***********************************************************
* *
@ -265,98 +232,66 @@
* *
***********************************************************/
/* Call count interval between reseeding the libc PRNG from /dev/urandom: */
/* 定义 libc 伪随机数生成器重新播种的调用计数间隔 */
#define RESEED_RNG 10000
/* Maximum line length passed from GCC to 'as' and used for parsing
configuration files: */
/* 定义从 GCC 传递给 'as' 的最大行长度,并用于解析配置文件 */
#define MAX_LINE 8192
/* Environment variable used to pass SHM ID to the called program. */
/* 定义用于传递共享内存ID给被调用程序的环境变量 */
#define SHM_ENV_VAR "__AFL_SHM_ID"
/* Other less interesting, internal-only variables. */
/* 定义其他不太有趣,仅内部使用的变量 */
#define CLANG_ENV_VAR "__AFL_CLANG_MODE"
#define AS_LOOP_ENV_VAR "__AFL_AS_LOOPCHECK"
#define PERSIST_ENV_VAR "__AFL_PERSISTENT"
#define DEFER_ENV_VAR "__AFL_DEFER_FORKSRV"
/* In-code signatures for deferred and persistent mode. */
/* 定义代码中用于延迟和持久模式的签名 */
#define PERSIST_SIG "##SIG_AFL_PERSISTENT##"
#define DEFER_SIG "##SIG_AFL_DEFER_FORKSRV##"
/* Distinctive bitmap signature used to indicate failed execution: */
/* 定义用于表示执行失败的独特位图签名 */
#define EXEC_FAIL_SIG 0xfee1dead
/* Distinctive exit code used to indicate MSAN trip condition: */
/* 定义用于表示MSAN内存sanitizer触发条件的独特退出代码 */
#define MSAN_ERROR 86
/* Designated file descriptors for forkserver commands (the application will
use FORKSRV_FD and FORKSRV_FD + 1): */
/* 定义用于fork服务器命令的指定文件描述符 */
#define FORKSRV_FD 198
/* Fork server init timeout multiplier: we'll wait the user-selected
timeout plus this much for the fork server to spin up. */
/* 定义fork服务器初始化超时乘数 */
#define FORK_WAIT_MULT 10
/* Calibration timeout adjustments, to be a bit more generous when resuming
fuzzing sessions or trying to calibrate already-added internal finds.
The first value is a percentage, the other is in milliseconds: */
/* 定义校准超时调整,恢复模糊测试会话或校准已添加的内部发现时更加宽松 */
#define CAL_TMOUT_PERC 125
#define CAL_TMOUT_ADD 50
/* Number of chances to calibrate a case before giving up: */
/* 定义校准一个案例前放弃的机会数 */
#define CAL_CHANCES 3
/* Map size for the traced binary (2^MAP_SIZE_POW2). Must be greater than
2; you probably want to keep it under 18 or so for performance reasons
(adjusting AFL_INST_RATIO when compiling is probably a better way to solve
problems with complex programs). You need to recompile the target binary
after changing this - otherwise, SEGVs may ensue. */
/* 定义跟踪二进制文件的映射大小 */
#define MAP_SIZE_POW2 16
#define MAP_SIZE (1 << MAP_SIZE_POW2)
/* Maximum allocator request size (keep well under INT_MAX): */
/* 定义最大分配请求大小 */
#define MAX_ALLOC 0x40000000
/* A made-up hashing seed: */
/* 定义一个虚构的哈希种子 */
#define HASH_CONST 0xa5b35705
/* Constants for afl-gotcpu to control busy loop timing: */
/* 定义 afl-gotcpu 控制忙循环计时的常量 */
#define CTEST_TARGET_MS 5000
#define CTEST_CORE_TRG_MS 1000
#define CTEST_BUSY_CYCLES (10 * 1000 * 1000)
/* Uncomment this to use inferior block-coverage-based instrumentation. Note
that you need to recompile the target binary for this to have any effect: */
/* 如果需要使用基于块覆盖的仪器,取消注释此宏 */
// #define COVERAGE_ONLY
/* Uncomment this to ignore hit counts and output just one bit per tuple.
As with the previous setting, you will need to recompile the target
binary: */
/* 如果需要忽略命中计数并且每个元组只输出一个位,取消注释此宏 */
// #define SKIP_COUNTS
/* Uncomment this to use instrumentation data to record newly discovered paths,
but do not use them as seeds for fuzzing. This is useful for conveniently
measuring coverage that could be attained by a "dumb" fuzzing algorithm: */
/* 如果需要使用仪器数据记录新发现的路径,但不使用它们作为模糊测试的种子,取消注释此宏 */
// #define IGNORE_FINDS
#endif /* ! _HAVE_CONFIG_H */
#endif /* ! _HAVE_CONFIG_H */

@ -155,54 +155,50 @@
* Misc terminal codes *
***********************/
#define TERM_HOME "\x1b[H"
#define TERM_CLEAR TERM_HOME "\x1b[2J"
#define cEOL "\x1b[0K"
#define CURSOR_HIDE "\x1b[?25l"
#define CURSOR_SHOW "\x1b[?25h"
// 定义一些额外的终端控制代码
#define TERM_HOME "\x1b[H" // 移动光标到终端左上角
#define TERM_CLEAR TERM_HOME "\x1b[2J" // 清除终端屏幕
#define cEOL "\x1b[0K" // 清除当前行从光标位置到行尾的内容
#define CURSOR_HIDE "\x1b[?25l" // 隐藏光标
#define CURSOR_SHOW "\x1b[?25h" // 显示光标
/************************
* Debug & error macros *
************************/
/* Just print stuff to the appropriate stream. */
// 定义一些宏用于调试和错误处理
// 如果配置中定义了MESSAGES_TO_STDOUT则使用printf否则使用fprintf(stderr, ...)
#ifdef MESSAGES_TO_STDOUT
# define SAYF(x...) printf(x)
#else
# define SAYF(x...) fprintf(stderr, x)
#endif /* ^MESSAGES_TO_STDOUT */
/* Show a prefixed warning. */
// 显示带前缀的警告信息
#define WARNF(x...) do { \
SAYF(cYEL "[!] " cBRI "WARNING: " cRST x); \
SAYF(cRST "\n"); \
} while (0)
/* Show a prefixed "doing something" message. */
// 显示带前缀的“正在执行”信息
#define ACTF(x...) do { \
SAYF(cLBL "[*] " cRST x); \
SAYF(cRST "\n"); \
} while (0)
/* Show a prefixed "success" message. */
// 显示带前缀的成功信息
#define OKF(x...) do { \
SAYF(cLGN "[+] " cRST x); \
SAYF(cRST "\n"); \
} while (0)
/* Show a prefixed fatal error message (not used in afl). */
// 显示带前缀的严重错误信息不在afl中使用
#define BADF(x...) do { \
SAYF(cLRD "\n[-] " cRST x); \
SAYF(cRST "\n"); \
} while (0)
/* Die with a verbose non-OS fatal error message. */
// 以详细非操作系统致命错误消息退出程序
#define FATAL(x...) do { \
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD "\n[-] PROGRAM ABORT : " \
cBRI x); \
@ -211,8 +207,7 @@
exit(1); \
} while (0)
/* Die by calling abort() to provide a core dump. */
// 通过调用abort()退出程序以便提供core dump
#define ABORT(x...) do { \
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD "\n[-] PROGRAM ABORT : " \
cBRI x); \
@ -221,8 +216,7 @@
abort(); \
} while (0)
/* Die while also including the output of perror(). */
// 以包含perror()输出的方式退出程序
#define PFATAL(x...) do { \
fflush(stdout); \
SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD "\n[-] SYSTEM ERROR : " \
@ -233,16 +227,12 @@
exit(1); \
} while (0)
/* Die with FAULT() or PFAULT() depending on the value of res (used to
interpret different failure modes for read(), write(), etc). */
// 根据res的值调用FAULT()或PFAULT()用于解释read()、write()等的不同失败模式
#define RPFATAL(res, x...) do { \
if (res < 0) PFATAL(x); else FATAL(x); \
} while (0)
/* Error-checking versions of read() and write() that call RPFATAL() as
appropriate. */
// 定义ck_write和ck_read宏用于检查write和read操作是否成功并在失败时调用RPFATAL
#define ck_write(fd, buf, len, fn) do { \
u32 _len = (len); \
s32 _res = write(fd, buf, _len); \
@ -255,4 +245,4 @@
if (_res != _len) RPFATAL(_res, "Short read from %s", fn); \
} while (0)
#endif /* ! _HAVE_DEBUG_H */
#endif /* !_HAVE_DEBUG_H */

@ -31,81 +31,94 @@
Other code written and maintained by Michal Zalewski <lcamtuf@google.com>
*/
// 检查_HAVE_HASH_H宏是否已定义如果没有则定义它以防止头文件被重复包含
#ifndef _HAVE_HASH_H
#define _HAVE_HASH_H
// 包含types.h头文件可能包含一些基本类型的定义
#include "types.h"
// 如果编译目标是x86_64架构则定义64位循环左移宏ROL64
#ifdef __x86_64__
#define ROL64(_x, _r) ((((u64)(_x)) << (_r)) | (((u64)(_x)) >> (64 - (_r))))
// 定义一个内联函数hash32用于计算32位哈希值x86_64架构专用
static inline u32 hash32(const void* key, u32 len, u32 seed) {
const u64* data = (u64*)key;
u64 h1 = seed ^ len;
len >>= 3;
while (len--) {
u64 k1 = *data++;
k1 *= 0x87c37b91114253d5ULL;
k1 = ROL64(k1, 31);
k1 *= 0x4cf5ad432745937fULL;
h1 ^= k1;
h1 = ROL64(h1, 27);
h1 = h1 * 5 + 0x52dce729;
}
h1 ^= h1 >> 33;
h1 *= 0xff51afd7ed558ccdULL;
h1 ^= h1 >> 33;
h1 *= 0xc4ceb9fe1a85ec53ULL;
h1 ^= h1 >> 33;
return h1;
// 将key转换为u64指针
const u64* data = (u64*)key;
// 初始化哈希值h1种子与长度异或
u64 h1 = seed ^ len;
// 将长度除以8因为u64是8字节
len >>= 3;
// 循环处理每个u64数据块
while (len--) {
// 读取下一个u64数据
u64 k1 = *data++;
// 应用MurmurHash算法的步骤
k1 *= 0x87c37b91114253d5ULL;
k1 = ROL64(k1, 31);
k1 *= 0x4cf5ad432745937fULL;
// 将k1合并到h1
h1 ^= k1;
h1 = ROL64(h1, 27);
h1 = h1 * 5 + 0x52dce729;
}
// 最后的哈希值处理步骤
h1 ^= h1 >> 33;
h1 *= 0xff51afd7ed558ccdULL;
h1 ^= h1 >> 33;
h1 *= 0xc4ceb9fe1a85ec53ULL;
h1 ^= h1 >> 33;
// 返回最终的哈希值
return h1;
}
// 如果编译目标不是x86_64架构则定义32位循环左移宏ROL32
#else
#define ROL32(_x, _r) ((((u32)(_x)) << (_r)) | (((u32)(_x)) >> (32 - (_r))))
// 定义一个内联函数hash32用于计算32位哈希值非x86_64架构专用
static inline u32 hash32(const void* key, u32 len, u32 seed) {
const u32* data = (u32*)key;
u32 h1 = seed ^ len;
len >>= 2;
while (len--) {
u32 k1 = *data++;
k1 *= 0xcc9e2d51;
k1 = ROL32(k1, 15);
k1 *= 0x1b873593;
h1 ^= k1;
h1 = ROL32(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
}
h1 ^= h1 >> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >> 16;
return h1;
// 将key转换为u32指针
const u32* data = (u32*)key;
// 初始化哈希值h1种子与长度异或
u32 h1 = seed ^ len;
// 将长度除以4因为u32是4字节
len >>= 2;
// 循环处理每个u32数据块
while (len--) {
// 读取下一个u32数据
u32 k1 = *data++;
// 应用MurmurHash算法的步骤
k1 *= 0xcc9e2d51;
k1 = ROL32(k1, 15);
k1 *= 0x1b873593;
// 将k1合并到h1
h1 ^= k1;
h1 = ROL32(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
}
// 最后的哈希值处理步骤
h1 ^= h1 >> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >> 16;
// 返回最终的哈希值
return h1;
}
#endif /* ^__x86_64__ */
// 结束宏定义_HAVE_HASH_H
#endif /* !_HAVE_HASH_H */

@ -26,20 +26,28 @@
#include <stdlib.h>
#include <unistd.h>
// 定义程序的主函数接收命令行参数个数argc和参数值argv
int main(int argc, char** argv) {
char buf[8];
if (read(0, buf, 8) < 1) {
printf("Hum?\n");
exit(1);
}
if (buf[0] == '0')
printf("Looks like a zero to me!\n");
else
printf("A non-zero value? How quaint!\n");
exit(0);
// 定义一个字符数组buf大小为8用于存储从标准输入读取的数据
char buf[8];
// 尝试从文件描述符0标准输入读取最多8个字节的数据到buf中
if (read(0, buf, 8) < 1) {
// 如果读取的字节数小于1即读取失败则打印消息并退出程序
printf("Hum?\n");
exit(1);
}
// 检查buf的第一个字符是否为'0'
if (buf[0] == '0')
// 如果是'0',则打印一条消息表示检测到零值
printf("Looks like a zero to me!\n");
else
// 如果不是'0',则打印一条消息表示检测到非零值
printf("A non-zero value? How quaint!\n");
// 正常退出程序
exit(0);
}

@ -28,14 +28,20 @@
// TODO(metzman): Create a test/ directory to store this and other similar
// files.
// 定义一个名为LLVMFuzzerTestOneInput的函数用于接收一个字节数组buf和其大小size
int LLVMFuzzerTestOneInput(uint8_t* buf, size_t size) {
if (size < 2)
// 检查输入数据的大小是否小于2如果是则返回0表示测试不通过或无需进一步处理
if (size < 2)
return 0;
// 检查输入数据的第一个字节是否为'0'
if (buf[0] == '0')
// 如果是'0',则打印一条消息表示检测到零值
printf("Looks like a zero to me!\n");
else
// 如果不是'0',则打印一条消息表示检测到非零值
printf("A non-zero value? How quaint!\n");
// 函数返回0表示测试通过或没有发现异常
return 0;
if (buf[0] == '0')
printf("Looks like a zero to me!\n");
else
printf("A non-zero value? How quaint!\n");
return 0;
}

@ -48,27 +48,32 @@ typedef uint32_t u32;
*/
// 条件编译指令用于定义64位无符号整数类型
#ifdef __x86_64__
typedef unsigned long long u64;
typedef unsigned long long u64; // 在x86_64架构下使用unsigned long long作为u64
#else
typedef uint64_t u64;
typedef uint64_t u64; // 否则使用标准库中的uint64_t作为u64
#endif /* ^__x86_64__ */
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
// 定义有符号整数类型
typedef int8_t s8; // 8位有符号整数
typedef int16_t s16; // 16位有符号整数
typedef int32_t s32; // 32位有符号整数
typedef int64_t s64; // 64位有符号整数
// 如果没有定义MIN则定义宏MIN和MAX
#ifndef MIN
# define MIN(_a,_b) ((_a) > (_b) ? (_b) : (_a))
# define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b))
# define MIN(_a,_b) ((_a) > (_b) ? (_b) : (_a)) // 取两个值中的最小值
# define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b)) // 取两个值中的最大值
#endif /* !MIN */
// 宏定义SWAP16用于交换16位值的字节序
#define SWAP16(_x) ({ \
u16 _ret = (_x); \
(u16)((_ret << 8) | (_ret >> 8)); \
})
// 宏定义SWAP32用于交换32位值的字节序
#define SWAP32(_x) ({ \
u32 _ret = (_x); \
(u32)((_ret << 24) | (_ret >> 24) | \
@ -76,19 +81,23 @@ typedef int64_t s64;
((_ret >> 8) & 0x0000FF00)); \
})
// 条件编译指令,用于定义随机数宏
#ifdef AFL_LLVM_PASS
# define AFL_R(x) (random() % (x))
# define AFL_R(x) (random() % (x)) // 在AFL_LLVM_PASS模式下使用
#else
# define R(x) (random() % (x))
# define R(x) (random() % (x)) // 否则使用
#endif /* ^AFL_LLVM_PASS */
// 宏定义STRINGIFY_INTERNAL和STRINGIFY用于将宏参数转换为字符串
#define STRINGIFY_INTERNAL(x) #x
#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
// 内存屏障用于阻止编译器和CPU对指令重排
#define MEM_BARRIER() \
__asm__ volatile("" ::: "memory")
#define likely(_x) __builtin_expect(!!(_x), 1)
#define unlikely(_x) __builtin_expect(!!(_x), 0)
// 宏定义likely和unlikely用于优化分支预测
#define likely(_x) __builtin_expect(!!(_x), 1) // 预期_x为真
#define unlikely(_x) __builtin_expect(!!(_x), 0) // 预期_x为假
#endif /* ! _HAVE_TYPES_H */

Loading…
Cancel
Save