// We always define LLVMFuzzerCustomMutator, but only use it when --experimental_mutator is // specified. libFuzzer contains logic that disables --len_control when it finds the custom // mutator symbol: // https://github.com/llvm/llvm-project/blob/da3623de2411dd931913eb510e94fe846c929c24/compiler-rt/lib/fuzzer/FuzzerDriver.cpp#L202-L207 // We thus have to explicitly set --len_control to its default value when not using the new // mutator.
/** * Starts libFuzzer via LLVMFuzzerRunDriver. * * @param args command-line arguments encoded in UTF-8 (not null-terminated) * @return the return value of LLVMFuzzerRunDriver */ privatestaticintstartLibFuzzer(byte[][] args){ return FuzzTargetRunnerNatives.startLibFuzzer( args, FuzzTargetRunner.class, useExperimentalMutator); }
/* * Starts libFuzzer via LLVMFuzzerRunDriver. */ publicstaticintstartLibFuzzer(List<String> args){ // We always define LLVMFuzzerCustomMutator, but only use it when --experimental_mutator is // specified. libFuzzer contains logic that disables --len_control when it finds the custom // mutator symbol: // https://github.com/llvm/llvm-project/blob/da3623de2411dd931913eb510e94fe846c929c24/compiler-rt/lib/fuzzer/FuzzerDriver.cpp#L202-L207 // We thus have to explicitly set --len_control to its default value when not using the new // mutator. if (!useExperimentalMutator) { // args may not be mutable. args = new ArrayList<>(args); // https://github.com/llvm/llvm-project/blob/da3623de2411dd931913eb510e94fe846c929c24/compiler-rt/lib/fuzzer/FuzzerFlags.def#L19 args.add("-len_control=100"); }
for (String arg : args.subList(1, args.size())) { if (!arg.startsWith("-")) { Log.info("using inputs from: " + arg); } }
privatestaticintrunOne(long dataPtr, int dataLength){ // ignore some code byte[] data; Object argument; if (useExperimentalMutator) { byte[] buf = copyToArray(dataPtr, dataLength); boolean readExactly = mutator.read(new ByteArrayInputStream(buf));
// All inputs constructed by the mutator framework can be read exactly, existing corpus files // may not be valid for the current fuzz target anymore, though. In this case, print a warning // once. if (!(invalidCorpusFileWarningShown || readExactly || isFixedLibFuzzerInput(buf))) { invalidCorpusFileWarningShown = true; Log.warn("Some files in the seed corpus do not match the fuzz target signature. " + "This indicates that they were generated with a different signature and may cause issues reproducing previous findings."); } data = null; argument = null; } elseif (useFuzzedDataProvider) { fuzzedDataProvider.setNativeData(dataPtr, dataLength); data = null; argument = fuzzedDataProvider; } else { data = copyToArray(dataPtr, dataLength); argument = data; } try { if (useExperimentalMutator) { // No need to detach as we are currently reading in the mutator state from bytes in every // iteration. mutator.invoke(false); } elseif (fuzzTargetInstance == null) { fuzzTargetMethod.invoke(argument); } else { fuzzTargetMethod.invoke(fuzzTargetInstance, argument); } } catch (Throwable uncaughtFinding) { finding = uncaughtFinding; } // ignore some code }
@SuppressWarnings("unused") privatestaticintmutateOne(long data, int size, int maxSize, int seed){ mutate(data, size, seed); return writeToMemory(mutator, data, maxSize); }
privatestaticvoidmutate(long data, int size, int seed){ // libFuzzer sends the input "\n" when there are no corpus entries. We use that as a signal to // initialize the mutator instead of just reading that trivial input to produce a more // interesting value. if (size == 1 && UNSAFE.getByte(data) == '\n') { // 这里的 mutator 就是上面的 ArgumentsMutator.forStaticMethodOrThrow / forInstanceMethodOrThrow mutator.init(seed); } else { mutator.read(new ByteArrayInputStream(copyToArray(data, size))); mutator.mutate(seed); } }