Skip to content
This repository was archived by the owner on Mar 22, 2024. It is now read-only.

Commit ffe21fa

Browse files
committed
Hot-path acceleration: one-pass scan and vectorization
1 parent 63eb62a commit ffe21fa

File tree

4 files changed

+123
-3
lines changed

4 files changed

+123
-3
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ MISC_PATH = $(PREFIX)/share/afl
2727
PROGS = afl-gcc afl-fuzz afl-showmap afl-tmin afl-gotcpu afl-analyze
2828
SH_PROGS = afl-plot afl-cmin afl-whatsup
2929

30-
CFLAGS ?= -O3 -funroll-loops
30+
CFLAGS ?= -O3 -march=native
3131
CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign \
3232
-DAFL_PATH=\"$(HELPER_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\" \
3333
-DBIN_PATH=\"$(BIN_PATH)\"

afl-fuzz.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,7 +1096,21 @@ static inline u8 has_new_bits(u8* virgin_map) {
10961096
* return has_new_bits(). */
10971097

10981098
static inline u8 has_new_bits_unclassified(u8* virgin_map) {
1099-
classify_counts(trace_bits); // TODO
1099+
1100+
/* Handle the hot path first: no new coverage */
1101+
u8* end = trace_bits + MAP_SIZE;
1102+
1103+
#ifdef WORD_SIZE_64
1104+
1105+
if (!skim((u64*)virgin_map, (u64*)trace_bits, (u64*)end)) return 0;
1106+
1107+
#else
1108+
1109+
if (!skim((u32*)virgin_map, (u32*)trace_bits, (u32*)end)) return 0;
1110+
1111+
#endif /* ^WORD_SIZE_64 */
1112+
1113+
classify_counts(trace_bits);
11001114
return has_new_bits(virgin_map);
11011115
}
11021116

@@ -3044,7 +3058,19 @@ static u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) {
30443058
/* Keep only if there are new bits in the map, add to queue for
30453059
future fuzzing, etc. */
30463060

3047-
if (!(hnb = has_new_bits_unclassified(virgin_bits))) {
3061+
3062+
/* A combination of classify_counts and has_new_bits. If 0 is returned, then
3063+
* the trace bits are kept as-is. Otherwise, the trace bits are overwritten
3064+
* with classified values.
3065+
*
3066+
* This accelerates the processing: in most cases, no interesting behavior
3067+
* happen, and the trace bits will be discarded soon. This function
3068+
* optimizes for such cases: one-pass scan on trace bits without modifying
3069+
* anything. Only on rare cases it fall backs to the slow path:
3070+
* classify_counts() first, then return has_new_bits(). */
3071+
hnb = has_new_bits_unclassified(virgin_bits);
3072+
3073+
if (!hnb) {
30483074
if (crash_mode) total_crashes++;
30493075
return 0;
30503076
}

coverage-32.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,19 @@ static inline void discover_word(u8* ret, u32* current, u32* virgin) {
8484
*virgin &= ~*current;
8585
}
8686
}
87+
88+
89+
#define PACK_SIZE 16
90+
static inline u32 skim(const u32* virgin, const u32* current, const u32* current_end) {
91+
92+
for (; current != current_end; virgin += 4, current += 4) {
93+
94+
if (current[0] && classify_word(current[0]) & virgin[0]) return 1;
95+
if (current[1] && classify_word(current[1]) & virgin[1]) return 1;
96+
if (current[2] && classify_word(current[2]) & virgin[2]) return 1;
97+
if (current[3] && classify_word(current[3]) & virgin[3]) return 1;
98+
99+
}
100+
101+
return 0;
102+
}

coverage-64.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#include "config.h"
22
#include "types.h"
33

4+
#if (defined(__AVX512F__) && defined(__AVX512DQ__)) || defined(__AVX2__)
5+
# include <immintrin.h>
6+
#endif
47

58
static inline u64 classify_word(u64 word) {
69

@@ -94,3 +97,78 @@ static inline void discover_word(u8* ret, u64* current, u64* virgin) {
9497
}
9598

9699
}
100+
101+
102+
#if defined(__AVX512F__) && defined(__AVX512DQ__)
103+
#define PACK_SIZE 64
104+
static inline u32 skim(const u64* virgin, const u64* current, const u64* current_end) {
105+
106+
for (; current != current_end; virgin += 8, current += 8) {
107+
108+
__m512i value = *(__m512i*)current;
109+
__mmask8 mask = _mm512_testn_epi64_mask(value, value);
110+
111+
/* All bytes are zero. */
112+
if (mask == 0xff) continue;
113+
114+
/* Look for nonzero bytes and check for new bits. */
115+
#define UNROLL(x) \
116+
if (!(mask & (1 << x)) && classify_word(current[x]) & virgin[x]) return 1
117+
UNROLL(0); UNROLL(1); UNROLL(2); UNROLL(3);
118+
UNROLL(4); UNROLL(5); UNROLL(6); UNROLL(7);
119+
#undef UNROLL
120+
121+
}
122+
123+
return 0;
124+
125+
}
126+
#endif
127+
128+
129+
#if !defined(PACK_SIZE) && defined(__AVX2__)
130+
#define PACK_SIZE 32
131+
static inline u32 skim(const u64* virgin, const u64* current, const u64* current_end) {
132+
133+
__m256i zeroes = _mm256_setzero_si256();
134+
135+
for (; current != current_end; virgin += 4, current += 4) {
136+
137+
__m256i value = *(__m256i*)current;
138+
__m256i cmp = _mm256_cmpeq_epi64(value, zeroes);
139+
u32 mask = _mm256_movemask_epi8(cmp);
140+
141+
/* All bytes are zero. */
142+
if (mask == -1) continue;
143+
144+
/* Look for nonzero bytes and check for new bits. */
145+
if (!(mask & 0xff) && classify_word(current[0]) & virgin[0]) return 1;
146+
if (!(mask & 0xff00) && classify_word(current[1]) & virgin[1]) return 1;
147+
if (!(mask & 0xff0000) && classify_word(current[2]) & virgin[2]) return 1;
148+
if (!(mask & 0xff000000) && classify_word(current[3]) & virgin[3]) return 1;
149+
150+
}
151+
152+
return 0;
153+
154+
}
155+
#endif
156+
157+
158+
#if !defined(PACK_SIZE)
159+
#define PACK_SIZE 32
160+
static inline u32 skim(const u64* virgin, const u64* current, const u64* current_end) {
161+
162+
for (; current != current_end; virgin += 4, current += 4) {
163+
164+
if (current[0] && classify_word(current[0]) & virgin[0]) return 1;
165+
if (current[1] && classify_word(current[1]) & virgin[1]) return 1;
166+
if (current[2] && classify_word(current[2]) & virgin[2]) return 1;
167+
if (current[3] && classify_word(current[3]) & virgin[3]) return 1;
168+
169+
}
170+
171+
return 0;
172+
173+
}
174+
#endif

0 commit comments

Comments
 (0)