mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 14:43:22 +00:00
Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
33f3c4c7da | |||
7ad694716b | |||
e93ab23823 | |||
79a24685b2 | |||
cad7536036 | |||
1ddfb1fec2 | |||
ae8df744ee | |||
aaaa96af6d | |||
2e2a3a2718 | |||
eee4be90c1 | |||
5fe21c3797 | |||
4eaacfb095 | |||
82b0cf0540 | |||
5a352adb19 | |||
9afba51ec1 | |||
99402aa31c | |||
af11b80fda | |||
10db3a35cf | |||
af44b07b31 | |||
9b433e2d8c | |||
85e14cf8d1 | |||
f2f417325f | |||
3e18b1a10c | |||
1d3e885441 | |||
0c69d0a0d8 | |||
bbffece7d7 | |||
2956b9cc4c | |||
9160805f4a | |||
50e2f9d46c | |||
223b14134c | |||
f5a672f9d8 | |||
9ce45665d7 | |||
10883b1392 | |||
d206d5fc46 |
@ -41,10 +41,6 @@ ARCH = $(shell uname -m)
|
||||
|
||||
$(info [*] Compiling AFL++ for OS $(SYS) on ARCH $(ARCH))
|
||||
|
||||
ifdef NO_SPLICING
|
||||
override CFLAGS_OPT += -DNO_SPLICING
|
||||
endif
|
||||
|
||||
ifdef NO_UTF
|
||||
override CFLAGS_OPT += -DFANCY_BOXES_NO_UTF
|
||||
endif
|
||||
@ -65,6 +61,10 @@ ifdef MSAN_BUILD
|
||||
override CFLAGS += -fsanitize=memory -fno-omit-frame-pointer
|
||||
override LDFLAGS += -fsanitize=memory
|
||||
endif
|
||||
ifdef NO_SPLICING
|
||||
$(info The NO_SPLICING parameter is deprecated)
|
||||
endif
|
||||
|
||||
|
||||
ifdef CODE_COVERAGE
|
||||
override CFLAGS += -D__AFL_CODE_COVERAGE=1
|
||||
@ -408,7 +408,6 @@ help:
|
||||
@echo PROFILING - compile afl-fuzz with profiling information
|
||||
@echo INTROSPECTION - compile afl-fuzz with mutation introspection
|
||||
@echo NO_PYTHON - disable python support
|
||||
@echo NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
|
||||
@echo "NO_UTF - do not use UTF-8 for line rendering in status screen (fallback to G1 box drawing, of vanilla AFL)"
|
||||
@echo NO_NYX - disable building nyx mode dependencies
|
||||
@echo "NO_CORESIGHT - disable building coresight (arm64 only)"
|
||||
|
@ -28,11 +28,11 @@ MAN_PATH ?= $(PREFIX)/share/man/man8
|
||||
|
||||
BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "+%Y-%m-%d" 2>/dev/null || date -u "+%Y-%m-%d")
|
||||
|
||||
VERSION = $(shell grep '^$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
|
||||
VERSION = $(shell grep '^ *$(HASH)define VERSION ' ./config.h | cut -d '"' -f2)
|
||||
|
||||
SYS = $(shell uname -s)
|
||||
|
||||
override LLVM_TOO_NEW_DEFAULT := 18
|
||||
override LLVM_TOO_NEW_DEFAULT := 19
|
||||
override LLVM_TOO_OLD_DEFAULT := 13
|
||||
|
||||
ifeq "$(SYS)" "OpenBSD"
|
||||
@ -69,9 +69,9 @@ endif
|
||||
|
||||
LLVM_STDCXX := gnu++11
|
||||
LLVM_LTO := 0
|
||||
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.' && echo 1 || echo 0)
|
||||
LLVM_UNSUPPORTED := $(shell echo "$(LLVMVER)" | grep -E -q '^[0-2]\.|^3\.[0-7]\.|^2[0-9]\.' && echo 1 || echo 0)
|
||||
# Uncomment to see the values assigned above
|
||||
# $(foreach var,LLVM_CONFIG LLVMVER LLVM_MAJOR LLVM_MINOR LLVM_TOO_NEW LLVM_TOO_OLD LLVM_TOO_NEW_DEFAULT LLVM_TOO_OLD_DEFAULT LLVM_NEW_API LLVM_NEWER_API LLVM_13_OK LLVM_HAVE_LTO LLVM_BINDIR LLVM_LIBDIR LLVM_STDCXX LLVM_APPLE_XCODE LLVM_LTO LLVM_UNSUPPORTED,$(warning $(var) = $($(var))))
|
||||
# $(foreach var,_CLANG_VERSIONS_TO_TEST LLVM_CONFIG LLVMVER LLVM_MAJOR LLVM_MINOR LLVM_TOO_NEW LLVM_TOO_OLD LLVM_TOO_NEW_DEFAULT LLVM_TOO_OLD_DEFAULT LLVM_NEW_API LLVM_NEWER_API LLVM_13_OK LLVM_HAVE_LTO LLVM_BINDIR LLVM_LIBDIR LLVM_STDCXX LLVM_APPLE_XCODE LLVM_LTO LLVM_UNSUPPORTED,$(warning $(var) = $($(var))))
|
||||
|
||||
ifeq "$(LLVMVER)" ""
|
||||
$(warning [!] llvm_mode needs llvm-config, which was not found. Set LLVM_CONFIG to its path and retry.)
|
||||
@ -335,7 +335,7 @@ else
|
||||
endif
|
||||
|
||||
ifeq "$(SYS)" "OpenBSD"
|
||||
CLANG_LFL += $$($(LLVM_CONFIG) --libdir)/libLLVM.so
|
||||
CLANG_LFL += $(LLVM_LIBDIR)/libLLVM.so
|
||||
CLANG_CPPFL += -mno-retpoline
|
||||
CFLAGS += -mno-retpoline
|
||||
# Needed for unwind symbols
|
||||
|
@ -3,6 +3,23 @@
|
||||
This is the list of all noteworthy changes made in every public
|
||||
release of the tool. See README.md for the general instruction manual.
|
||||
|
||||
|
||||
### Version ++4.31a (dev)
|
||||
- afl-fuzz:
|
||||
- Python 3.13+ support
|
||||
- loose file and shared memory permissions on Android and iPhone
|
||||
- splicing is now DISABLED by default because research showed
|
||||
it is counterproductive. New command line parameter `-u` to enable
|
||||
it. Splicing is auto-enabled if two cycles without finds happen.
|
||||
- afl-cc:
|
||||
- -fsanitize=fuzzer now inserts libAFLDriver.a addtionally early to help
|
||||
compiling if LLVMFuzzerTestOneOnput is in an .a archive
|
||||
- added __sanitizer_weak_hook_* functions (in case that is helpful in
|
||||
weird setups)
|
||||
- fix bug with large map sizes when multiple libraries are loaded after
|
||||
the shared memory was obtained.
|
||||
|
||||
|
||||
### Version ++4.30c (release)
|
||||
! afl-gcc and afl-clang funcionality is now removed !
|
||||
- afl-fuzz:
|
||||
|
@ -90,7 +90,6 @@ These build options exist:
|
||||
* PROFILING - compile afl-fuzz with profiling information
|
||||
* INTROSPECTION - compile afl-fuzz with mutation introspection
|
||||
* NO_PYTHON - disable python support
|
||||
* NO_SPLICING - disables splicing mutation in afl-fuzz, not recommended for normal fuzzing
|
||||
* NO_UTF - do not use UTF-8 for line rendering in status screen (fallback to G1 box drawing, of vanilla AFL)
|
||||
* NO_NYX - disable building nyx mode dependencies
|
||||
* NO_CORESIGHT - disable building coresight (arm64 only)
|
||||
|
@ -9,5 +9,11 @@ echo Newest available version: $NEW
|
||||
|
||||
test -z "$OLD" -o -z "$NEW" -o "$OLD" = "$NEW" && { echo Nothing to be done. ; exit 0 ; }
|
||||
|
||||
sed -i "s/=$OLD/=$NEW/" GNUmakefile || exit 1
|
||||
# Determine the correct sed command
|
||||
case $(sed --help 2>&1) in
|
||||
*GNU*) set sed -i;;
|
||||
*) set sed -i '';;
|
||||
esac
|
||||
|
||||
"$@" "s/=$OLD/=$NEW/" GNUmakefile || exit 1
|
||||
echo Successfully updated GNUmakefile
|
||||
|
@ -747,7 +747,7 @@ typedef struct afl_state {
|
||||
up to 256 */
|
||||
|
||||
unsigned long long int last_avg_exec_update;
|
||||
u32 last_avg_execs;
|
||||
u64 last_avg_total_execs;
|
||||
double last_avg_execs_saved;
|
||||
|
||||
/* foreign sync */
|
||||
|
@ -26,7 +26,7 @@
|
||||
/* Version string: */
|
||||
|
||||
// c = release, a = volatile github dev, e = experimental branch
|
||||
#define VERSION "++4.30c"
|
||||
#define VERSION "++4.31a"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
@ -52,6 +52,18 @@
|
||||
/* Default file permission umode when creating files (default: 0600) */
|
||||
#define DEFAULT_PERMISSION 0600
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_OS_IOS
|
||||
#undef DEFAULT_PERMISSION
|
||||
#define DEFAULT_PERMISSION 0666
|
||||
#endif
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
#undef DEFAULT_PERMISSION
|
||||
#define DEFAULT_PERMISSION 0666
|
||||
#endif
|
||||
|
||||
/* SkipDet's global configuration */
|
||||
|
||||
#define MINIMAL_BLOCK_SIZE 64
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __AFL_CODE_COVERAGE
|
||||
@ -358,7 +357,7 @@ static void __afl_map_shm(void) {
|
||||
|
||||
if (__afl_final_loc) {
|
||||
|
||||
__afl_map_size = ++__afl_final_loc; // as we count starting 0
|
||||
__afl_map_size = __afl_final_loc + 1; // as we count starting 0
|
||||
|
||||
if (getenv("AFL_DUMP_MAP_SIZE")) {
|
||||
|
||||
@ -601,9 +600,9 @@ static void __afl_map_shm(void) {
|
||||
|
||||
}
|
||||
|
||||
__afl_area_ptr_dummy = (u8 *)malloc(__afl_final_loc);
|
||||
__afl_map_size = __afl_final_loc + 1;
|
||||
__afl_area_ptr_dummy = (u8 *)malloc(__afl_map_size);
|
||||
__afl_area_ptr = __afl_area_ptr_dummy;
|
||||
__afl_map_size = __afl_final_loc;
|
||||
|
||||
if (!__afl_area_ptr_dummy) {
|
||||
|
||||
@ -2670,6 +2669,89 @@ void __cmplog_rtn_llvm_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) {
|
||||
|
||||
}
|
||||
|
||||
/* llvm weak hooks */
|
||||
|
||||
void __sanitizer_weak_hook_memcmp(void *pc, const void *s1, const void *s2,
|
||||
size_t n, int result) {
|
||||
|
||||
__cmplog_rtn_hook_n((u8 *)s1, (u8 *)s2, (u64)n);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_memmem(void *pc, const void *s1, size_t len1,
|
||||
const void *s2, size_t len2, void *result) {
|
||||
|
||||
__cmplog_rtn_hook_n((u8 *)s1, (u8 *)s2, len1 < len2 ? (u64)len1 : (u64)len2);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strncasecmp(void *pc, const void *s1, const void *s2,
|
||||
size_t n, int result) {
|
||||
|
||||
__cmplog_rtn_hook_strn((u8 *)s1, (u8 *)s2, (u64)n);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strncasestr(void *pc, const void *s1, const void *s2,
|
||||
size_t n, char *result) {
|
||||
|
||||
__cmplog_rtn_hook_strn((u8 *)s1, (u8 *)s2, (u64)n);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strncmp(void *pc, const void *s1, const void *s2,
|
||||
size_t n, int result) {
|
||||
|
||||
__cmplog_rtn_hook_strn((u8 *)s1, (u8 *)s2, (u64)n);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strcasecmp(void *pc, const void *s1, const void *s2,
|
||||
int result) {
|
||||
|
||||
__cmplog_rtn_hook_str((u8 *)s1, (u8 *)s2);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strcasestr(void *pc, const void *s1, const void *s2,
|
||||
size_t n, char *result) {
|
||||
|
||||
__cmplog_rtn_hook_str((u8 *)s1, (u8 *)s2);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strcmp(void *pc, const void *s1, const void *s2,
|
||||
int result) {
|
||||
|
||||
__cmplog_rtn_hook_str((u8 *)s1, (u8 *)s2);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strstr(void *pc, const void *s1, const void *s2,
|
||||
char *result) {
|
||||
|
||||
__cmplog_rtn_hook_str((u8 *)s1, (u8 *)s2);
|
||||
(void)pc;
|
||||
(void)result;
|
||||
|
||||
}
|
||||
|
||||
/* COVERAGE manipulation features */
|
||||
|
||||
// this variable is then used in the shm setup to create an additional map
|
||||
|
@ -695,14 +695,18 @@ static void set_up_environment(char **argv) {
|
||||
ck_free(frida_binary);
|
||||
|
||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
/* CoreSight mode uses the default behavior. */
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@ -710,7 +714,9 @@ static void set_up_environment(char **argv) {
|
||||
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
setenv("LD_PRELOAD", frida_binary, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
|
||||
#endif
|
||||
ck_free(frida_binary);
|
||||
|
||||
}
|
||||
|
79
src/afl-cc.c
79
src/afl-cc.c
@ -1764,6 +1764,41 @@ static u8 fsanitize_fuzzer_comma(char *string) {
|
||||
|
||||
}
|
||||
|
||||
/* Add params to link with libAFLDriver.a on request */
|
||||
static void add_aflpplib(aflcc_state_t *aflcc) {
|
||||
|
||||
if (!aflcc->need_aflpplib) return;
|
||||
|
||||
u8 *afllib = find_object(aflcc, "libAFLDriver.a");
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
|
||||
|
||||
}
|
||||
|
||||
if (!afllib) {
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
WARNF(
|
||||
"Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
|
||||
"the flags - this will fail!");
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
insert_param(aflcc, afllib);
|
||||
|
||||
#ifdef __APPLE__
|
||||
insert_param(aflcc, "-Wl,-undefined,dynamic_lookup");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Parse and process possible -fsanitize related args, return PARAM_MISS
|
||||
if nothing matched. We have 3 main tasks here for these args:
|
||||
@ -1777,6 +1812,7 @@ static u8 fsanitize_fuzzer_comma(char *string) {
|
||||
param_st parse_fsanitize(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan) {
|
||||
|
||||
param_st final_ = PARAM_MISS;
|
||||
u8 insert = 0;
|
||||
|
||||
// MACRO START
|
||||
#define HAVE_SANITIZER_SCAN_KEEP(v, k) \
|
||||
@ -1822,6 +1858,7 @@ param_st parse_fsanitize(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan) {
|
||||
if (scan) {
|
||||
|
||||
aflcc->need_aflpplib = 1;
|
||||
insert = 1;
|
||||
final_ = PARAM_SCAN;
|
||||
|
||||
} else {
|
||||
@ -1842,6 +1879,7 @@ param_st parse_fsanitize(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan) {
|
||||
if (fsanitize_fuzzer_comma(cur_argv_)) {
|
||||
|
||||
aflcc->need_aflpplib = 1;
|
||||
insert = 1;
|
||||
final_ = PARAM_SCAN;
|
||||
|
||||
}
|
||||
@ -1882,7 +1920,8 @@ param_st parse_fsanitize(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan) {
|
||||
|
||||
}
|
||||
|
||||
if (final_ == PARAM_KEEP) insert_param(aflcc, cur_argv);
|
||||
if (final_ == PARAM_KEEP) { insert_param(aflcc, cur_argv); }
|
||||
if (insert) { add_aflpplib(aflcc); }
|
||||
|
||||
return final_;
|
||||
|
||||
@ -2352,41 +2391,6 @@ void add_lto_passes(aflcc_state_t *aflcc) {
|
||||
|
||||
}
|
||||
|
||||
/* Add params to link with libAFLDriver.a on request */
|
||||
static void add_aflpplib(aflcc_state_t *aflcc) {
|
||||
|
||||
if (!aflcc->need_aflpplib) return;
|
||||
|
||||
u8 *afllib = find_object(aflcc, "libAFLDriver.a");
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
|
||||
|
||||
}
|
||||
|
||||
if (!afllib) {
|
||||
|
||||
if (!be_quiet) {
|
||||
|
||||
WARNF(
|
||||
"Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
|
||||
"the flags - this will fail!");
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
insert_param(aflcc, afllib);
|
||||
|
||||
#ifdef __APPLE__
|
||||
insert_param(aflcc, "-Wl,-undefined,dynamic_lookup");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Add params to link with runtimes depended by our instrumentation */
|
||||
void add_runtime(aflcc_state_t *aflcc) {
|
||||
|
||||
@ -2479,7 +2483,7 @@ void add_runtime(aflcc_state_t *aflcc) {
|
||||
|
||||
#endif
|
||||
|
||||
add_aflpplib(aflcc);
|
||||
add_aflpplib(aflcc); // double insertion helps compiling
|
||||
|
||||
#if defined(USEMMAP) && !defined(__HAIKU__) && !__APPLE__
|
||||
insert_param(aflcc, "-Wl,-lrt");
|
||||
@ -2614,6 +2618,7 @@ void add_misc_params(aflcc_state_t *aflcc) {
|
||||
insert_param(aflcc, "-fno-builtin-strcasecmp");
|
||||
insert_param(aflcc, "-fno-builtin-strncasecmp");
|
||||
insert_param(aflcc, "-fno-builtin-memcmp");
|
||||
insert_param(aflcc, "-fno-builtin-memmem");
|
||||
insert_param(aflcc, "-fno-builtin-bcmp");
|
||||
insert_param(aflcc, "-fno-builtin-strstr");
|
||||
insert_param(aflcc, "-fno-builtin-strcasestr");
|
||||
|
@ -220,14 +220,60 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
|
||||
if (py_module != NULL) {
|
||||
|
||||
u8 py_notrim = 0;
|
||||
#if PY_MINOR_VERSION > 12 || PY_MAJOR_VERSION > 3
|
||||
PyObject_GetOptionalAttrString(py_module, "init",
|
||||
&py_functions[PY_FUNC_INIT]);
|
||||
#else
|
||||
py_functions[PY_FUNC_INIT] = PyObject_GetAttrString(py_module, "init");
|
||||
#endif
|
||||
if (!py_functions[PY_FUNC_INIT]) {
|
||||
|
||||
WARNF("init function not found in python module");
|
||||
|
||||
}
|
||||
|
||||
#if PY_MINOR_VERSION > 12 || PY_MAJOR_VERSION > 3
|
||||
PyObject_GetOptionalAttrString(py_module, "fuzz",
|
||||
&py_functions[PY_FUNC_FUZZ]);
|
||||
#else
|
||||
py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz");
|
||||
#endif
|
||||
#if PY_MINOR_VERSION > 12 || PY_MAJOR_VERSION > 3
|
||||
if (!py_functions[PY_FUNC_FUZZ])
|
||||
PyObject_GetOptionalAttrString(py_module, "mutate",
|
||||
&py_functions[PY_FUNC_FUZZ]);
|
||||
PyObject_GetOptionalAttrString(py_module, "describe",
|
||||
&py_functions[PY_FUNC_DESCRIBE]);
|
||||
PyObject_GetOptionalAttrString(py_module, "fuzz_count",
|
||||
&py_functions[PY_FUNC_FUZZ_COUNT]);
|
||||
PyObject_GetOptionalAttrString(py_module, "post_process",
|
||||
&py_functions[PY_FUNC_POST_PROCESS]);
|
||||
PyObject_GetOptionalAttrString(py_module, "init_trim",
|
||||
&py_functions[PY_FUNC_INIT_TRIM]);
|
||||
PyObject_GetOptionalAttrString(py_module, "post_trim",
|
||||
&py_functions[PY_FUNC_POST_TRIM]);
|
||||
PyObject_GetOptionalAttrString(py_module, "trim",
|
||||
&py_functions[PY_FUNC_TRIM]);
|
||||
PyObject_GetOptionalAttrString(py_module, "havoc_mutation",
|
||||
&py_functions[PY_FUNC_HAVOC_MUTATION]);
|
||||
PyObject_GetOptionalAttrString(
|
||||
py_module, "havoc_mutation_probability",
|
||||
&py_functions[PY_FUNC_HAVOC_MUTATION_PROBABILITY]);
|
||||
PyObject_GetOptionalAttrString(py_module, "queue_get",
|
||||
&py_functions[PY_FUNC_QUEUE_GET]);
|
||||
PyObject_GetOptionalAttrString(py_module, "fuzz_send",
|
||||
&py_functions[PY_FUNC_FUZZ_SEND]);
|
||||
PyObject_GetOptionalAttrString(py_module, "post_run",
|
||||
&py_functions[PY_FUNC_POST_RUN]);
|
||||
PyObject_GetOptionalAttrString(py_module, "splice_optout",
|
||||
&py_functions[PY_FUNC_SPLICE_OPTOUT]);
|
||||
PyObject_GetOptionalAttrString(py_module, "queue_new_entry",
|
||||
&py_functions[PY_FUNC_QUEUE_NEW_ENTRY]);
|
||||
PyObject_GetOptionalAttrString(py_module, "introspection",
|
||||
&py_functions[PY_FUNC_INTROSPECTION]);
|
||||
PyObject_GetOptionalAttrString(py_module, "deinit",
|
||||
&py_functions[PY_FUNC_DEINIT]);
|
||||
#else
|
||||
if (!py_functions[PY_FUNC_FUZZ])
|
||||
py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "mutate");
|
||||
py_functions[PY_FUNC_DESCRIBE] =
|
||||
@ -253,12 +299,13 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
|
||||
PyObject_GetAttrString(py_module, "post_run");
|
||||
py_functions[PY_FUNC_SPLICE_OPTOUT] =
|
||||
PyObject_GetAttrString(py_module, "splice_optout");
|
||||
if (py_functions[PY_FUNC_SPLICE_OPTOUT]) { afl->custom_splice_optout = 1; }
|
||||
py_functions[PY_FUNC_QUEUE_NEW_ENTRY] =
|
||||
PyObject_GetAttrString(py_module, "queue_new_entry");
|
||||
py_functions[PY_FUNC_INTROSPECTION] =
|
||||
PyObject_GetAttrString(py_module, "introspection");
|
||||
py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit");
|
||||
#endif
|
||||
if (py_functions[PY_FUNC_SPLICE_OPTOUT]) { afl->custom_splice_optout = 1; }
|
||||
if (!py_functions[PY_FUNC_DEINIT])
|
||||
WARNF("deinit function not found in python module");
|
||||
|
||||
|
@ -104,9 +104,6 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
|
||||
afl->min_length = 1;
|
||||
afl->max_length = MAX_FILE;
|
||||
afl->switch_fuzz_mode = STRATEGY_SWITCH_TIME * 1000;
|
||||
#ifndef NO_SPLICING
|
||||
afl->use_splicing = 1;
|
||||
#endif
|
||||
afl->q_testcase_max_cache_size = TESTCASE_CACHE_SIZE * 1048576UL;
|
||||
afl->q_testcase_max_cache_entries = 64 * 1024;
|
||||
|
||||
|
@ -340,9 +340,9 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
||||
cur_time - afl->last_avg_exec_update >= 60000))) {
|
||||
|
||||
afl->last_avg_execs_saved =
|
||||
(double)(1000 * (afl->fsrv.total_execs - afl->last_avg_execs)) /
|
||||
(double)(1000 * (afl->fsrv.total_execs - afl->last_avg_total_execs)) /
|
||||
(double)(cur_time - afl->last_avg_exec_update);
|
||||
afl->last_avg_execs = afl->fsrv.total_execs;
|
||||
afl->last_avg_total_execs = afl->fsrv.total_execs;
|
||||
afl->last_avg_exec_update = cur_time;
|
||||
|
||||
}
|
||||
|
112
src/afl-fuzz.c
112
src/afl-fuzz.c
@ -170,7 +170,7 @@ static void at_exit() {
|
||||
|
||||
if (pid2 > 0) {
|
||||
|
||||
pgrp = getpgid(pid1);
|
||||
pgrp = getpgid(pid2);
|
||||
if (pgrp > 0) { killpg(pgrp, kill_signal); }
|
||||
kill(pid2, kill_signal);
|
||||
|
||||
@ -238,6 +238,7 @@ static void usage(u8 *argv0, int more_help) {
|
||||
"immediately,\n"
|
||||
" -1 = immediately and together with normal mutation.\n"
|
||||
" Note: this option is usually not very effective\n"
|
||||
" -u - enable testcase splicing\n"
|
||||
" -c program - enable CmpLog by specifying a binary compiled for "
|
||||
"it.\n"
|
||||
" if using QEMU/FRIDA or the fuzzing target is "
|
||||
@ -443,10 +444,6 @@ static void usage(u8 *argv0, int more_help) {
|
||||
SAYF("Compiled with ASAN_BUILD.\n");
|
||||
#endif
|
||||
|
||||
#ifdef NO_SPLICING
|
||||
SAYF("Compiled with NO_SPLICING.\n");
|
||||
#endif
|
||||
|
||||
#ifdef FANCY_BOXES_NO_UTF
|
||||
SAYF("Compiled without UTF-8 support for line rendering in status screen.\n");
|
||||
#endif
|
||||
@ -611,7 +608,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
// still available: HjJkKqruvwz
|
||||
while ((opt = getopt(argc, argv,
|
||||
"+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:"
|
||||
"T:UV:WXx:YzZ")) > 0) {
|
||||
"T:uUV:WXx:YzZ")) > 0) {
|
||||
|
||||
switch (opt) {
|
||||
|
||||
@ -699,6 +696,10 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
afl->old_seed_selection = 1;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
afl->use_splicing = 1;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
afl->infoexec = optarg;
|
||||
break;
|
||||
@ -1965,7 +1966,9 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
ck_free(frida_binary);
|
||||
|
||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@ -1974,7 +1977,9 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
/* CoreSight mode uses the default behavior. */
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@ -1992,7 +1997,9 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
OKF("Injecting %s ...", frida_binary);
|
||||
setenv("LD_PRELOAD", frida_binary, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
|
||||
#endif
|
||||
ck_free(frida_binary);
|
||||
|
||||
}
|
||||
@ -2957,64 +2964,53 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
++afl->cycles_wo_finds;
|
||||
|
||||
if (afl->use_splicing) {
|
||||
if (unlikely(afl->shm.cmplog_mode &&
|
||||
afl->cmplog_max_filesize < MAX_FILE)) {
|
||||
|
||||
if (unlikely(afl->shm.cmplog_mode &&
|
||||
afl->cmplog_max_filesize < MAX_FILE)) {
|
||||
afl->cmplog_max_filesize <<= 4;
|
||||
|
||||
afl->cmplog_max_filesize <<= 4;
|
||||
}
|
||||
|
||||
}
|
||||
switch (afl->expand_havoc) {
|
||||
|
||||
switch (afl->expand_havoc) {
|
||||
case 0:
|
||||
// this adds extra splicing mutation options to havoc mode
|
||||
afl->expand_havoc = 1;
|
||||
break;
|
||||
case 1:
|
||||
// add MOpt mutator
|
||||
/*
|
||||
if (afl->limit_time_sig == 0 && !afl->custom_only &&
|
||||
!afl->python_only) {
|
||||
|
||||
case 0:
|
||||
// this adds extra splicing mutation options to havoc mode
|
||||
afl->expand_havoc = 1;
|
||||
break;
|
||||
case 1:
|
||||
// add MOpt mutator
|
||||
/*
|
||||
if (afl->limit_time_sig == 0 && !afl->custom_only &&
|
||||
!afl->python_only) {
|
||||
afl->limit_time_sig = -1;
|
||||
afl->limit_time_puppet = 0;
|
||||
|
||||
afl->limit_time_sig = -1;
|
||||
afl->limit_time_puppet = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
afl->expand_havoc = 2;
|
||||
if (afl->cmplog_lvl && afl->cmplog_lvl < 2) afl->cmplog_lvl = 2;
|
||||
break;
|
||||
case 2:
|
||||
// increase havoc mutations per fuzz attempt
|
||||
afl->havoc_stack_pow2++;
|
||||
afl->expand_havoc = 3;
|
||||
break;
|
||||
case 3:
|
||||
// further increase havoc mutations per fuzz attempt
|
||||
afl->havoc_stack_pow2++;
|
||||
afl->expand_havoc = 4;
|
||||
break;
|
||||
case 4:
|
||||
afl->expand_havoc = 5;
|
||||
// if (afl->cmplog_lvl && afl->cmplog_lvl < 3) afl->cmplog_lvl =
|
||||
// 3;
|
||||
break;
|
||||
case 5:
|
||||
// nothing else currently
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
#ifndef NO_SPLICING
|
||||
afl->use_splicing = 1;
|
||||
#else
|
||||
afl->use_splicing = 0;
|
||||
#endif
|
||||
*/
|
||||
afl->expand_havoc = 2;
|
||||
if (afl->cmplog_lvl && afl->cmplog_lvl < 2) afl->cmplog_lvl = 2;
|
||||
break;
|
||||
case 2:
|
||||
// increase havoc mutations per fuzz attempt
|
||||
afl->havoc_stack_pow2++;
|
||||
afl->expand_havoc = 3;
|
||||
break;
|
||||
case 3:
|
||||
// further increase havoc mutations per fuzz attempt
|
||||
afl->havoc_stack_pow2++;
|
||||
afl->expand_havoc = 4;
|
||||
break;
|
||||
case 4:
|
||||
afl->expand_havoc = 5;
|
||||
// if (afl->cmplog_lvl && afl->cmplog_lvl < 3) afl->cmplog_lvl =
|
||||
// 3;
|
||||
break;
|
||||
case 5:
|
||||
// if we did not use splicing (default) then activate it
|
||||
afl->use_splicing = 1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
@ -3430,7 +3426,7 @@ stop_fuzzing:
|
||||
|
||||
ZLIBCLOSE(fr_fd);
|
||||
afl->var_byte_count = count_bytes(afl, afl->var_bytes);
|
||||
OKF("Written fastresume.bin with %u bytes!", w);
|
||||
OKF("fastresume.bin succesfully written with %u bytes.", w);
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -740,14 +740,18 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
|
||||
ck_free(frida_binary);
|
||||
|
||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
/* CoreSight mode uses the default behavior. */
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@ -755,7 +759,9 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
setenv("LD_PRELOAD", frida_binary, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
|
||||
#endif
|
||||
ck_free(frida_binary);
|
||||
|
||||
}
|
||||
|
@ -714,14 +714,18 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
|
||||
ck_free(frida_binary);
|
||||
|
||||
setenv("LD_PRELOAD", frida_afl_preload, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
/* CoreSight mode uses the default behavior. */
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@ -729,7 +733,9 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so");
|
||||
setenv("LD_PRELOAD", frida_binary, 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1);
|
||||
#endif
|
||||
ck_free(frida_binary);
|
||||
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ test -e ../afl-gcc-fast -a -e ../afl-compiler-rt.o && {
|
||||
|
||||
# now for the special gcc_plugin things
|
||||
echo foobar.c > instrumentlist.txt
|
||||
AFL_COMPILER_INSTRUMENT_FILE=instrumentlist.txt ../afl-gcc-fast -o test-compcov test-compcov.c > /dev/null 2>&1
|
||||
AFL_GCC_INSTRUMENT_FILE=instrumentlist.txt ../afl-gcc-fast -o test-compcov test-compcov.c > /dev/null 2>&1
|
||||
test -x test-compcov && test_compcov_binary_functionality ./test-compcov && {
|
||||
echo 1 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o - -r -- ./test-compcov 2>&1 | grep -q "Captured 0 tuples" && {
|
||||
$ECHO "$GREEN[+] gcc_plugin instrumentlist feature works correctly"
|
||||
|
@ -1 +1 @@
|
||||
2abdcd3c
|
||||
fb3d2151
|
||||
|
Submodule unicorn_mode/unicornafl updated: 2abdcd3c79...fb3d215198
@ -56,6 +56,10 @@ Here's a quick overview of the stuff you can find in this directory:
|
||||
|
||||
- libpng_no_checksum - a sample patch for removing CRC checks in libpng.
|
||||
|
||||
- mutation_chain - a tool that backtraces the mutation chain of AFL
|
||||
crash files based on the crash/queue file naming
|
||||
standards and outputs this in a json format.
|
||||
|
||||
- persistent_mode - an example of how to use the LLVM persistent process
|
||||
mode to speed up certain fuzzing jobs.
|
||||
|
||||
|
@ -233,7 +233,9 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
|
||||
} else {
|
||||
|
||||
setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
|
||||
#ifdef __APPLE__
|
||||
setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ Once you have built AFL++, you can choose out of two approaches:
|
||||
|
||||
## Simple Selection with `AFL_PC_FILTER`
|
||||
|
||||
This approach requires a build with `AFL_INSTRUMENTATION=llvmnative` or
|
||||
This approach requires a build with `AFL_LLVM_INSTRUMENT=llvmnative` or
|
||||
`llvmcodecov` as well as an AddressSanitizer build with debug information.
|
||||
|
||||
By setting the environment variable `AFL_PC_FILTER` to a string, the runtime
|
||||
@ -52,7 +52,7 @@ PC. It also works well with Nyx, where symbolizing is usually disabled for the
|
||||
target process to avoid delays with frequent crashes.
|
||||
|
||||
Similar to the previous method, This approach requires a build with
|
||||
`AFL_INSTRUMENTATION=llvmnative` or `llvmcodecov` as well debug information.
|
||||
`AFL_LLVM_INSTRUMENT=llvmnative` or `llvmcodecov` as well debug information.
|
||||
However, it does not require the ASan runtime as it doesn't do the symbolizing
|
||||
in process. Due to the way it maps PCs to symbols, it is less accurate when it
|
||||
comes to includes and inlines (it assumes all PCs within a function belong to
|
||||
|
154
utils/mutation_chain/mutation_chain.py
Normal file
154
utils/mutation_chain/mutation_chain.py
Normal file
@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# MUTATION CHAIN COMPUTATION TOOL
|
||||
#
|
||||
# Ever wondered what the complete history of your AFL crash file looks like?
|
||||
# Now you can!
|
||||
#
|
||||
# This tool is developed to support file structures for parallel fuzzing runs using the
|
||||
# naming of main/secondary nodes as stated in the AFL docs (fuzzer01, fuzzer02 etc...)
|
||||
# In case you want to use it for single node runs just recreate the directory structure
|
||||
# which is used when parallel fuzzing is used (dump your results in a dir called fuzzer01).
|
||||
#
|
||||
# author: Maarten Dekker
|
||||
|
||||
# import required modules
|
||||
import os, re, json
|
||||
import argparse
|
||||
|
||||
crashes = {}
|
||||
queues = {}
|
||||
|
||||
def fillDictWithFilenameKeys(dir):
|
||||
dict = {}
|
||||
for filename in os.listdir(dir):
|
||||
if re.match("^id:\\d+", filename):
|
||||
dict[filename] = None
|
||||
return dict
|
||||
|
||||
# recusively compute the chain of queue items that led to the AFL crash file
|
||||
def compute_mutation_chain(filename, current_fuzzer, n):
|
||||
|
||||
if re.match(".*src:(\\d+),", filename):
|
||||
|
||||
source_id = re.match(".*src:(\\d+),", filename).group(1)
|
||||
file_we_look_for_rex = "^id:" + source_id + ","
|
||||
|
||||
fuzzer_queue = None
|
||||
|
||||
# determine if we need to look in the queue of another fuzzer instance
|
||||
if re.match(".*sync:(fuzzer\\d+),", filename):
|
||||
fuzzer_queue = re.match(".*sync:(fuzzer\\d+),", filename).group(1)
|
||||
else:
|
||||
fuzzer_queue = current_fuzzer
|
||||
|
||||
for k,v in queues[fuzzer_queue].items():
|
||||
|
||||
if re.match(file_we_look_for_rex, k):
|
||||
|
||||
retval = {}
|
||||
retval[k] = compute_mutation_chain(k, fuzzer_queue, n+1)
|
||||
return retval
|
||||
|
||||
# if the mutation result is a splice it thas 2 sources
|
||||
elif re.match(".*src:(\\d+)\\+(\\d+)", filename):
|
||||
|
||||
sources = re.match(".*src:(\\d+)\\+(\\d+)", filename)
|
||||
|
||||
source_id_1 = sources.group(1)
|
||||
source_id_2 = sources.group(2)
|
||||
|
||||
file_we_look_for_1_rex = "^id:" + source_id_1 + ","
|
||||
file_we_look_for_2_rex = "^id:" + source_id_2 + ","
|
||||
|
||||
# for mutation with two sources, the sources are never synced form other queues
|
||||
retval = {}
|
||||
|
||||
for k,v in queues[current_fuzzer].items():
|
||||
|
||||
if re.match(file_we_look_for_1_rex, k):
|
||||
retval[k] = compute_mutation_chain(k, current_fuzzer, n+1)
|
||||
|
||||
elif re.match(file_we_look_for_2_rex, k):
|
||||
retval[k] = compute_mutation_chain(k, current_fuzzer, n+1)
|
||||
|
||||
return retval
|
||||
|
||||
else:
|
||||
return "seed"
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='mutation_chain.py',
|
||||
description='Compute the mutation chain of AFL crash files to visulise the mutation history from seed files to crash' +
|
||||
'This tool just dump json data to the CLI, it is advised to echo them into a file for further analysis (i.e. [command] >> your_file.json)',
|
||||
epilog='Greetings from old zealand'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-m", "--mode",
|
||||
choices = ['single', 'all'],
|
||||
help = 'compute chain for one file or all crash files in supplied directory. In single mode the -f argument is required',
|
||||
required = True
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-i", "--input",
|
||||
action = 'store',
|
||||
help = 'Input directory for the mutation chain tool (the fuzzer\'s output directory)',
|
||||
required = True
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-n", "--node",
|
||||
action = 'store',
|
||||
help = '[Only used in single mode; optinal] name of the fuzzer node that contains the crash file supplied in the --file argument (e.g. \'fuzzer03\'). Defaults to \'fuzzer01\' if not supplied',
|
||||
required = False
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-f", "--file",
|
||||
action = 'store',
|
||||
help = '[Only used in single mode; required] filename of specific crash file (e.g. \'id:000008,sig:06,src:000005,op:havoc,rep:8\')',
|
||||
required = False
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.mode == "single":
|
||||
|
||||
if args.node == None:
|
||||
args.node = "fuzzer01"
|
||||
|
||||
if args.file == None:
|
||||
parser.error("'--mode single' requires the '--file' argument.")
|
||||
|
||||
crash_file_path = args.input + '/' + args.node + '/crashes/' + args.file
|
||||
if not os.path.isfile(crash_file_path):
|
||||
print("Error: \'" + crash_file_path + "\' does not exist.\nPlease verify whether the node and filename are correct.")
|
||||
return
|
||||
|
||||
# Create the interal representation of the various queues of parallel fuzzing nodes
|
||||
for dir in os.listdir(args.input):
|
||||
if re.match("^fuzzer\\d+", dir):
|
||||
queues[dir] = fillDictWithFilenameKeys(args.input + '/' + dir + '/queue')
|
||||
|
||||
if args.mode == "all":
|
||||
|
||||
for dir in os.listdir(args.input):
|
||||
if re.match("^fuzzer\\d+", dir):
|
||||
for filename in os.listdir(args.input + '/' + dir + "/crashes"):
|
||||
if re.match("^id:\\d+", filename):
|
||||
print(filename)
|
||||
crashes[filename] = compute_mutation_chain(filename, dir, 0)
|
||||
|
||||
elif args.mode == "single":
|
||||
|
||||
crashes[args.file] = compute_mutation_chain(args.file, args.node, 0)
|
||||
|
||||
print(json.dumps(crashes, sort_keys=True, indent=4))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Reference in New Issue
Block a user