ReflectUtilsFuzzer.java

// Copyright 2023 Google LLC
//
// 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.
//
////////////////////////////////////////////////////////////////////////////////
import com.code_intelligence.jazzer.api.FuzzedDataProvider;
import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.reflect.InheritanceUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.apache.commons.lang3.reflect.TypeUtils;

/** This fuzzer targets the methods of the Utils classes in the reflect package */
public class ReflectUtilsFuzzer extends ClassFuzzerBase {
  public static void fuzzerTestOneInput(FuzzedDataProvider data) {
    try {
      // Randomly pick 2 class objects
      Class cls1 = data.pickValue(classSet);
      Class cls2 = data.pickValue(classSet);

      switch (data.consumeInt(1, 28)) {
        case 1:
          ConstructorUtils.getAccessibleConstructor(cls1, cls2);
          break;
        case 2:
          ConstructorUtils.getAccessibleConstructor(data.pickValue(cls1.getConstructors()));
          ConstructorUtils.getAccessibleConstructor(data.pickValue(cls2.getConstructors()));
          break;
        case 3:
          ConstructorUtils.getMatchingAccessibleConstructor(cls1, cls2);
          break;
        case 4:
          ConstructorUtils.invokeConstructor(cls1, cls2);
          break;
        case 5:
          ConstructorUtils.invokeExactConstructor(cls1, cls2);
          break;
        case 6:
          FieldUtils.getAllFields(cls1);
          FieldUtils.getAllFields(cls2);
          break;
        case 7:
          FieldUtils.getDeclaredField(cls1, data.consumeRemainingAsString());
          break;
        case 8:
          FieldUtils.getField(cls1, data.consumeRemainingAsString());
          break;
        case 9:
          FieldUtils.readDeclaredStaticField(cls1, data.consumeRemainingAsString());
          break;
        case 10:
          FieldUtils.readDeclaredStaticField(cls1, data.consumeRemainingAsString());
          break;
        case 11:
          FieldUtils.readField(cls1, data.consumeRemainingAsString());
          break;
        case 12:
          FieldUtils.readStaticField(cls1, data.consumeRemainingAsString());
          break;
        case 13:
          InheritanceUtils.distance(cls1, cls2);
          break;
        case 14:
          MethodUtils.getAccessibleMethod(data.pickValue(cls1.getMethods()));
          MethodUtils.getAccessibleMethod(data.pickValue(cls2.getMethods()));
          break;
        case 15:
          MethodUtils.getAccessibleMethod(cls1, data.consumeRemainingAsString(), cls2);
          break;
        case 16:
          MethodUtils.getMatchingAccessibleMethod(cls1, data.consumeRemainingAsString(), cls2);
          break;
        case 17:
          MethodUtils.getMatchingMethod(cls1, data.consumeRemainingAsString(), cls2);
          break;
        case 18:
          MethodUtils.invokeExactStaticMethod(cls1, data.consumeRemainingAsString(), cls2);
          break;
        case 19:
          MethodUtils.invokeStaticMethod(cls1, data.consumeRemainingAsString(), cls2);
          break;
        case 20:
          TypeUtils.containsTypeVariables(data.pickValue(cls1.getTypeParameters()));
          TypeUtils.containsTypeVariables(data.pickValue(cls2.getTypeParameters()));
          break;
        case 21:
          TypeUtils.equals(
              data.pickValue(cls1.getTypeParameters()), data.pickValue(cls2.getTypeParameters()));
          break;
        case 22:
          TypeUtils.genericArrayType(data.pickValue(cls1.getTypeParameters()));
          TypeUtils.genericArrayType(data.pickValue(cls2.getTypeParameters()));
          break;
        case 23:
          TypeUtils.getArrayComponentType(data.pickValue(cls1.getTypeParameters()));
          TypeUtils.getArrayComponentType(data.pickValue(cls2.getTypeParameters()));
          break;
        case 24:
          TypeUtils.getTypeArguments(data.pickValue(cls1.getTypeParameters()), cls1);
          TypeUtils.getTypeArguments(data.pickValue(cls2.getTypeParameters()), cls2);
          break;
        case 25:
          TypeUtils.isArrayType(data.pickValue(cls1.getTypeParameters()));
          TypeUtils.isArrayType(data.pickValue(cls2.getTypeParameters()));
          break;
        case 26:
          TypeUtils.isAssignable(
              data.pickValue(cls1.getTypeParameters()), data.pickValue(cls2.getTypeParameters()));
          break;
        case 27:
          TypeUtils.getTypeArguments(
              TypeUtils.parameterize(cls1, data.pickValue(cls1.getTypeParameters())));
          TypeUtils.getTypeArguments(
              TypeUtils.parameterize(cls2, data.pickValue(cls2.getTypeParameters())));
          break;
        case 28:
          TypeUtils.wrap(cls1);
          TypeUtils.wrap(cls2);
          break;
      }
    } catch (ReflectiveOperationException
        | IllegalArgumentException
        | IllegalStateException
        | LinkageError e) {
      // Known exception
    } catch (NullPointerException e) {
      // Some methods throw NullPointerException
      if (!isExpectedNullPointerException(e)) {
        // Throw unexpected NullPointerException
        throw e;
      }
    }
  }

  private static Boolean isExpectedNullPointerException(NullPointerException e) {
    final String[] expectedMessages = {"Cannot locate", "Cannot invoke"};

    Boolean result = false;
    for (String message : expectedMessages) {
      result |= e.getMessage().contains(message);
    }

    return result;
  }
}