// Copyright 2021 Code Intelligence GmbH // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.code_intelligence.jazzer.api; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; /** * Static helper functions that allow Jazzer fuzz targets to use Autofuzz. */ final public class Autofuzz { private static final MethodHandle CONSUME; private static final MethodHandle AUTOFUZZ_FUNCTION_1; private static final MethodHandle AUTOFUZZ_FUNCTION_2; private static final MethodHandle AUTOFUZZ_FUNCTION_3; private static final MethodHandle AUTOFUZZ_FUNCTION_4; private static final MethodHandle AUTOFUZZ_FUNCTION_5; private static final MethodHandle AUTOFUZZ_CONSUMER_1; private static final MethodHandle AUTOFUZZ_CONSUMER_2; private static final MethodHandle AUTOFUZZ_CONSUMER_3; private static final MethodHandle AUTOFUZZ_CONSUMER_4; private static final MethodHandle AUTOFUZZ_CONSUMER_5; static { MethodHandle consume = null; MethodHandle autofuzzFunction1 = null; MethodHandle autofuzzFunction2 = null; MethodHandle autofuzzFunction3 = null; MethodHandle autofuzzFunction4 = null; MethodHandle autofuzzFunction5 = null; MethodHandle autofuzzConsumer1 = null; MethodHandle autofuzzConsumer2 = null; MethodHandle autofuzzConsumer3 = null; MethodHandle autofuzzConsumer4 = null; MethodHandle autofuzzConsumer5 = null; try { Class metaClass = Class.forName("com.code_intelligence.jazzer.autofuzz.Meta"); MethodType consumeType = MethodType.methodType(Object.class, FuzzedDataProvider.class, Class.class); consume = MethodHandles.publicLookup().findStatic(metaClass, "consume", consumeType); autofuzzFunction1 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz", MethodType.methodType(Object.class, FuzzedDataProvider.class, Function1.class)); autofuzzFunction2 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz", MethodType.methodType(Object.class, FuzzedDataProvider.class, Function2.class)); autofuzzFunction3 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz", MethodType.methodType(Object.class, FuzzedDataProvider.class, Function3.class)); autofuzzFunction4 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz", MethodType.methodType(Object.class, FuzzedDataProvider.class, Function4.class)); autofuzzFunction5 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz", MethodType.methodType(Object.class, FuzzedDataProvider.class, Function5.class)); autofuzzConsumer1 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz", MethodType.methodType(void.class, FuzzedDataProvider.class, Consumer1.class)); autofuzzConsumer2 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz", MethodType.methodType(void.class, FuzzedDataProvider.class, Consumer2.class)); autofuzzConsumer3 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz", MethodType.methodType(void.class, FuzzedDataProvider.class, Consumer3.class)); autofuzzConsumer4 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz", MethodType.methodType(void.class, FuzzedDataProvider.class, Consumer4.class)); autofuzzConsumer5 = MethodHandles.publicLookup().findStatic(metaClass, "autofuzz", MethodType.methodType(void.class, FuzzedDataProvider.class, Consumer5.class)); } catch (ClassNotFoundException ignore) { // Not running in the context of the agent. This is fine as long as no methods are called on // this class. } catch (NoSuchMethodException | IllegalAccessException e) { // This should never happen as the Jazzer API is loaded from the agent and thus should always // match the version of the runtime classes. // Does not use the Log class as it is unlikely it can be loaded if the Autofuzz classes // couldn't be loaded. System.err.println("ERROR: Incompatible version of the Jazzer API detected, please update."); e.printStackTrace(); System.exit(1); } CONSUME = consume; AUTOFUZZ_FUNCTION_1 = autofuzzFunction1; AUTOFUZZ_FUNCTION_2 = autofuzzFunction2; AUTOFUZZ_FUNCTION_3 = autofuzzFunction3; AUTOFUZZ_FUNCTION_4 = autofuzzFunction4; AUTOFUZZ_FUNCTION_5 = autofuzzFunction5; AUTOFUZZ_CONSUMER_1 = autofuzzConsumer1; AUTOFUZZ_CONSUMER_2 = autofuzzConsumer2; AUTOFUZZ_CONSUMER_3 = autofuzzConsumer3; AUTOFUZZ_CONSUMER_4 = autofuzzConsumer4; AUTOFUZZ_CONSUMER_5 = autofuzzConsumer5; } private Autofuzz() {} /** * Attempts to invoke {@code func} with arguments created automatically from the fuzzer input * using only public methods available on the classpath. *

* Note: This function is inherently heuristic and may fail to execute {@code func} in * meaningful ways for a number of reasons. * * @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}. * @param func a method reference for the function to autofuzz. If there are multiple overloads, * resolve ambiguities by explicitly casting to {@link Function1} with (partially) specified * type variables, e.g. {@code (Function1) String::new}. * @return the return value of {@code func}, or {@code null} if {@code autofuzz} failed to invoke * the function. * @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link * AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call. * The {@link Throwable} is thrown unchecked. */ @SuppressWarnings("unchecked") public static R autofuzz(FuzzedDataProvider data, Function1 func) { try { return (R) AUTOFUZZ_FUNCTION_1.invoke(data, func); } catch (AutofuzzInvocationException e) { rethrowUnchecked(e.getCause()); } catch (Throwable t) { rethrowUnchecked(t); } // Not reached. return null; } /** * Attempts to invoke {@code func} with arguments created automatically from the fuzzer input * using only public methods available on the classpath. *

* Note: This function is inherently heuristic and may fail to execute {@code func} in * meaningful ways for a number of reasons. * * @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}. * @param func a method reference for the function to autofuzz. If there are multiple overloads, * resolve ambiguities by explicitly casting to {@link Function2} with (partially) specified * type variables. * @return the return value of {@code func}, or {@code null} if {@code autofuzz} failed to invoke * the function. * @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link * AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call. * The {@link Throwable} is thrown unchecked. */ @SuppressWarnings("unchecked") public static R autofuzz(FuzzedDataProvider data, Function2 func) { try { return (R) AUTOFUZZ_FUNCTION_2.invoke(data, func); } catch (AutofuzzInvocationException e) { rethrowUnchecked(e.getCause()); } catch (Throwable t) { rethrowUnchecked(t); } // Not reached. return null; } /** * Attempts to invoke {@code func} with arguments created automatically from the fuzzer input * using only public methods available on the classpath. *

* Note: This function is inherently heuristic and may fail to execute {@code func} in * meaningful ways for a number of reasons. * * @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}. * @param func a method reference for the function to autofuzz. If there are multiple overloads, * resolve ambiguities by explicitly casting to {@link Function3} with (partially) specified * type variables. * @return the return value of {@code func}, or {@code null} if {@code autofuzz} failed to invoke * the function. * @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link * AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call. * The {@link Throwable} is thrown unchecked. */ @SuppressWarnings("unchecked") public static R autofuzz(FuzzedDataProvider data, Function3 func) { try { return (R) AUTOFUZZ_FUNCTION_3.invoke(data, func); } catch (AutofuzzInvocationException e) { rethrowUnchecked(e.getCause()); } catch (Throwable t) { rethrowUnchecked(t); } // Not reached. return null; } /** * Attempts to invoke {@code func} with arguments created automatically from the fuzzer input * using only public methods available on the classpath. *

* Note: This function is inherently heuristic and may fail to execute {@code func} in * meaningful ways for a number of reasons. * * @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}. * @param func a method reference for the function to autofuzz. If there are multiple overloads, * resolve ambiguities by explicitly casting to {@link Function4} with (partially) specified * type variables. * @return the return value of {@code func}, or {@code null} if {@code autofuzz} failed to invoke * the function. * @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link * AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call. * The {@link Throwable} is thrown unchecked. */ @SuppressWarnings("unchecked") public static R autofuzz( FuzzedDataProvider data, Function4 func) { try { return (R) AUTOFUZZ_FUNCTION_4.invoke(data, func); } catch (AutofuzzInvocationException e) { rethrowUnchecked(e.getCause()); } catch (Throwable t) { rethrowUnchecked(t); } // Not reached. return null; } /** * Attempts to invoke {@code func} with arguments created automatically from the fuzzer input * using only public methods available on the classpath. *

* Note: This function is inherently heuristic and may fail to execute {@code func} in * meaningful ways for a number of reasons. * * @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}. * @param func a method reference for the function to autofuzz. If there are multiple overloads, * resolve ambiguities by explicitly casting to {@link Function5} with (partially) specified * type variables. * @return the return value of {@code func}, or {@code null} if {@code autofuzz} failed to invoke * the function. * @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link * AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call. * The {@link Throwable} is thrown unchecked. */ @SuppressWarnings("unchecked") public static R autofuzz( FuzzedDataProvider data, Function5 func) { try { return (R) AUTOFUZZ_FUNCTION_5.invoke(data, func); } catch (AutofuzzInvocationException e) { rethrowUnchecked(e.getCause()); } catch (Throwable t) { rethrowUnchecked(t); } // Not reached. return null; } /** * Attempts to invoke {@code func} with arguments created automatically from the fuzzer input * using only public methods available on the classpath. *

* Note: This function is inherently heuristic and may fail to execute {@code func} in * meaningful ways for a number of reasons. * * @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}. * @param func a method reference for the function to autofuzz. If there are multiple overloads, * resolve ambiguities by explicitly casting to {@link Consumer1} with explicitly specified * type variable. * @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link * AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call. * The {@link Throwable} is thrown unchecked. */ public static void autofuzz(FuzzedDataProvider data, Consumer1 func) { try { AUTOFUZZ_CONSUMER_1.invoke(data, func); } catch (AutofuzzInvocationException e) { rethrowUnchecked(e.getCause()); } catch (Throwable t) { rethrowUnchecked(t); } } /** * Attempts to invoke {@code func} with arguments created automatically from the fuzzer input * using only public methods available on the classpath. *

* Note: This function is inherently heuristic and may fail to execute {@code func} in * meaningful ways for a number of reasons. * * @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}. * @param func a method reference for the function to autofuzz. If there are multiple overloads, * resolve ambiguities by explicitly casting to {@link Consumer2} with (partially) specified * type variables. * @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link * AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call. * The {@link Throwable} is thrown unchecked. */ public static void autofuzz(FuzzedDataProvider data, Consumer2 func) { try { AUTOFUZZ_CONSUMER_2.invoke(data, func); } catch (AutofuzzInvocationException e) { rethrowUnchecked(e.getCause()); } catch (Throwable t) { rethrowUnchecked(t); } } /** * Attempts to invoke {@code func} with arguments created automatically from the fuzzer input * using only public methods available on the classpath. *

* Note: This function is inherently heuristic and may fail to execute {@code func} in * meaningful ways for a number of reasons. * * @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}. * @param func a method reference for the function to autofuzz. If there are multiple overloads, * resolve ambiguities by explicitly casting to {@link Consumer3} with (partially) specified * type variables. * @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link * AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call. * The {@link Throwable} is thrown unchecked. */ public static void autofuzz(FuzzedDataProvider data, Consumer3 func) { try { AUTOFUZZ_CONSUMER_3.invoke(data, func); } catch (AutofuzzInvocationException e) { rethrowUnchecked(e.getCause()); } catch (Throwable t) { rethrowUnchecked(t); } } /** * Attempts to invoke {@code func} with arguments created automatically from the fuzzer input * using only public methods available on the classpath. *

* Note: This function is inherently heuristic and may fail to execute {@code func} in * meaningful ways for a number of reasons. * * @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}. * @param func a method reference for the function to autofuzz. If there are multiple overloads, * resolve ambiguities by explicitly casting to {@link Consumer4} with (partially) specified * type variables. * @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link * AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call. * The {@link Throwable} is thrown unchecked. */ public static void autofuzz( FuzzedDataProvider data, Consumer4 func) { try { AUTOFUZZ_CONSUMER_4.invoke(data, func); } catch (AutofuzzInvocationException e) { rethrowUnchecked(e.getCause()); } catch (Throwable t) { rethrowUnchecked(t); } } /** * Attempts to invoke {@code func} with arguments created automatically from the fuzzer input * using only public methods available on the classpath. *

* Note: This function is inherently heuristic and may fail to execute {@code func} in * meaningful ways for a number of reasons. * * @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}. * @param func a method reference for the function to autofuzz. If there are multiple overloads, * resolve ambiguities by explicitly casting to {@link Consumer5} with (partially) specified * type variables. * @throws Throwable any {@link Throwable} thrown by {@code func}, or an {@link * AutofuzzConstructionException} if autofuzz failed to construct the arguments for the call. * The {@link Throwable} is thrown unchecked. */ public static void autofuzz( FuzzedDataProvider data, Consumer5 func) { try { AUTOFUZZ_CONSUMER_5.invoke(data, func); } catch (AutofuzzInvocationException e) { rethrowUnchecked(e.getCause()); } catch (Throwable t) { rethrowUnchecked(t); } } /** * Attempts to construct an instance of {@code type} from the fuzzer input using only public * methods available on the classpath. *

* Note: This function is inherently heuristic and may fail to return meaningful values for * a variety of reasons. * * @param data the {@link FuzzedDataProvider} instance provided to {@code fuzzerTestOneInput}. * @param type the {@link Class} to construct an instance of. * @return an instance of {@code type} constructed from the fuzzer input, or {@code null} if * autofuzz failed to create an instance. */ @SuppressWarnings("unchecked") public static T consume(FuzzedDataProvider data, Class type) { try { return (T) CONSUME.invokeExact(data, type); } catch (AutofuzzConstructionException ignored) { return null; } catch (Throwable t) { rethrowUnchecked(t); // Not reached. return null; } } // Rethrows a (possibly checked) exception while avoiding a throws declaration. @SuppressWarnings("unchecked") private static void rethrowUnchecked(Throwable t) throws T { throw(T) t; } }