{"id":25776242,"url":"https://github.com/cmu-pasta/mu2","last_synced_at":"2026-01-18T08:22:59.303Z","repository":{"id":36965171,"uuid":"395405720","full_name":"cmu-pasta/mu2","owner":"cmu-pasta","description":"Mutation-guided mutation-based fuzz testing","archived":false,"fork":false,"pushed_at":"2024-07-13T15:26:34.000Z","size":397,"stargazers_count":41,"open_issues_count":1,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-07-13T16:44:16.762Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cmu-pasta.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-12T18:08:09.000Z","updated_at":"2024-07-13T15:26:38.000Z","dependencies_parsed_at":"2024-07-13T16:42:37.997Z","dependency_job_id":"e871f375-da65-4a23-aab1-0fe06d1731fe","html_url":"https://github.com/cmu-pasta/mu2","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmu-pasta%2Fmu2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmu-pasta%2Fmu2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmu-pasta%2Fmu2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmu-pasta%2Fmu2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cmu-pasta","download_url":"https://codeload.github.com/cmu-pasta/mu2/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240987435,"owners_count":19889333,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-27T06:01:19.898Z","updated_at":"2026-01-17T07:45:08.122Z","avatar_url":"https://github.com/cmu-pasta.png","language":"Java","funding_links":[],"categories":["测试"],"sub_categories":[],"readme":"# Mutation-Guided Fuzzing\n\nMu2 is a fuzz testing platform for mutation-guided fuzzing, built on top of the [JQF](https://github.com/rohanpadhye/JQF/) platform for fuzzing Java programs. Documentation for running and understanding the implementation of mutation-guided fuzzing provided here.\n\n\u003c!-- For project writeup, see [this document](https://saphirasnow.github.io/17-355/Bella_Laybourn_17355_Project.pdf). --\u003e\n\nFor more questions, feel free to email [Bella Laybourn](mailto:ilaybour@andrew.cmu.edu), [Vasu Vikram](mailto:vasumv@cmu.edu), or [Rohan Padhye](https://rohan.padhye.org).\n\n## Research Paper - ISSTA 2023\n\nMu2 is described in the following research paper:\n\n\u003e Vasudev Vikram, Isabella Laybourn, Ao Li, Nicole Nair, Kelton OBrien, Rafaello Sanna, and Rohan Padhye. 2023. **Guiding Greybox Fuzzing with Mutation Testing**. In Proceedings of the 32nd ACM SIGSOFT International Symposium on Software Testing and Analysis (ISSTA 2023). Association for Computing Machinery, New York, NY, USA, 929–941. https://doi.org/10.1145/3597926.3598107\n\n## Build + Test + Install\n\nTo install Mu2, run the following:\n\n```\ngit clone https://github.com/cmu-pasta/mu2 \u0026\u0026 cd mu2\nmvn install\n```\n\n### Development\n\nMu2 is a multimodule project containing the following modules:\n\n1. `core`: all the core instrumentation and guidance logic\n2. `examples`: example fuzz drivers for applying mutation-guided fuzzing\n3. `integration-tests`: integration tests for mutation-guided fuzzing on sorting targets in `examples`\n\nWhen making changes to mu2 or JQF, you only need to install that particular project's SNAPSHOT for the changes to take effect.\n\nTo test changes to `mu2`, run the integration tests as follows from the `mu2` repository:\n```\nmvn verify\n```\n\nCoverage reports should be available in `integration-tests/target/site/jacoco-integration-test-coverage-report/index.html`.\n\n## Differential Mutation Testing Fuzzing\n\nTo use the differential fuzzing goal `mu2:diff`, instrument your tests with `@Diff` and `@Comparison` annotations instead of `@Test` and use the `DiffGoal` and `MutateDiffGoal` as described below.\n\n### Annotations\n\nIn the differential testing framework, each test is a pair of functions, one annotated with `@Diff` and the other with `@Comparison`.\n\nThe function annotated with `@Diff` should **not** be `static` and should return an object (neither void nor a primitive, though boxed primitives work).\nThe result of this diff function will be compared with other results using the comparison function (annotated with `@Comparison`). \n\nThe comparison function should be `static`, take two arguments of the same type as the return type of any associated diff functions, and return a `Boolean` \n(`Boolean.TRUE` if the two inputs are equivalent, `Boolean.FALSE` otherwise).\n\nMultiple functions with these annotations can be included in a single test class, so, to uniquely match the diff function with a comparison function, \npass the name of the comparison function as an argument to `@Diff` as `cmp` (see below for example). If no argument is passed to `cmp`, `Objects.equals()` \nwill be used as a default.\n\nEach diff function is associated with up to one comparison function, but arbitrarily many diff functions may use a comparison function.\n\nExample of a differential test for a function `populateList(List\u003cInteger\u003e)` when the comparison only cares about the size of the populated list:\n\n```java\n@Diff(cmp = \"compare\")\npublic List\u003cInteger\u003e testPopulate(List\u003cInteger\u003e input) {\n    return populateList(input);\n}\n\n@Comparison\npublic static Boolean compare(List\u003cInteger\u003e list1, List\u003cInteger\u003e list2) {\n    return list1.size() == list2.size();\n}\n```\n\n### Diff Goal\n\nFor running differential fuzzing. Currently defaults to mutation-guided fuzzing.\n\nExample: \n\n```sh\nmvn mu2:diff -Dclass=package.class -Dmethod=method -Dincludes=prefix\n```\n\n### Mutate Goal\n\nFor repro on mutation guidance with diff-based tests.\n\nExample: \n\n```sh\nmvn mu2:mutate -Dclass=package.class -Dmethod=method -Dincludes=prefix -Dinput=path/to/corpus\n```\n\n### Repro Goal\n\nFor repro on other guidances with diff-based tests.\n\nExample: \n\n```sh\nmvn mu2:repro -Dclass=package.class -Dmethod=method -Dincludes=prefix -Dinput=path/to/corpus\n```\n\n### Selecting Instrumentable Classes\n\nYou can use the `-Dincludes` flags to select which code will be mutated. \n\n```sh\nmvn mu2:diff -Dclass=package.class -Dmethod=method -Dincludes=prefix1,prefix2\n```\n\nAdditionally, setting the `-DtargetIncludes` flag to a comma-separated list that includes every mutated class \nas well as all classes that depend on a mutable class anywhere in their dependency trees improves efficiency by \nloading classes not in the list with a separate intermediate ClassLoader.\n\nExample using a test of Scala's chess library:\n```sh\nmvn mu2:diff -Dclass=edu.berkeley.cs.jqf.examples.chess.FENTest -Dmethod=testWithGenerator -Dincludes=chess.format.Forsyth,chess.Situation -DtargetIncludes=edu.berkeley.cs.jqf.examples.chess,chess\n```\n\n## Implementation\n\n### MutationInstance\n\nA `MutationInstance` is an instance of a mutation: e.g. the class in which the mutation resides, the kind of mutation performed (the `Mutator` - see below), and the location in which the mutation takes places (given as the n'th opportunity for the `Mutator` to be applied to the given class). Each instance also has an ID, which can be used as its index in the `MutationInstance.mutationInstances` array.\n\n### ClassLoaders\n\n#### MutationClassLoader\n\nA `ClassLoader` which loads a mutated version of a class specified by a `MutationInstance`. For all classes except that specified by the `MutationInstance`, it loads it normally. For the class specified, it mutates the class as specified by the `Mutator` and the mutator index.\n\nThis class can be used on its own, or can be used through a `MutationClassLoaders` object, which takes the class-loading information as a parameter then provides a map from `MutationInstances` to `MutationClassLoader`s.\n\n#### CartographyClassLoader\n\nInitial class loading should take place using this ClassLoader. It creates a list of MutationInstances representing all of the mutation opportunities (the \"cartograph\"). It does this by instrumenting the input class using the `Cartographer`: a `SafeClassWriter` which both logs which mutants are possible, and transforms the input class into one which measures which mutants are run for later optimization.\n\n#### MutationClassLoaders\n\nA class that contains references to both the `CartographyClassLoader` and a mapping of each `MutationInstance` to its `MutationClassLoader`. A `MutationClassLoaders` object is the external entry point, and such an object is passed to a `MutationGuidance` during construction.\n\n### Mutators\n\n#### Mutator Format\n\nEach mutator replaces one instruction with another, or with a series of instructions. \nThey sometimes take the form `prefix_oldInstruction_TO_newInstruction(Opcodes.oldInstruction, returnType, [list, of, instruction, calls, ...])` and other times, as appropriate to the type of mutator, are just descriptors.\n\nTo make that more clear, three actual examples, broken down:\n\n`I_ADD_TO_SUB(Opcodes.IADD, null, new InstructionCall(Opcodes.ISUB))`\nrefers to swapping \u003cb\u003eI\u003c/b\u003enteger \u003cb\u003eADD\u003c/b\u003eition for \u003cb\u003eSUB\u003c/b\u003etraction, which requires no relevant return type.\n\n`VOID_REMOVE_STATIC(Opcodes.INVOKESTATIC, \"V\", new InstructionCall(Opcodes.NOP))`\nrefers to removing calls to void functions made with `invokestatic`, which requires that the return type of the called function be \u003cb\u003eV\u003c/b\u003eoid.\n\n`S_IRETURN_TO_0(Opcodes.IRETURN, \"S\", new InstructionCall(Opcodes.POP), new InstructionCall(Opcodes.ICONST_0), new InstructionCall(Opcodes.IRETURN))`\nrefers to making a function with return type \u003cb\u003eS\u003c/b\u003ehort return the short `0` instead of what it would normally have returned. This requires that the return type of the returning function be \u003cb\u003eS\u003c/b\u003ehort.\n\nNote how in the second two examples, the opcode alone was not enough to identify the relevant return type, which is why that information was included separately.\n\n##### Pops: An Aside\n\nWhen calling functions, the arguments are loaded onto the stack. This means that, when removing a function call, those arguments must be popped off the stack before continuing. \nTypically, we would pop off the same number of arguments as the function has, but when the opcode is `invokestatic` there's one fewer because there's an implicit `this` argument added in other cases that `invokestatic` doesn't need.\n\n#### InstructionCall\n\nJust a wrapper for bytecode instructions so their arguments can be included.\n\n### MutationSnoop\n\nA class whose static methods are invoked from mu2-instrumented classes. Used to track infinite loops in mutated code and to perform speculative mutation analysis in the original (cartography) test run.\n\n### MutationGuidance\n\nFor the most part, an extension of `Zest`.\nFor each fuzz input, runs first the class loaded by the `CartographyClassLoader`, then each of the `MutationInstance`s it has generated that hasn't been killed by a previous fuzz input and have been marked as run by the class loaded by the `CartographyClassLoader`.\nSaves for reason `+mutants` along with Zest's `+coverage`, etc.\n\n### Timeout\n\nTo prevent hanging forever on an infinite loop, both MutationInstances and CartographyClassLoaders outfit their classes with a timeout functionality that essentially kills the program after some maximum number of control jumps.\nThis assumes that if the number of control jumps exceeds that then the program has encountered an infinite loop and will not ascertain any new information by continuing to run.\n\n## Scripts\n\n### Setup\n\n```\npip install -r requirements.txt\n```\n\n### Plot Mutants\n\nThis is a script for visualizing the various mutant numbers across trials of a given fuzzing session run with `-Dengine=mutation`. It takes in an input `plot_data` CSV file and \noutputs an image plotting found mutants, killed mutants, and optionally seen/infected mutants.\nUsage:\n```\npython scripts/plot_mutant_data.py \u003cplot_data_file\u003e \u003coutput_image_file\u003e \n```\n\n### Experiments and Venn Diagram\nUsage:\n```\n./getMutants.sh \u003ctestClass\u003e \u003ctestMethod\u003e \u003cincludesClass\u003e \u003cexperiments\u003e \u003ctrials\u003e \u003cbaseDirectory\u003e\n\n./getMutants.sh edu.berkeley.cs.jqf.examples.commons.PatriciaTrieTest testPrefixMap org.apache.commons.collections4.trie 3 1000 ../../jqf/examples\n```\nVenn diagram script alone:\n```\npython scripts/venn.py --filters_dir \u003cfilters_dir\u003e --num_experiments \u003cnum_experiments\u003e --output_img \u003coutput_img_name\u003e\n```\n\n## Acknowledgments\n\nThis project is supported in part by the National Science Foundation under Grant Number [CCF-2120955](https://www.nsf.gov/awardsearch/showAward?AWD_ID=2120955). Any opinions, findings, and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the National Science Foundation. \n\nThis project is also partly supported by [CyLab](https://www.cylab.cmu.edu/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmu-pasta%2Fmu2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcmu-pasta%2Fmu2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmu-pasta%2Fmu2/lists"}