*4.1. Experimental Settings*

 **5:** Power schedule

**Baseline Fuzzer**. We compare MooFuzz with existing state-of-the-art tools AFL [7], AFLFast [11], FairFuzz [13], and PerfFuzz [16]. The selection of baseline fuzzer is mainly based on the following considerations:


**Benchmark**. To evaluate MooFuzz, we choose seven real-world open source Linux applications as the benchmark to conduct experiments. Jasper [64] is a software tool kit for processing image data that provides a way to represent images and facilitates the manipulation of image data. LibSass [65] is a C/C++ port of the Sass engine. Exiv2 [66] is a C++ library and a command line utility to read, write, delete, and modify Exif, IPTC, XMP, and ICC image metadata. Libming [67] is a library for generating Macromedia Flash files, written in C, and includes useful utilities for working with Flash files. OpenJPEG [68] is an open source JPEG 2000 codec written in C language. Bento4 [69] is a C++ class library that

is designed to read and write ISO-MP4 files. The GUN Binutils [70] is a collection of binary tools. Table 2 shows target applications and their fuzzing configure.


**Table 2.** Target applications and their fuzzing configure.

**Performance Metrics**. Crashes, paths, and vulnerabilities are chosen as metrics in this section. In code coverage metrics, we use the number of seeds in the queue as an indicator and use tool Afl-cov [71] to measure code line coverage and function coverage.In vulnerability detection, we directly use AddressSanitizer [72] to detect it.

**Experiment Environment**. All experiments are conducted on a server configured with two Xeon E5-2680 v4 processors (56 logical cores in total) and 32 GB RAM. The server installed Ubuntu 18.04 system. For the same application, the initial seed set is the same. We fuzz each application for 24 h (on a single logical core) and repeat 5 times to reduce randomness. In all implementations, we use 42 logical cores, and we leave 14 logical cores for other processes to keep the workload stable.

#### *4.2. Unique Crashes Evaluation (RQ1)*

In order to evaluate the effectiveness of MooFuzz, a direct method is to evaluate the number of crashes and the speed at which they are triggered. It is believed that more crashes may trigger more bugs. We fuzz each application to run on 5 different fuzzers to compare the number of unique crashes and the speed of discovery. Figure 3 shows the growth trends of unique crashes discovery in different fuzzers. From these results, we can make the follow observations.

**Figure 3.** The growth trends of unique crashes discovery in different fuzzers within 24 h.

First, different fuzzers have different capability in fuzzing different application programs. For example, PerfFuzz has zero crash in fuzzing openjpeg within 24 h, but it can

trigger most crashes in fuzzing exiv2 among other fuzzers. This shows that the different criteria of the seed selection affect the number of crashes.

Second, seed schedule and power schedule affect the efficiency of crashes discovery. The experimental results show that MooFuzz outperforms AFL in the speed of crashes discovery and just takes about 10 h to trigger most of the unique crashes. There is no path risk measurement and energy monitoring in AFL, leading to a lot of time spent on invalid mutation operators.

Third, MooFuzz is able to find more crashes than other state-of-the-art fuzzers. The static results are shown in Table 3. We count the number of crashes found in applications by different fuzzers within 24 h, and count the total number of crashes found by each fuzzer. Table 3 shows that except for exiv2, MooFuzz triggers more crashes than other fuzzers, among which jasper triggers 182 crashes within 24 h and AFL only triggers 118 crashes. In total, MooFuzz triggers 818 crashes in benchmark application programs, improving by 46%, 32%, 34%, and 153%, respectively, compared with state-of-the-art fuzzers AFL [7], AFLFast [11], FairFuzz [13], and PerfFuzz [16].


**Table 3.** Number of unique crashes found in real-world programs by various fuzzers.

Overall, MooFuzz significantly outperforms other fuzzers in terms of speed and number of unique crashes.

#### *4.3. Coverage Evaluation (RQ2)*

Code coverage is an effective way to evaluate fuzzers. The experiment measures coverage from source code line, function, and path. Table 4 shows the line and function covered by different fuzzers. In total, MooFuzz's line coverage and function coverage are better than AFL, AFLFast, FairFuzz, and PerfFuzz.


**Table 4.** Line and function covered by fuzzers.

Figure 4 shows the growth trends of paths discovery in five different fuzzers after fuzzing applications for 24 h. We can clearly observe that except for cxxfilt, MooFuzz ranks first among all fuzzers from the perspective of the number of path discovery. Among them, it can find about 6000 paths in fuzzing openjpeg, and the other four fuzzers can only find about 3600 paths. It can find about 1200 paths after fuzzing jasper for 24 h, while other fuzzers can only find about 500 to 700 paths. Although the number of paths discovered

by MooFuzz is lower than FairFuzz and AFLFast in fuzzing cxxfilt, it can trigger the most crashes compared with other fuzzers. From the speed of path discovery, MooFuzz is significantly higher than other fuzzers.

**Figure 4.** The growth trends of paths discovery in different fuzzers within 24 h.

Overall, MooFuzz outperforms other fuzzers in terms of line, function, and path coverage.

#### *4.4. Vulnerability Evaluation (RQ3)*

MooFuzz tests old version of the applications and analyzes related vulnerabilities to evaluate the ability in vulnerability detection. Table 5 shows the real vulnerabilities combination with its IDs identified by MooFuzz. MooFuzz is able to find stack overflow, heap overflow, null pointer dereference, and memory leaks related vulnerabilities.

**Table 5.** Real-world vulnerabilities found by MooFuzz.


**Vulnerability analysis.** We use a real-world application program vulnerability to analyze the effectiveness of our approach, as shown in Figure 5. This is a code snippet from openjpeg [68] which contains a heap-buffer-overflow vulnerability (i.e., CVE-2020-8112).

In Figure 5, the main function contains a conditional statement (Lines 1–9). In Moo-Fuzz, the seed *st* satisfies the judgment condition and enters the true branch to execute function *opj*\_*tcd*\_*decode*\_*tile*(...). Moreover, the seed *sn* enters the false branch to execute other codes that do not contain dangerous functions. As*malloc* is a dangerous function which is used in *opj*\_*tcd*\_*decode*\_*tile*(...), risks might emerge when this function is used. Therefore, MooFuzz preferentially selects seed *st* for mutation. In this case, *malloc*(*l*\_*data*\_*size*) is called and *l*\_*data*\_*size* comes from an unsigned operation in the function *opj*\_*tcd*\_*decode*\_*tile*. Then, the function *opj*\_*t*1\_*clbl*\_*decode*\_*processor* will be called in the following program flow, where the allocated memory will be modify through two variables *cblk* \_ *h* and *cblk* \_ *w*. All of these two variables are obtained through signed operation, which causes an integer overflow making *cblk*\_*h* ∗ *cblk*\_*w* > *l*\_*data*\_*size*, and MooFuzz easily satisfies the above conditions through mutation, so the heap-buffer-overflow happened.

```
1 int main(int argc , char **argv){
2 ...
3 if (!parameters.nb_tile_to_decode){
4 opj_tcd_decode_tile(...)
5 }
 6 else {
 7 ...
 8 }
 9 }
10
11 OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd , ...){
12 /* unsigned operations */
13 OPJ_SIZE_T res_w = (OPJ_SIZE_T)(l_res ->x1 - l_res ->x0);
14 OPJ_SIZE_T res_h = (OPJ_SIZE_T)(l_res ->y1 - l_res ->y0);
15
16 l_data_size = res_w * res_h;
17 /* tile ->data allocate l_data_size space */
18 tilec ->data = malloc(l_data_size);
19 ...
20 opj_t1_clbl_decode_processor(...);
21 }
22
23 static void opj_t1_clbl_decode_processor(...){
24 /* cblk_h and cblk_w are obtained through signed operation
25 * which cause integer overflow
26 * cblk_h * cblk_w > l_data_size , heap overflow happened. */
27 datap = tilec ->data;
28 for (j = 0; j < cblk_h; ++j){
29 i = 0;
30 for (; i < (cblk_w & ~(OPJ_UINT32)3U); i += 4U){
31 OPJ_INT32 tmp0 = datap[(j * cblk_w) + i + 0U];
32 ...
33 }
34 }
35 }
```
**Figure 5.** An example from openjpeg (CVE-2020-8112).
